roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64         isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123         
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618         /** @type Boolean */
619         isTouch : isTouch,
620
621         /**
622          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623          * you may want to set this to true.
624          * @type Boolean
625          */
626         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
627         
628         
629                 
630         /**
631          * Selects a single element as a Roo Element
632          * This is about as close as you can get to jQuery's $('do crazy stuff')
633          * @param {String} selector The selector/xpath query
634          * @param {Node} root (optional) The start of the query (defaults to document).
635          * @return {Roo.Element}
636          */
637         selectNode : function(selector, root) 
638         {
639             var node = Roo.DomQuery.selectNode(selector,root);
640             return node ? Roo.get(node) : new Roo.Element(false);
641         }
642         
643     });
644
645
646 })();
647
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
650                 "Roo.app", "Roo.ux",
651                 "Roo.bootstrap",
652                 "Roo.bootstrap.dash");
653 /*
654  * Based on:
655  * Ext JS Library 1.1.1
656  * Copyright(c) 2006-2007, Ext JS, LLC.
657  *
658  * Originally Released Under LGPL - original licence link has changed is not relivant.
659  *
660  * Fork - LGPL
661  * <script type="text/javascript">
662  */
663
664 (function() {    
665     // wrappedn so fnCleanup is not in global scope...
666     if(Roo.isIE) {
667         function fnCleanUp() {
668             var p = Function.prototype;
669             delete p.createSequence;
670             delete p.defer;
671             delete p.createDelegate;
672             delete p.createCallback;
673             delete p.createInterceptor;
674
675             window.detachEvent("onunload", fnCleanUp);
676         }
677         window.attachEvent("onunload", fnCleanUp);
678     }
679 })();
680
681
682 /**
683  * @class Function
684  * These functions are available on every Function object (any JavaScript function).
685  */
686 Roo.apply(Function.prototype, {
687      /**
688      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
689      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
690      * Will create a function that is bound to those 2 args.
691      * @return {Function} The new function
692     */
693     createCallback : function(/*args...*/){
694         // make args available, in function below
695         var args = arguments;
696         var method = this;
697         return function() {
698             return method.apply(window, args);
699         };
700     },
701
702     /**
703      * Creates a delegate (callback) that sets the scope to obj.
704      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
705      * Will create a function that is automatically scoped to this.
706      * @param {Object} obj (optional) The object for which the scope is set
707      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
708      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
709      *                                             if a number the args are inserted at the specified position
710      * @return {Function} The new function
711      */
712     createDelegate : function(obj, args, appendArgs){
713         var method = this;
714         return function() {
715             var callArgs = args || arguments;
716             if(appendArgs === true){
717                 callArgs = Array.prototype.slice.call(arguments, 0);
718                 callArgs = callArgs.concat(args);
719             }else if(typeof appendArgs == "number"){
720                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
721                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
722                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
723             }
724             return method.apply(obj || window, callArgs);
725         };
726     },
727
728     /**
729      * Calls this function after the number of millseconds specified.
730      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
731      * @param {Object} obj (optional) The object for which the scope is set
732      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
733      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
734      *                                             if a number the args are inserted at the specified position
735      * @return {Number} The timeout id that can be used with clearTimeout
736      */
737     defer : function(millis, obj, args, appendArgs){
738         var fn = this.createDelegate(obj, args, appendArgs);
739         if(millis){
740             return setTimeout(fn, millis);
741         }
742         fn();
743         return 0;
744     },
745     /**
746      * Create a combined function call sequence of the original function + the passed function.
747      * The resulting function returns the results of the original function.
748      * The passed fcn is called with the parameters of the original function
749      * @param {Function} fcn The function to sequence
750      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
751      * @return {Function} The new function
752      */
753     createSequence : function(fcn, scope){
754         if(typeof fcn != "function"){
755             return this;
756         }
757         var method = this;
758         return function() {
759             var retval = method.apply(this || window, arguments);
760             fcn.apply(scope || this || window, arguments);
761             return retval;
762         };
763     },
764
765     /**
766      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
767      * The resulting function returns the results of the original function.
768      * The passed fcn is called with the parameters of the original function.
769      * @addon
770      * @param {Function} fcn The function to call before the original
771      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
772      * @return {Function} The new function
773      */
774     createInterceptor : function(fcn, scope){
775         if(typeof fcn != "function"){
776             return this;
777         }
778         var method = this;
779         return function() {
780             fcn.target = this;
781             fcn.method = method;
782             if(fcn.apply(scope || this || window, arguments) === false){
783                 return;
784             }
785             return method.apply(this || window, arguments);
786         };
787     }
788 });
789 /*
790  * Based on:
791  * Ext JS Library 1.1.1
792  * Copyright(c) 2006-2007, Ext JS, LLC.
793  *
794  * Originally Released Under LGPL - original licence link has changed is not relivant.
795  *
796  * Fork - LGPL
797  * <script type="text/javascript">
798  */
799
800 Roo.applyIf(String, {
801     
802     /** @scope String */
803     
804     /**
805      * Escapes the passed string for ' and \
806      * @param {String} string The string to escape
807      * @return {String} The escaped string
808      * @static
809      */
810     escape : function(string) {
811         return string.replace(/('|\\)/g, "\\$1");
812     },
813
814     /**
815      * Pads the left side of a string with a specified character.  This is especially useful
816      * for normalizing number and date strings.  Example usage:
817      * <pre><code>
818 var s = String.leftPad('123', 5, '0');
819 // s now contains the string: '00123'
820 </code></pre>
821      * @param {String} string The original string
822      * @param {Number} size The total length of the output string
823      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
824      * @return {String} The padded string
825      * @static
826      */
827     leftPad : function (val, size, ch) {
828         var result = new String(val);
829         if(ch === null || ch === undefined || ch === '') {
830             ch = " ";
831         }
832         while (result.length < size) {
833             result = ch + result;
834         }
835         return result;
836     },
837
838     /**
839      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
840      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
841      * <pre><code>
842 var cls = 'my-class', text = 'Some text';
843 var s = String.format('<div class="{0}">{1}</div>', cls, text);
844 // s now contains the string: '<div class="my-class">Some text</div>'
845 </code></pre>
846      * @param {String} string The tokenized string to be formatted
847      * @param {String} value1 The value to replace token {0}
848      * @param {String} value2 Etc...
849      * @return {String} The formatted string
850      * @static
851      */
852     format : function(format){
853         var args = Array.prototype.slice.call(arguments, 1);
854         return format.replace(/\{(\d+)\}/g, function(m, i){
855             return Roo.util.Format.htmlEncode(args[i]);
856         });
857     }
858 });
859
860 /**
861  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
862  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
863  * they are already different, the first value passed in is returned.  Note that this method returns the new value
864  * but does not change the current string.
865  * <pre><code>
866 // alternate sort directions
867 sort = sort.toggle('ASC', 'DESC');
868
869 // instead of conditional logic:
870 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
871 </code></pre>
872  * @param {String} value The value to compare to the current string
873  * @param {String} other The new value to use if the string already equals the first value passed in
874  * @return {String} The new value
875  */
876  
877 String.prototype.toggle = function(value, other){
878     return this == value ? other : value;
879 };/*
880  * Based on:
881  * Ext JS Library 1.1.1
882  * Copyright(c) 2006-2007, Ext JS, LLC.
883  *
884  * Originally Released Under LGPL - original licence link has changed is not relivant.
885  *
886  * Fork - LGPL
887  * <script type="text/javascript">
888  */
889
890  /**
891  * @class Number
892  */
893 Roo.applyIf(Number.prototype, {
894     /**
895      * Checks whether or not the current number is within a desired range.  If the number is already within the
896      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
897      * exceeded.  Note that this method returns the constrained value but does not change the current number.
898      * @param {Number} min The minimum number in the range
899      * @param {Number} max The maximum number in the range
900      * @return {Number} The constrained value if outside the range, otherwise the current value
901      */
902     constrain : function(min, max){
903         return Math.min(Math.max(this, min), max);
904     }
905 });/*
906  * Based on:
907  * Ext JS Library 1.1.1
908  * Copyright(c) 2006-2007, Ext JS, LLC.
909  *
910  * Originally Released Under LGPL - original licence link has changed is not relivant.
911  *
912  * Fork - LGPL
913  * <script type="text/javascript">
914  */
915  /**
916  * @class Array
917  */
918 Roo.applyIf(Array.prototype, {
919     /**
920      * Checks whether or not the specified object exists in the array.
921      * @param {Object} o The object to check for
922      * @return {Number} The index of o in the array (or -1 if it is not found)
923      */
924     indexOf : function(o){
925        for (var i = 0, len = this.length; i < len; i++){
926               if(this[i] == o) return i;
927        }
928            return -1;
929     },
930
931     /**
932      * Removes the specified object from the array.  If the object is not found nothing happens.
933      * @param {Object} o The object to remove
934      */
935     remove : function(o){
936        var index = this.indexOf(o);
937        if(index != -1){
938            this.splice(index, 1);
939        }
940     },
941     /**
942      * Map (JS 1.6 compatibility)
943      * @param {Function} function  to call
944      */
945     map : function(fun )
946     {
947         var len = this.length >>> 0;
948         if (typeof fun != "function")
949             throw new TypeError();
950
951         var res = new Array(len);
952         var thisp = arguments[1];
953         for (var i = 0; i < len; i++)
954         {
955             if (i in this)
956                 res[i] = fun.call(thisp, this[i], i, this);
957         }
958
959         return res;
960     }
961     
962 });
963
964
965  /*
966  * Based on:
967  * Ext JS Library 1.1.1
968  * Copyright(c) 2006-2007, Ext JS, LLC.
969  *
970  * Originally Released Under LGPL - original licence link has changed is not relivant.
971  *
972  * Fork - LGPL
973  * <script type="text/javascript">
974  */
975
976 /**
977  * @class Date
978  *
979  * The date parsing and format syntax is a subset of
980  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
981  * supported will provide results equivalent to their PHP versions.
982  *
983  * Following is the list of all currently supported formats:
984  *<pre>
985 Sample date:
986 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
987
988 Format  Output      Description
989 ------  ----------  --------------------------------------------------------------
990   d      10         Day of the month, 2 digits with leading zeros
991   D      Wed        A textual representation of a day, three letters
992   j      10         Day of the month without leading zeros
993   l      Wednesday  A full textual representation of the day of the week
994   S      th         English ordinal day of month suffix, 2 chars (use with j)
995   w      3          Numeric representation of the day of the week
996   z      9          The julian date, or day of the year (0-365)
997   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
998   F      January    A full textual representation of the month
999   m      01         Numeric representation of a month, with leading zeros
1000   M      Jan        Month name abbreviation, three letters
1001   n      1          Numeric representation of a month, without leading zeros
1002   t      31         Number of days in the given month
1003   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1004   Y      2007       A full numeric representation of a year, 4 digits
1005   y      07         A two digit representation of a year
1006   a      pm         Lowercase Ante meridiem and Post meridiem
1007   A      PM         Uppercase Ante meridiem and Post meridiem
1008   g      3          12-hour format of an hour without leading zeros
1009   G      15         24-hour format of an hour without leading zeros
1010   h      03         12-hour format of an hour with leading zeros
1011   H      15         24-hour format of an hour with leading zeros
1012   i      05         Minutes with leading zeros
1013   s      01         Seconds, with leading zeros
1014   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1015   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1016   T      CST        Timezone setting of the machine running the code
1017   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1018 </pre>
1019  *
1020  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1021  * <pre><code>
1022 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1023 document.write(dt.format('Y-m-d'));                         //2007-01-10
1024 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1025 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1026  </code></pre>
1027  *
1028  * Here are some standard date/time patterns that you might find helpful.  They
1029  * are not part of the source of Date.js, but to use them you can simply copy this
1030  * block of code into any script that is included after Date.js and they will also become
1031  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1032  * <pre><code>
1033 Date.patterns = {
1034     ISO8601Long:"Y-m-d H:i:s",
1035     ISO8601Short:"Y-m-d",
1036     ShortDate: "n/j/Y",
1037     LongDate: "l, F d, Y",
1038     FullDateTime: "l, F d, Y g:i:s A",
1039     MonthDay: "F d",
1040     ShortTime: "g:i A",
1041     LongTime: "g:i:s A",
1042     SortableDateTime: "Y-m-d\\TH:i:s",
1043     UniversalSortableDateTime: "Y-m-d H:i:sO",
1044     YearMonth: "F, Y"
1045 };
1046 </code></pre>
1047  *
1048  * Example usage:
1049  * <pre><code>
1050 var dt = new Date();
1051 document.write(dt.format(Date.patterns.ShortDate));
1052  </code></pre>
1053  */
1054
1055 /*
1056  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1057  * They generate precompiled functions from date formats instead of parsing and
1058  * processing the pattern every time you format a date.  These functions are available
1059  * on every Date object (any javascript function).
1060  *
1061  * The original article and download are here:
1062  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1063  *
1064  */
1065  
1066  
1067  // was in core
1068 /**
1069  Returns the number of milliseconds between this date and date
1070  @param {Date} date (optional) Defaults to now
1071  @return {Number} The diff in milliseconds
1072  @member Date getElapsed
1073  */
1074 Date.prototype.getElapsed = function(date) {
1075         return Math.abs((date || new Date()).getTime()-this.getTime());
1076 };
1077 // was in date file..
1078
1079
1080 // private
1081 Date.parseFunctions = {count:0};
1082 // private
1083 Date.parseRegexes = [];
1084 // private
1085 Date.formatFunctions = {count:0};
1086
1087 // private
1088 Date.prototype.dateFormat = function(format) {
1089     if (Date.formatFunctions[format] == null) {
1090         Date.createNewFormat(format);
1091     }
1092     var func = Date.formatFunctions[format];
1093     return this[func]();
1094 };
1095
1096
1097 /**
1098  * Formats a date given the supplied format string
1099  * @param {String} format The format string
1100  * @return {String} The formatted date
1101  * @method
1102  */
1103 Date.prototype.format = Date.prototype.dateFormat;
1104
1105 // private
1106 Date.createNewFormat = function(format) {
1107     var funcName = "format" + Date.formatFunctions.count++;
1108     Date.formatFunctions[format] = funcName;
1109     var code = "Date.prototype." + funcName + " = function(){return ";
1110     var special = false;
1111     var ch = '';
1112     for (var i = 0; i < format.length; ++i) {
1113         ch = format.charAt(i);
1114         if (!special && ch == "\\") {
1115             special = true;
1116         }
1117         else if (special) {
1118             special = false;
1119             code += "'" + String.escape(ch) + "' + ";
1120         }
1121         else {
1122             code += Date.getFormatCode(ch);
1123         }
1124     }
1125     /** eval:var:zzzzzzzzzzzzz */
1126     eval(code.substring(0, code.length - 3) + ";}");
1127 };
1128
1129 // private
1130 Date.getFormatCode = function(character) {
1131     switch (character) {
1132     case "d":
1133         return "String.leftPad(this.getDate(), 2, '0') + ";
1134     case "D":
1135         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1136     case "j":
1137         return "this.getDate() + ";
1138     case "l":
1139         return "Date.dayNames[this.getDay()] + ";
1140     case "S":
1141         return "this.getSuffix() + ";
1142     case "w":
1143         return "this.getDay() + ";
1144     case "z":
1145         return "this.getDayOfYear() + ";
1146     case "W":
1147         return "this.getWeekOfYear() + ";
1148     case "F":
1149         return "Date.monthNames[this.getMonth()] + ";
1150     case "m":
1151         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1152     case "M":
1153         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1154     case "n":
1155         return "(this.getMonth() + 1) + ";
1156     case "t":
1157         return "this.getDaysInMonth() + ";
1158     case "L":
1159         return "(this.isLeapYear() ? 1 : 0) + ";
1160     case "Y":
1161         return "this.getFullYear() + ";
1162     case "y":
1163         return "('' + this.getFullYear()).substring(2, 4) + ";
1164     case "a":
1165         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1166     case "A":
1167         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1168     case "g":
1169         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1170     case "G":
1171         return "this.getHours() + ";
1172     case "h":
1173         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1174     case "H":
1175         return "String.leftPad(this.getHours(), 2, '0') + ";
1176     case "i":
1177         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1178     case "s":
1179         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1180     case "O":
1181         return "this.getGMTOffset() + ";
1182     case "P":
1183         return "this.getGMTColonOffset() + ";
1184     case "T":
1185         return "this.getTimezone() + ";
1186     case "Z":
1187         return "(this.getTimezoneOffset() * -60) + ";
1188     default:
1189         return "'" + String.escape(character) + "' + ";
1190     }
1191 };
1192
1193 /**
1194  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1195  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1196  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1197  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1198  * string or the parse operation will fail.
1199  * Example Usage:
1200 <pre><code>
1201 //dt = Fri May 25 2007 (current date)
1202 var dt = new Date();
1203
1204 //dt = Thu May 25 2006 (today's month/day in 2006)
1205 dt = Date.parseDate("2006", "Y");
1206
1207 //dt = Sun Jan 15 2006 (all date parts specified)
1208 dt = Date.parseDate("2006-1-15", "Y-m-d");
1209
1210 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1211 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1212 </code></pre>
1213  * @param {String} input The unparsed date as a string
1214  * @param {String} format The format the date is in
1215  * @return {Date} The parsed date
1216  * @static
1217  */
1218 Date.parseDate = function(input, format) {
1219     if (Date.parseFunctions[format] == null) {
1220         Date.createParser(format);
1221     }
1222     var func = Date.parseFunctions[format];
1223     return Date[func](input);
1224 };
1225 /**
1226  * @private
1227  */
1228 Date.createParser = function(format) {
1229     var funcName = "parse" + Date.parseFunctions.count++;
1230     var regexNum = Date.parseRegexes.length;
1231     var currentGroup = 1;
1232     Date.parseFunctions[format] = funcName;
1233
1234     var code = "Date." + funcName + " = function(input){\n"
1235         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1236         + "var d = new Date();\n"
1237         + "y = d.getFullYear();\n"
1238         + "m = d.getMonth();\n"
1239         + "d = d.getDate();\n"
1240         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1241         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1242         + "if (results && results.length > 0) {";
1243     var regex = "";
1244
1245     var special = false;
1246     var ch = '';
1247     for (var i = 0; i < format.length; ++i) {
1248         ch = format.charAt(i);
1249         if (!special && ch == "\\") {
1250             special = true;
1251         }
1252         else if (special) {
1253             special = false;
1254             regex += String.escape(ch);
1255         }
1256         else {
1257             var obj = Date.formatCodeToRegex(ch, currentGroup);
1258             currentGroup += obj.g;
1259             regex += obj.s;
1260             if (obj.g && obj.c) {
1261                 code += obj.c;
1262             }
1263         }
1264     }
1265
1266     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1267         + "{v = new Date(y, m, d, h, i, s);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1269         + "{v = new Date(y, m, d, h, i);}\n"
1270         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1271         + "{v = new Date(y, m, d, h);}\n"
1272         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1273         + "{v = new Date(y, m, d);}\n"
1274         + "else if (y >= 0 && m >= 0)\n"
1275         + "{v = new Date(y, m);}\n"
1276         + "else if (y >= 0)\n"
1277         + "{v = new Date(y);}\n"
1278         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1279         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1280         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1281         + ";}";
1282
1283     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1284     /** eval:var:zzzzzzzzzzzzz */
1285     eval(code);
1286 };
1287
1288 // private
1289 Date.formatCodeToRegex = function(character, currentGroup) {
1290     switch (character) {
1291     case "D":
1292         return {g:0,
1293         c:null,
1294         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1295     case "j":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{1,2})"}; // day of month without leading zeroes
1299     case "d":
1300         return {g:1,
1301             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1302             s:"(\\d{2})"}; // day of month with leading zeroes
1303     case "l":
1304         return {g:0,
1305             c:null,
1306             s:"(?:" + Date.dayNames.join("|") + ")"};
1307     case "S":
1308         return {g:0,
1309             c:null,
1310             s:"(?:st|nd|rd|th)"};
1311     case "w":
1312         return {g:0,
1313             c:null,
1314             s:"\\d"};
1315     case "z":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{1,3})"};
1319     case "W":
1320         return {g:0,
1321             c:null,
1322             s:"(?:\\d{2})"};
1323     case "F":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1326             s:"(" + Date.monthNames.join("|") + ")"};
1327     case "M":
1328         return {g:1,
1329             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1330             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1331     case "n":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1335     case "m":
1336         return {g:1,
1337             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1338             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1339     case "t":
1340         return {g:0,
1341             c:null,
1342             s:"\\d{1,2}"};
1343     case "L":
1344         return {g:0,
1345             c:null,
1346             s:"(?:1|0)"};
1347     case "Y":
1348         return {g:1,
1349             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1350             s:"(\\d{4})"};
1351     case "y":
1352         return {g:1,
1353             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1354                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1355             s:"(\\d{1,2})"};
1356     case "a":
1357         return {g:1,
1358             c:"if (results[" + currentGroup + "] == 'am') {\n"
1359                 + "if (h == 12) { h = 0; }\n"
1360                 + "} else { if (h < 12) { h += 12; }}",
1361             s:"(am|pm)"};
1362     case "A":
1363         return {g:1,
1364             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1365                 + "if (h == 12) { h = 0; }\n"
1366                 + "} else { if (h < 12) { h += 12; }}",
1367             s:"(AM|PM)"};
1368     case "g":
1369     case "G":
1370         return {g:1,
1371             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1372             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1373     case "h":
1374     case "H":
1375         return {g:1,
1376             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1378     case "i":
1379         return {g:1,
1380             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "s":
1383         return {g:1,
1384             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385             s:"(\\d{2})"};
1386     case "O":
1387         return {g:1,
1388             c:[
1389                 "o = results[", currentGroup, "];\n",
1390                 "var sn = o.substring(0,1);\n", // get + / - sign
1391                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1392                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1393                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1394                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1395             ].join(""),
1396             s:"([+\-]\\d{2,4})"};
1397     
1398     
1399     case "P":
1400         return {g:1,
1401                 c:[
1402                    "o = results[", currentGroup, "];\n",
1403                    "var sn = o.substring(0,1);\n",
1404                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1405                    "var mn = o.substring(4,6) % 60;\n",
1406                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1407                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1408             ].join(""),
1409             s:"([+\-]\\d{4})"};
1410     case "T":
1411         return {g:0,
1412             c:null,
1413             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1414     case "Z":
1415         return {g:1,
1416             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1417                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1418             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1419     default:
1420         return {g:0,
1421             c:null,
1422             s:String.escape(character)};
1423     }
1424 };
1425
1426 /**
1427  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1428  * @return {String} The abbreviated timezone name (e.g. 'CST')
1429  */
1430 Date.prototype.getTimezone = function() {
1431     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1432 };
1433
1434 /**
1435  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1436  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1437  */
1438 Date.prototype.getGMTOffset = function() {
1439     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1440         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1441         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1442 };
1443
1444 /**
1445  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1446  * @return {String} 2-characters representing hours and 2-characters representing minutes
1447  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1448  */
1449 Date.prototype.getGMTColonOffset = function() {
1450         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1451                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1452                 + ":"
1453                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1454 }
1455
1456 /**
1457  * Get the numeric day number of the year, adjusted for leap year.
1458  * @return {Number} 0 through 364 (365 in leap years)
1459  */
1460 Date.prototype.getDayOfYear = function() {
1461     var num = 0;
1462     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1463     for (var i = 0; i < this.getMonth(); ++i) {
1464         num += Date.daysInMonth[i];
1465     }
1466     return num + this.getDate() - 1;
1467 };
1468
1469 /**
1470  * Get the string representation of the numeric week number of the year
1471  * (equivalent to the format specifier 'W').
1472  * @return {String} '00' through '52'
1473  */
1474 Date.prototype.getWeekOfYear = function() {
1475     // Skip to Thursday of this week
1476     var now = this.getDayOfYear() + (4 - this.getDay());
1477     // Find the first Thursday of the year
1478     var jan1 = new Date(this.getFullYear(), 0, 1);
1479     var then = (7 - jan1.getDay() + 4);
1480     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1481 };
1482
1483 /**
1484  * Whether or not the current date is in a leap year.
1485  * @return {Boolean} True if the current date is in a leap year, else false
1486  */
1487 Date.prototype.isLeapYear = function() {
1488     var year = this.getFullYear();
1489     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1490 };
1491
1492 /**
1493  * Get the first day of the current month, adjusted for leap year.  The returned value
1494  * is the numeric day index within the week (0-6) which can be used in conjunction with
1495  * the {@link #monthNames} array to retrieve the textual day name.
1496  * Example:
1497  *<pre><code>
1498 var dt = new Date('1/10/2007');
1499 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1500 </code></pre>
1501  * @return {Number} The day number (0-6)
1502  */
1503 Date.prototype.getFirstDayOfMonth = function() {
1504     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1505     return (day < 0) ? (day + 7) : day;
1506 };
1507
1508 /**
1509  * Get the last day of the current month, adjusted for leap year.  The returned value
1510  * is the numeric day index within the week (0-6) which can be used in conjunction with
1511  * the {@link #monthNames} array to retrieve the textual day name.
1512  * Example:
1513  *<pre><code>
1514 var dt = new Date('1/10/2007');
1515 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1516 </code></pre>
1517  * @return {Number} The day number (0-6)
1518  */
1519 Date.prototype.getLastDayOfMonth = function() {
1520     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1521     return (day < 0) ? (day + 7) : day;
1522 };
1523
1524
1525 /**
1526  * Get the first date of this date's month
1527  * @return {Date}
1528  */
1529 Date.prototype.getFirstDateOfMonth = function() {
1530     return new Date(this.getFullYear(), this.getMonth(), 1);
1531 };
1532
1533 /**
1534  * Get the last date of this date's month
1535  * @return {Date}
1536  */
1537 Date.prototype.getLastDateOfMonth = function() {
1538     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1539 };
1540 /**
1541  * Get the number of days in the current month, adjusted for leap year.
1542  * @return {Number} The number of days in the month
1543  */
1544 Date.prototype.getDaysInMonth = function() {
1545     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1546     return Date.daysInMonth[this.getMonth()];
1547 };
1548
1549 /**
1550  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1551  * @return {String} 'st, 'nd', 'rd' or 'th'
1552  */
1553 Date.prototype.getSuffix = function() {
1554     switch (this.getDate()) {
1555         case 1:
1556         case 21:
1557         case 31:
1558             return "st";
1559         case 2:
1560         case 22:
1561             return "nd";
1562         case 3:
1563         case 23:
1564             return "rd";
1565         default:
1566             return "th";
1567     }
1568 };
1569
1570 // private
1571 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1572
1573 /**
1574  * An array of textual month names.
1575  * Override these values for international dates, for example...
1576  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1577  * @type Array
1578  * @static
1579  */
1580 Date.monthNames =
1581    ["January",
1582     "February",
1583     "March",
1584     "April",
1585     "May",
1586     "June",
1587     "July",
1588     "August",
1589     "September",
1590     "October",
1591     "November",
1592     "December"];
1593
1594 /**
1595  * An array of textual day names.
1596  * Override these values for international dates, for example...
1597  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1598  * @type Array
1599  * @static
1600  */
1601 Date.dayNames =
1602    ["Sunday",
1603     "Monday",
1604     "Tuesday",
1605     "Wednesday",
1606     "Thursday",
1607     "Friday",
1608     "Saturday"];
1609
1610 // private
1611 Date.y2kYear = 50;
1612 // private
1613 Date.monthNumbers = {
1614     Jan:0,
1615     Feb:1,
1616     Mar:2,
1617     Apr:3,
1618     May:4,
1619     Jun:5,
1620     Jul:6,
1621     Aug:7,
1622     Sep:8,
1623     Oct:9,
1624     Nov:10,
1625     Dec:11};
1626
1627 /**
1628  * Creates and returns a new Date instance with the exact same date value as the called instance.
1629  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1630  * variable will also be changed.  When the intention is to create a new variable that will not
1631  * modify the original instance, you should create a clone.
1632  *
1633  * Example of correctly cloning a date:
1634  * <pre><code>
1635 //wrong way:
1636 var orig = new Date('10/1/2006');
1637 var copy = orig;
1638 copy.setDate(5);
1639 document.write(orig);  //returns 'Thu Oct 05 2006'!
1640
1641 //correct way:
1642 var orig = new Date('10/1/2006');
1643 var copy = orig.clone();
1644 copy.setDate(5);
1645 document.write(orig);  //returns 'Thu Oct 01 2006'
1646 </code></pre>
1647  * @return {Date} The new Date instance
1648  */
1649 Date.prototype.clone = function() {
1650         return new Date(this.getTime());
1651 };
1652
1653 /**
1654  * Clears any time information from this date
1655  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1656  @return {Date} this or the clone
1657  */
1658 Date.prototype.clearTime = function(clone){
1659     if(clone){
1660         return this.clone().clearTime();
1661     }
1662     this.setHours(0);
1663     this.setMinutes(0);
1664     this.setSeconds(0);
1665     this.setMilliseconds(0);
1666     return this;
1667 };
1668
1669 // private
1670 // safari setMonth is broken
1671 if(Roo.isSafari){
1672     Date.brokenSetMonth = Date.prototype.setMonth;
1673         Date.prototype.setMonth = function(num){
1674                 if(num <= -1){
1675                         var n = Math.ceil(-num);
1676                         var back_year = Math.ceil(n/12);
1677                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1678                         this.setFullYear(this.getFullYear() - back_year);
1679                         return Date.brokenSetMonth.call(this, month);
1680                 } else {
1681                         return Date.brokenSetMonth.apply(this, arguments);
1682                 }
1683         };
1684 }
1685
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.MILLI = "ms";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.SECOND = "s";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.MINUTE = "mi";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.HOUR = "h";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.DAY = "d";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.MONTH = "mo";
1710 /** Date interval constant 
1711 * @static 
1712 * @type String */
1713 Date.YEAR = "y";
1714
1715 /**
1716  * Provides a convenient method of performing basic date arithmetic.  This method
1717  * does not modify the Date instance being called - it creates and returns
1718  * a new Date instance containing the resulting date value.
1719  *
1720  * Examples:
1721  * <pre><code>
1722 //Basic usage:
1723 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1724 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1725
1726 //Negative values will subtract correctly:
1727 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1728 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1729
1730 //You can even chain several calls together in one line!
1731 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1732 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1733  </code></pre>
1734  *
1735  * @param {String} interval   A valid date interval enum value
1736  * @param {Number} value      The amount to add to the current date
1737  * @return {Date} The new Date instance
1738  */
1739 Date.prototype.add = function(interval, value){
1740   var d = this.clone();
1741   if (!interval || value === 0) return d;
1742   switch(interval.toLowerCase()){
1743     case Date.MILLI:
1744       d.setMilliseconds(this.getMilliseconds() + value);
1745       break;
1746     case Date.SECOND:
1747       d.setSeconds(this.getSeconds() + value);
1748       break;
1749     case Date.MINUTE:
1750       d.setMinutes(this.getMinutes() + value);
1751       break;
1752     case Date.HOUR:
1753       d.setHours(this.getHours() + value);
1754       break;
1755     case Date.DAY:
1756       d.setDate(this.getDate() + value);
1757       break;
1758     case Date.MONTH:
1759       var day = this.getDate();
1760       if(day > 28){
1761           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1762       }
1763       d.setDate(day);
1764       d.setMonth(this.getMonth() + value);
1765       break;
1766     case Date.YEAR:
1767       d.setFullYear(this.getFullYear() + value);
1768       break;
1769   }
1770   return d;
1771 };
1772 /*
1773  * Based on:
1774  * Ext JS Library 1.1.1
1775  * Copyright(c) 2006-2007, Ext JS, LLC.
1776  *
1777  * Originally Released Under LGPL - original licence link has changed is not relivant.
1778  *
1779  * Fork - LGPL
1780  * <script type="text/javascript">
1781  */
1782
1783 /**
1784  * @class Roo.lib.Dom
1785  * @static
1786  * 
1787  * Dom utils (from YIU afaik)
1788  * 
1789  **/
1790 Roo.lib.Dom = {
1791     /**
1792      * Get the view width
1793      * @param {Boolean} full True will get the full document, otherwise it's the view width
1794      * @return {Number} The width
1795      */
1796      
1797     getViewWidth : function(full) {
1798         return full ? this.getDocumentWidth() : this.getViewportWidth();
1799     },
1800     /**
1801      * Get the view height
1802      * @param {Boolean} full True will get the full document, otherwise it's the view height
1803      * @return {Number} The height
1804      */
1805     getViewHeight : function(full) {
1806         return full ? this.getDocumentHeight() : this.getViewportHeight();
1807     },
1808
1809     getDocumentHeight: function() {
1810         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1811         return Math.max(scrollHeight, this.getViewportHeight());
1812     },
1813
1814     getDocumentWidth: function() {
1815         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1816         return Math.max(scrollWidth, this.getViewportWidth());
1817     },
1818
1819     getViewportHeight: function() {
1820         var height = self.innerHeight;
1821         var mode = document.compatMode;
1822
1823         if ((mode || Roo.isIE) && !Roo.isOpera) {
1824             height = (mode == "CSS1Compat") ?
1825                      document.documentElement.clientHeight :
1826                      document.body.clientHeight;
1827         }
1828
1829         return height;
1830     },
1831
1832     getViewportWidth: function() {
1833         var width = self.innerWidth;
1834         var mode = document.compatMode;
1835
1836         if (mode || Roo.isIE) {
1837             width = (mode == "CSS1Compat") ?
1838                     document.documentElement.clientWidth :
1839                     document.body.clientWidth;
1840         }
1841         return width;
1842     },
1843
1844     isAncestor : function(p, c) {
1845         p = Roo.getDom(p);
1846         c = Roo.getDom(c);
1847         if (!p || !c) {
1848             return false;
1849         }
1850
1851         if (p.contains && !Roo.isSafari) {
1852             return p.contains(c);
1853         } else if (p.compareDocumentPosition) {
1854             return !!(p.compareDocumentPosition(c) & 16);
1855         } else {
1856             var parent = c.parentNode;
1857             while (parent) {
1858                 if (parent == p) {
1859                     return true;
1860                 }
1861                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1862                     return false;
1863                 }
1864                 parent = parent.parentNode;
1865             }
1866             return false;
1867         }
1868     },
1869
1870     getRegion : function(el) {
1871         return Roo.lib.Region.getRegion(el);
1872     },
1873
1874     getY : function(el) {
1875         return this.getXY(el)[1];
1876     },
1877
1878     getX : function(el) {
1879         return this.getXY(el)[0];
1880     },
1881
1882     getXY : function(el) {
1883         var p, pe, b, scroll, bd = document.body;
1884         el = Roo.getDom(el);
1885         var fly = Roo.lib.AnimBase.fly;
1886         if (el.getBoundingClientRect) {
1887             b = el.getBoundingClientRect();
1888             scroll = fly(document).getScroll();
1889             return [b.left + scroll.left, b.top + scroll.top];
1890         }
1891         var x = 0, y = 0;
1892
1893         p = el;
1894
1895         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1896
1897         while (p) {
1898
1899             x += p.offsetLeft;
1900             y += p.offsetTop;
1901
1902             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1903                 hasAbsolute = true;
1904             }
1905
1906             if (Roo.isGecko) {
1907                 pe = fly(p);
1908
1909                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1910                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1911
1912
1913                 x += bl;
1914                 y += bt;
1915
1916
1917                 if (p != el && pe.getStyle('overflow') != 'visible') {
1918                     x += bl;
1919                     y += bt;
1920                 }
1921             }
1922             p = p.offsetParent;
1923         }
1924
1925         if (Roo.isSafari && hasAbsolute) {
1926             x -= bd.offsetLeft;
1927             y -= bd.offsetTop;
1928         }
1929
1930         if (Roo.isGecko && !hasAbsolute) {
1931             var dbd = fly(bd);
1932             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1933             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1934         }
1935
1936         p = el.parentNode;
1937         while (p && p != bd) {
1938             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1939                 x -= p.scrollLeft;
1940                 y -= p.scrollTop;
1941             }
1942             p = p.parentNode;
1943         }
1944         return [x, y];
1945     },
1946  
1947   
1948
1949
1950     setXY : function(el, xy) {
1951         el = Roo.fly(el, '_setXY');
1952         el.position();
1953         var pts = el.translatePoints(xy);
1954         if (xy[0] !== false) {
1955             el.dom.style.left = pts.left + "px";
1956         }
1957         if (xy[1] !== false) {
1958             el.dom.style.top = pts.top + "px";
1959         }
1960     },
1961
1962     setX : function(el, x) {
1963         this.setXY(el, [x, false]);
1964     },
1965
1966     setY : function(el, y) {
1967         this.setXY(el, [false, y]);
1968     }
1969 };
1970 /*
1971  * Portions of this file are based on pieces of Yahoo User Interface Library
1972  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1973  * YUI licensed under the BSD License:
1974  * http://developer.yahoo.net/yui/license.txt
1975  * <script type="text/javascript">
1976  *
1977  */
1978
1979 Roo.lib.Event = function() {
1980     var loadComplete = false;
1981     var listeners = [];
1982     var unloadListeners = [];
1983     var retryCount = 0;
1984     var onAvailStack = [];
1985     var counter = 0;
1986     var lastError = null;
1987
1988     return {
1989         POLL_RETRYS: 200,
1990         POLL_INTERVAL: 20,
1991         EL: 0,
1992         TYPE: 1,
1993         FN: 2,
1994         WFN: 3,
1995         OBJ: 3,
1996         ADJ_SCOPE: 4,
1997         _interval: null,
1998
1999         startInterval: function() {
2000             if (!this._interval) {
2001                 var self = this;
2002                 var callback = function() {
2003                     self._tryPreloadAttach();
2004                 };
2005                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006
2007             }
2008         },
2009
2010         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2011             onAvailStack.push({ id:         p_id,
2012                 fn:         p_fn,
2013                 obj:        p_obj,
2014                 override:   p_override,
2015                 checkReady: false    });
2016
2017             retryCount = this.POLL_RETRYS;
2018             this.startInterval();
2019         },
2020
2021
2022         addListener: function(el, eventName, fn) {
2023             el = Roo.getDom(el);
2024             if (!el || !fn) {
2025                 return false;
2026             }
2027
2028             if ("unload" == eventName) {
2029                 unloadListeners[unloadListeners.length] =
2030                 [el, eventName, fn];
2031                 return true;
2032             }
2033
2034             var wrappedFn = function(e) {
2035                 return fn(Roo.lib.Event.getEvent(e));
2036             };
2037
2038             var li = [el, eventName, fn, wrappedFn];
2039
2040             var index = listeners.length;
2041             listeners[index] = li;
2042
2043             this.doAdd(el, eventName, wrappedFn, false);
2044             return true;
2045
2046         },
2047
2048
2049         removeListener: function(el, eventName, fn) {
2050             var i, len;
2051
2052             el = Roo.getDom(el);
2053
2054             if(!fn) {
2055                 return this.purgeElement(el, false, eventName);
2056             }
2057
2058
2059             if ("unload" == eventName) {
2060
2061                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2062                     var li = unloadListeners[i];
2063                     if (li &&
2064                         li[0] == el &&
2065                         li[1] == eventName &&
2066                         li[2] == fn) {
2067                         unloadListeners.splice(i, 1);
2068                         return true;
2069                     }
2070                 }
2071
2072                 return false;
2073             }
2074
2075             var cacheItem = null;
2076
2077
2078             var index = arguments[3];
2079
2080             if ("undefined" == typeof index) {
2081                 index = this._getCacheIndex(el, eventName, fn);
2082             }
2083
2084             if (index >= 0) {
2085                 cacheItem = listeners[index];
2086             }
2087
2088             if (!el || !cacheItem) {
2089                 return false;
2090             }
2091
2092             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2093
2094             delete listeners[index][this.WFN];
2095             delete listeners[index][this.FN];
2096             listeners.splice(index, 1);
2097
2098             return true;
2099
2100         },
2101
2102
2103         getTarget: function(ev, resolveTextNode) {
2104             ev = ev.browserEvent || ev;
2105             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2106             var t = ev.target || ev.srcElement;
2107             return this.resolveTextNode(t);
2108         },
2109
2110
2111         resolveTextNode: function(node) {
2112             if (Roo.isSafari && node && 3 == node.nodeType) {
2113                 return node.parentNode;
2114             } else {
2115                 return node;
2116             }
2117         },
2118
2119
2120         getPageX: function(ev) {
2121             ev = ev.browserEvent || ev;
2122             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2123             var x = ev.pageX;
2124             if (!x && 0 !== x) {
2125                 x = ev.clientX || 0;
2126
2127                 if (Roo.isIE) {
2128                     x += this.getScroll()[1];
2129                 }
2130             }
2131
2132             return x;
2133         },
2134
2135
2136         getPageY: function(ev) {
2137             ev = ev.browserEvent || ev;
2138             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2139             var y = ev.pageY;
2140             if (!y && 0 !== y) {
2141                 y = ev.clientY || 0;
2142
2143                 if (Roo.isIE) {
2144                     y += this.getScroll()[0];
2145                 }
2146             }
2147
2148
2149             return y;
2150         },
2151
2152
2153         getXY: function(ev) {
2154             ev = ev.browserEvent || ev;
2155             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2156             return [this.getPageX(ev), this.getPageY(ev)];
2157         },
2158
2159
2160         getRelatedTarget: function(ev) {
2161             ev = ev.browserEvent || ev;
2162             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2163             var t = ev.relatedTarget;
2164             if (!t) {
2165                 if (ev.type == "mouseout") {
2166                     t = ev.toElement;
2167                 } else if (ev.type == "mouseover") {
2168                     t = ev.fromElement;
2169                 }
2170             }
2171
2172             return this.resolveTextNode(t);
2173         },
2174
2175
2176         getTime: function(ev) {
2177             ev = ev.browserEvent || ev;
2178             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2179             if (!ev.time) {
2180                 var t = new Date().getTime();
2181                 try {
2182                     ev.time = t;
2183                 } catch(ex) {
2184                     this.lastError = ex;
2185                     return t;
2186                 }
2187             }
2188
2189             return ev.time;
2190         },
2191
2192
2193         stopEvent: function(ev) {
2194             this.stopPropagation(ev);
2195             this.preventDefault(ev);
2196         },
2197
2198
2199         stopPropagation: function(ev) {
2200             ev = ev.browserEvent || ev;
2201             if (ev.stopPropagation) {
2202                 ev.stopPropagation();
2203             } else {
2204                 ev.cancelBubble = true;
2205             }
2206         },
2207
2208
2209         preventDefault: function(ev) {
2210             ev = ev.browserEvent || ev;
2211             if(ev.preventDefault) {
2212                 ev.preventDefault();
2213             } else {
2214                 ev.returnValue = false;
2215             }
2216         },
2217
2218
2219         getEvent: function(e) {
2220             var ev = e || window.event;
2221             if (!ev) {
2222                 var c = this.getEvent.caller;
2223                 while (c) {
2224                     ev = c.arguments[0];
2225                     if (ev && Event == ev.constructor) {
2226                         break;
2227                     }
2228                     c = c.caller;
2229                 }
2230             }
2231             return ev;
2232         },
2233
2234
2235         getCharCode: function(ev) {
2236             ev = ev.browserEvent || ev;
2237             return ev.charCode || ev.keyCode || 0;
2238         },
2239
2240
2241         _getCacheIndex: function(el, eventName, fn) {
2242             for (var i = 0,len = listeners.length; i < len; ++i) {
2243                 var li = listeners[i];
2244                 if (li &&
2245                     li[this.FN] == fn &&
2246                     li[this.EL] == el &&
2247                     li[this.TYPE] == eventName) {
2248                     return i;
2249                 }
2250             }
2251
2252             return -1;
2253         },
2254
2255
2256         elCache: {},
2257
2258
2259         getEl: function(id) {
2260             return document.getElementById(id);
2261         },
2262
2263
2264         clearCache: function() {
2265         },
2266
2267
2268         _load: function(e) {
2269             loadComplete = true;
2270             var EU = Roo.lib.Event;
2271
2272
2273             if (Roo.isIE) {
2274                 EU.doRemove(window, "load", EU._load);
2275             }
2276         },
2277
2278
2279         _tryPreloadAttach: function() {
2280
2281             if (this.locked) {
2282                 return false;
2283             }
2284
2285             this.locked = true;
2286
2287
2288             var tryAgain = !loadComplete;
2289             if (!tryAgain) {
2290                 tryAgain = (retryCount > 0);
2291             }
2292
2293
2294             var notAvail = [];
2295             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2296                 var item = onAvailStack[i];
2297                 if (item) {
2298                     var el = this.getEl(item.id);
2299
2300                     if (el) {
2301                         if (!item.checkReady ||
2302                             loadComplete ||
2303                             el.nextSibling ||
2304                             (document && document.body)) {
2305
2306                             var scope = el;
2307                             if (item.override) {
2308                                 if (item.override === true) {
2309                                     scope = item.obj;
2310                                 } else {
2311                                     scope = item.override;
2312                                 }
2313                             }
2314                             item.fn.call(scope, item.obj);
2315                             onAvailStack[i] = null;
2316                         }
2317                     } else {
2318                         notAvail.push(item);
2319                     }
2320                 }
2321             }
2322
2323             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2324
2325             if (tryAgain) {
2326
2327                 this.startInterval();
2328             } else {
2329                 clearInterval(this._interval);
2330                 this._interval = null;
2331             }
2332
2333             this.locked = false;
2334
2335             return true;
2336
2337         },
2338
2339
2340         purgeElement: function(el, recurse, eventName) {
2341             var elListeners = this.getListeners(el, eventName);
2342             if (elListeners) {
2343                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2344                     var l = elListeners[i];
2345                     this.removeListener(el, l.type, l.fn);
2346                 }
2347             }
2348
2349             if (recurse && el && el.childNodes) {
2350                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2351                     this.purgeElement(el.childNodes[i], recurse, eventName);
2352                 }
2353             }
2354         },
2355
2356
2357         getListeners: function(el, eventName) {
2358             var results = [], searchLists;
2359             if (!eventName) {
2360                 searchLists = [listeners, unloadListeners];
2361             } else if (eventName == "unload") {
2362                 searchLists = [unloadListeners];
2363             } else {
2364                 searchLists = [listeners];
2365             }
2366
2367             for (var j = 0; j < searchLists.length; ++j) {
2368                 var searchList = searchLists[j];
2369                 if (searchList && searchList.length > 0) {
2370                     for (var i = 0,len = searchList.length; i < len; ++i) {
2371                         var l = searchList[i];
2372                         if (l && l[this.EL] === el &&
2373                             (!eventName || eventName === l[this.TYPE])) {
2374                             results.push({
2375                                 type:   l[this.TYPE],
2376                                 fn:     l[this.FN],
2377                                 obj:    l[this.OBJ],
2378                                 adjust: l[this.ADJ_SCOPE],
2379                                 index:  i
2380                             });
2381                         }
2382                     }
2383                 }
2384             }
2385
2386             return (results.length) ? results : null;
2387         },
2388
2389
2390         _unload: function(e) {
2391
2392             var EU = Roo.lib.Event, i, j, l, len, index;
2393
2394             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2395                 l = unloadListeners[i];
2396                 if (l) {
2397                     var scope = window;
2398                     if (l[EU.ADJ_SCOPE]) {
2399                         if (l[EU.ADJ_SCOPE] === true) {
2400                             scope = l[EU.OBJ];
2401                         } else {
2402                             scope = l[EU.ADJ_SCOPE];
2403                         }
2404                     }
2405                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2406                     unloadListeners[i] = null;
2407                     l = null;
2408                     scope = null;
2409                 }
2410             }
2411
2412             unloadListeners = null;
2413
2414             if (listeners && listeners.length > 0) {
2415                 j = listeners.length;
2416                 while (j) {
2417                     index = j - 1;
2418                     l = listeners[index];
2419                     if (l) {
2420                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2421                                 l[EU.FN], index);
2422                     }
2423                     j = j - 1;
2424                 }
2425                 l = null;
2426
2427                 EU.clearCache();
2428             }
2429
2430             EU.doRemove(window, "unload", EU._unload);
2431
2432         },
2433
2434
2435         getScroll: function() {
2436             var dd = document.documentElement, db = document.body;
2437             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2438                 return [dd.scrollTop, dd.scrollLeft];
2439             } else if (db) {
2440                 return [db.scrollTop, db.scrollLeft];
2441             } else {
2442                 return [0, 0];
2443             }
2444         },
2445
2446
2447         doAdd: function () {
2448             if (window.addEventListener) {
2449                 return function(el, eventName, fn, capture) {
2450                     el.addEventListener(eventName, fn, (capture));
2451                 };
2452             } else if (window.attachEvent) {
2453                 return function(el, eventName, fn, capture) {
2454                     el.attachEvent("on" + eventName, fn);
2455                 };
2456             } else {
2457                 return function() {
2458                 };
2459             }
2460         }(),
2461
2462
2463         doRemove: function() {
2464             if (window.removeEventListener) {
2465                 return function (el, eventName, fn, capture) {
2466                     el.removeEventListener(eventName, fn, (capture));
2467                 };
2468             } else if (window.detachEvent) {
2469                 return function (el, eventName, fn) {
2470                     el.detachEvent("on" + eventName, fn);
2471                 };
2472             } else {
2473                 return function() {
2474                 };
2475             }
2476         }()
2477     };
2478     
2479 }();
2480 (function() {     
2481    
2482     var E = Roo.lib.Event;
2483     E.on = E.addListener;
2484     E.un = E.removeListener;
2485
2486     if (document && document.body) {
2487         E._load();
2488     } else {
2489         E.doAdd(window, "load", E._load);
2490     }
2491     E.doAdd(window, "unload", E._unload);
2492     E._tryPreloadAttach();
2493 })();
2494
2495 /*
2496  * Portions of this file are based on pieces of Yahoo User Interface Library
2497  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2498  * YUI licensed under the BSD License:
2499  * http://developer.yahoo.net/yui/license.txt
2500  * <script type="text/javascript">
2501  *
2502  */
2503
2504 (function() {
2505     /**
2506      * @class Roo.lib.Ajax
2507      *
2508      */
2509     Roo.lib.Ajax = {
2510         /**
2511          * @static 
2512          */
2513         request : function(method, uri, cb, data, options) {
2514             if(options){
2515                 var hs = options.headers;
2516                 if(hs){
2517                     for(var h in hs){
2518                         if(hs.hasOwnProperty(h)){
2519                             this.initHeader(h, hs[h], false);
2520                         }
2521                     }
2522                 }
2523                 if(options.xmlData){
2524                     this.initHeader('Content-Type', 'text/xml', false);
2525                     method = 'POST';
2526                     data = options.xmlData;
2527                 }
2528             }
2529
2530             return this.asyncRequest(method, uri, cb, data);
2531         },
2532
2533         serializeForm : function(form) {
2534             if(typeof form == 'string') {
2535                 form = (document.getElementById(form) || document.forms[form]);
2536             }
2537
2538             var el, name, val, disabled, data = '', hasSubmit = false;
2539             for (var i = 0; i < form.elements.length; i++) {
2540                 el = form.elements[i];
2541                 disabled = form.elements[i].disabled;
2542                 name = form.elements[i].name;
2543                 val = form.elements[i].value;
2544
2545                 if (!disabled && name){
2546                     switch (el.type)
2547                             {
2548                         case 'select-one':
2549                         case 'select-multiple':
2550                             for (var j = 0; j < el.options.length; j++) {
2551                                 if (el.options[j].selected) {
2552                                     if (Roo.isIE) {
2553                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2554                                     }
2555                                     else {
2556                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2557                                     }
2558                                 }
2559                             }
2560                             break;
2561                         case 'radio':
2562                         case 'checkbox':
2563                             if (el.checked) {
2564                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2565                             }
2566                             break;
2567                         case 'file':
2568
2569                         case undefined:
2570
2571                         case 'reset':
2572
2573                         case 'button':
2574
2575                             break;
2576                         case 'submit':
2577                             if(hasSubmit == false) {
2578                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579                                 hasSubmit = true;
2580                             }
2581                             break;
2582                         default:
2583                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584                             break;
2585                     }
2586                 }
2587             }
2588             data = data.substr(0, data.length - 1);
2589             return data;
2590         },
2591
2592         headers:{},
2593
2594         hasHeaders:false,
2595
2596         useDefaultHeader:true,
2597
2598         defaultPostHeader:'application/x-www-form-urlencoded',
2599
2600         useDefaultXhrHeader:true,
2601
2602         defaultXhrHeader:'XMLHttpRequest',
2603
2604         hasDefaultHeaders:true,
2605
2606         defaultHeaders:{},
2607
2608         poll:{},
2609
2610         timeout:{},
2611
2612         pollInterval:50,
2613
2614         transactionId:0,
2615
2616         setProgId:function(id)
2617         {
2618             this.activeX.unshift(id);
2619         },
2620
2621         setDefaultPostHeader:function(b)
2622         {
2623             this.useDefaultHeader = b;
2624         },
2625
2626         setDefaultXhrHeader:function(b)
2627         {
2628             this.useDefaultXhrHeader = b;
2629         },
2630
2631         setPollingInterval:function(i)
2632         {
2633             if (typeof i == 'number' && isFinite(i)) {
2634                 this.pollInterval = i;
2635             }
2636         },
2637
2638         createXhrObject:function(transactionId)
2639         {
2640             var obj,http;
2641             try
2642             {
2643
2644                 http = new XMLHttpRequest();
2645
2646                 obj = { conn:http, tId:transactionId };
2647             }
2648             catch(e)
2649             {
2650                 for (var i = 0; i < this.activeX.length; ++i) {
2651                     try
2652                     {
2653
2654                         http = new ActiveXObject(this.activeX[i]);
2655
2656                         obj = { conn:http, tId:transactionId };
2657                         break;
2658                     }
2659                     catch(e) {
2660                     }
2661                 }
2662             }
2663             finally
2664             {
2665                 return obj;
2666             }
2667         },
2668
2669         getConnectionObject:function()
2670         {
2671             var o;
2672             var tId = this.transactionId;
2673
2674             try
2675             {
2676                 o = this.createXhrObject(tId);
2677                 if (o) {
2678                     this.transactionId++;
2679                 }
2680             }
2681             catch(e) {
2682             }
2683             finally
2684             {
2685                 return o;
2686             }
2687         },
2688
2689         asyncRequest:function(method, uri, callback, postData)
2690         {
2691             var o = this.getConnectionObject();
2692
2693             if (!o) {
2694                 return null;
2695             }
2696             else {
2697                 o.conn.open(method, uri, true);
2698
2699                 if (this.useDefaultXhrHeader) {
2700                     if (!this.defaultHeaders['X-Requested-With']) {
2701                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2702                     }
2703                 }
2704
2705                 if(postData && this.useDefaultHeader){
2706                     this.initHeader('Content-Type', this.defaultPostHeader);
2707                 }
2708
2709                  if (this.hasDefaultHeaders || this.hasHeaders) {
2710                     this.setHeader(o);
2711                 }
2712
2713                 this.handleReadyState(o, callback);
2714                 o.conn.send(postData || null);
2715
2716                 return o;
2717             }
2718         },
2719
2720         handleReadyState:function(o, callback)
2721         {
2722             var oConn = this;
2723
2724             if (callback && callback.timeout) {
2725                 
2726                 this.timeout[o.tId] = window.setTimeout(function() {
2727                     oConn.abort(o, callback, true);
2728                 }, callback.timeout);
2729             }
2730
2731             this.poll[o.tId] = window.setInterval(
2732                     function() {
2733                         if (o.conn && o.conn.readyState == 4) {
2734                             window.clearInterval(oConn.poll[o.tId]);
2735                             delete oConn.poll[o.tId];
2736
2737                             if(callback && callback.timeout) {
2738                                 window.clearTimeout(oConn.timeout[o.tId]);
2739                                 delete oConn.timeout[o.tId];
2740                             }
2741
2742                             oConn.handleTransactionResponse(o, callback);
2743                         }
2744                     }
2745                     , this.pollInterval);
2746         },
2747
2748         handleTransactionResponse:function(o, callback, isAbort)
2749         {
2750
2751             if (!callback) {
2752                 this.releaseObject(o);
2753                 return;
2754             }
2755
2756             var httpStatus, responseObject;
2757
2758             try
2759             {
2760                 if (o.conn.status !== undefined && o.conn.status != 0) {
2761                     httpStatus = o.conn.status;
2762                 }
2763                 else {
2764                     httpStatus = 13030;
2765                 }
2766             }
2767             catch(e) {
2768
2769
2770                 httpStatus = 13030;
2771             }
2772
2773             if (httpStatus >= 200 && httpStatus < 300) {
2774                 responseObject = this.createResponseObject(o, callback.argument);
2775                 if (callback.success) {
2776                     if (!callback.scope) {
2777                         callback.success(responseObject);
2778                     }
2779                     else {
2780
2781
2782                         callback.success.apply(callback.scope, [responseObject]);
2783                     }
2784                 }
2785             }
2786             else {
2787                 switch (httpStatus) {
2788
2789                     case 12002:
2790                     case 12029:
2791                     case 12030:
2792                     case 12031:
2793                     case 12152:
2794                     case 13030:
2795                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2796                         if (callback.failure) {
2797                             if (!callback.scope) {
2798                                 callback.failure(responseObject);
2799                             }
2800                             else {
2801                                 callback.failure.apply(callback.scope, [responseObject]);
2802                             }
2803                         }
2804                         break;
2805                     default:
2806                         responseObject = this.createResponseObject(o, callback.argument);
2807                         if (callback.failure) {
2808                             if (!callback.scope) {
2809                                 callback.failure(responseObject);
2810                             }
2811                             else {
2812                                 callback.failure.apply(callback.scope, [responseObject]);
2813                             }
2814                         }
2815                 }
2816             }
2817
2818             this.releaseObject(o);
2819             responseObject = null;
2820         },
2821
2822         createResponseObject:function(o, callbackArg)
2823         {
2824             var obj = {};
2825             var headerObj = {};
2826
2827             try
2828             {
2829                 var headerStr = o.conn.getAllResponseHeaders();
2830                 var header = headerStr.split('\n');
2831                 for (var i = 0; i < header.length; i++) {
2832                     var delimitPos = header[i].indexOf(':');
2833                     if (delimitPos != -1) {
2834                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2835                     }
2836                 }
2837             }
2838             catch(e) {
2839             }
2840
2841             obj.tId = o.tId;
2842             obj.status = o.conn.status;
2843             obj.statusText = o.conn.statusText;
2844             obj.getResponseHeader = headerObj;
2845             obj.getAllResponseHeaders = headerStr;
2846             obj.responseText = o.conn.responseText;
2847             obj.responseXML = o.conn.responseXML;
2848
2849             if (typeof callbackArg !== undefined) {
2850                 obj.argument = callbackArg;
2851             }
2852
2853             return obj;
2854         },
2855
2856         createExceptionObject:function(tId, callbackArg, isAbort)
2857         {
2858             var COMM_CODE = 0;
2859             var COMM_ERROR = 'communication failure';
2860             var ABORT_CODE = -1;
2861             var ABORT_ERROR = 'transaction aborted';
2862
2863             var obj = {};
2864
2865             obj.tId = tId;
2866             if (isAbort) {
2867                 obj.status = ABORT_CODE;
2868                 obj.statusText = ABORT_ERROR;
2869             }
2870             else {
2871                 obj.status = COMM_CODE;
2872                 obj.statusText = COMM_ERROR;
2873             }
2874
2875             if (callbackArg) {
2876                 obj.argument = callbackArg;
2877             }
2878
2879             return obj;
2880         },
2881
2882         initHeader:function(label, value, isDefault)
2883         {
2884             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2885
2886             if (headerObj[label] === undefined) {
2887                 headerObj[label] = value;
2888             }
2889             else {
2890
2891
2892                 headerObj[label] = value + "," + headerObj[label];
2893             }
2894
2895             if (isDefault) {
2896                 this.hasDefaultHeaders = true;
2897             }
2898             else {
2899                 this.hasHeaders = true;
2900             }
2901         },
2902
2903
2904         setHeader:function(o)
2905         {
2906             if (this.hasDefaultHeaders) {
2907                 for (var prop in this.defaultHeaders) {
2908                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2909                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910                     }
2911                 }
2912             }
2913
2914             if (this.hasHeaders) {
2915                 for (var prop in this.headers) {
2916                     if (this.headers.hasOwnProperty(prop)) {
2917                         o.conn.setRequestHeader(prop, this.headers[prop]);
2918                     }
2919                 }
2920                 this.headers = {};
2921                 this.hasHeaders = false;
2922             }
2923         },
2924
2925         resetDefaultHeaders:function() {
2926             delete this.defaultHeaders;
2927             this.defaultHeaders = {};
2928             this.hasDefaultHeaders = false;
2929         },
2930
2931         abort:function(o, callback, isTimeout)
2932         {
2933             if(this.isCallInProgress(o)) {
2934                 o.conn.abort();
2935                 window.clearInterval(this.poll[o.tId]);
2936                 delete this.poll[o.tId];
2937                 if (isTimeout) {
2938                     delete this.timeout[o.tId];
2939                 }
2940
2941                 this.handleTransactionResponse(o, callback, true);
2942
2943                 return true;
2944             }
2945             else {
2946                 return false;
2947             }
2948         },
2949
2950
2951         isCallInProgress:function(o)
2952         {
2953             if (o && o.conn) {
2954                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2955             }
2956             else {
2957
2958                 return false;
2959             }
2960         },
2961
2962
2963         releaseObject:function(o)
2964         {
2965
2966             o.conn = null;
2967
2968             o = null;
2969         },
2970
2971         activeX:[
2972         'MSXML2.XMLHTTP.3.0',
2973         'MSXML2.XMLHTTP',
2974         'Microsoft.XMLHTTP'
2975         ]
2976
2977
2978     };
2979 })();/*
2980  * Portions of this file are based on pieces of Yahoo User Interface Library
2981  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2982  * YUI licensed under the BSD License:
2983  * http://developer.yahoo.net/yui/license.txt
2984  * <script type="text/javascript">
2985  *
2986  */
2987
2988 Roo.lib.Region = function(t, r, b, l) {
2989     this.top = t;
2990     this[1] = t;
2991     this.right = r;
2992     this.bottom = b;
2993     this.left = l;
2994     this[0] = l;
2995 };
2996
2997
2998 Roo.lib.Region.prototype = {
2999     contains : function(region) {
3000         return ( region.left >= this.left &&
3001                  region.right <= this.right &&
3002                  region.top >= this.top &&
3003                  region.bottom <= this.bottom    );
3004
3005     },
3006
3007     getArea : function() {
3008         return ( (this.bottom - this.top) * (this.right - this.left) );
3009     },
3010
3011     intersect : function(region) {
3012         var t = Math.max(this.top, region.top);
3013         var r = Math.min(this.right, region.right);
3014         var b = Math.min(this.bottom, region.bottom);
3015         var l = Math.max(this.left, region.left);
3016
3017         if (b >= t && r >= l) {
3018             return new Roo.lib.Region(t, r, b, l);
3019         } else {
3020             return null;
3021         }
3022     },
3023     union : function(region) {
3024         var t = Math.min(this.top, region.top);
3025         var r = Math.max(this.right, region.right);
3026         var b = Math.max(this.bottom, region.bottom);
3027         var l = Math.min(this.left, region.left);
3028
3029         return new Roo.lib.Region(t, r, b, l);
3030     },
3031
3032     adjust : function(t, l, b, r) {
3033         this.top += t;
3034         this.left += l;
3035         this.right += r;
3036         this.bottom += b;
3037         return this;
3038     }
3039 };
3040
3041 Roo.lib.Region.getRegion = function(el) {
3042     var p = Roo.lib.Dom.getXY(el);
3043
3044     var t = p[1];
3045     var r = p[0] + el.offsetWidth;
3046     var b = p[1] + el.offsetHeight;
3047     var l = p[0];
3048
3049     return new Roo.lib.Region(t, r, b, l);
3050 };
3051 /*
3052  * Portions of this file are based on pieces of Yahoo User Interface Library
3053  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3054  * YUI licensed under the BSD License:
3055  * http://developer.yahoo.net/yui/license.txt
3056  * <script type="text/javascript">
3057  *
3058  */
3059 //@@dep Roo.lib.Region
3060
3061
3062 Roo.lib.Point = function(x, y) {
3063     if (x instanceof Array) {
3064         y = x[1];
3065         x = x[0];
3066     }
3067     this.x = this.right = this.left = this[0] = x;
3068     this.y = this.top = this.bottom = this[1] = y;
3069 };
3070
3071 Roo.lib.Point.prototype = new Roo.lib.Region();
3072 /*
3073  * Portions of this file are based on pieces of Yahoo User Interface Library
3074  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3075  * YUI licensed under the BSD License:
3076  * http://developer.yahoo.net/yui/license.txt
3077  * <script type="text/javascript">
3078  *
3079  */
3080  
3081 (function() {   
3082
3083     Roo.lib.Anim = {
3084         scroll : function(el, args, duration, easing, cb, scope) {
3085             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3086         },
3087
3088         motion : function(el, args, duration, easing, cb, scope) {
3089             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3090         },
3091
3092         color : function(el, args, duration, easing, cb, scope) {
3093             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3094         },
3095
3096         run : function(el, args, duration, easing, cb, scope, type) {
3097             type = type || Roo.lib.AnimBase;
3098             if (typeof easing == "string") {
3099                 easing = Roo.lib.Easing[easing];
3100             }
3101             var anim = new type(el, args, duration, easing);
3102             anim.animateX(function() {
3103                 Roo.callback(cb, scope);
3104             });
3105             return anim;
3106         }
3107     };
3108 })();/*
3109  * Portions of this file are based on pieces of Yahoo User Interface Library
3110  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3111  * YUI licensed under the BSD License:
3112  * http://developer.yahoo.net/yui/license.txt
3113  * <script type="text/javascript">
3114  *
3115  */
3116
3117 (function() {    
3118     var libFlyweight;
3119     
3120     function fly(el) {
3121         if (!libFlyweight) {
3122             libFlyweight = new Roo.Element.Flyweight();
3123         }
3124         libFlyweight.dom = el;
3125         return libFlyweight;
3126     }
3127
3128     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3129     
3130    
3131     
3132     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3133         if (el) {
3134             this.init(el, attributes, duration, method);
3135         }
3136     };
3137
3138     Roo.lib.AnimBase.fly = fly;
3139     
3140     
3141     
3142     Roo.lib.AnimBase.prototype = {
3143
3144         toString: function() {
3145             var el = this.getEl();
3146             var id = el.id || el.tagName;
3147             return ("Anim " + id);
3148         },
3149
3150         patterns: {
3151             noNegatives:        /width|height|opacity|padding/i,
3152             offsetAttribute:  /^((width|height)|(top|left))$/,
3153             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3154             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3155         },
3156
3157
3158         doMethod: function(attr, start, end) {
3159             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3160         },
3161
3162
3163         setAttribute: function(attr, val, unit) {
3164             if (this.patterns.noNegatives.test(attr)) {
3165                 val = (val > 0) ? val : 0;
3166             }
3167
3168             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3169         },
3170
3171
3172         getAttribute: function(attr) {
3173             var el = this.getEl();
3174             var val = fly(el).getStyle(attr);
3175
3176             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3177                 return parseFloat(val);
3178             }
3179
3180             var a = this.patterns.offsetAttribute.exec(attr) || [];
3181             var pos = !!( a[3] );
3182             var box = !!( a[2] );
3183
3184
3185             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3186                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3187             } else {
3188                 val = 0;
3189             }
3190
3191             return val;
3192         },
3193
3194
3195         getDefaultUnit: function(attr) {
3196             if (this.patterns.defaultUnit.test(attr)) {
3197                 return 'px';
3198             }
3199
3200             return '';
3201         },
3202
3203         animateX : function(callback, scope) {
3204             var f = function() {
3205                 this.onComplete.removeListener(f);
3206                 if (typeof callback == "function") {
3207                     callback.call(scope || this, this);
3208                 }
3209             };
3210             this.onComplete.addListener(f, this);
3211             this.animate();
3212         },
3213
3214
3215         setRuntimeAttribute: function(attr) {
3216             var start;
3217             var end;
3218             var attributes = this.attributes;
3219
3220             this.runtimeAttributes[attr] = {};
3221
3222             var isset = function(prop) {
3223                 return (typeof prop !== 'undefined');
3224             };
3225
3226             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3227                 return false;
3228             }
3229
3230             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3231
3232
3233             if (isset(attributes[attr]['to'])) {
3234                 end = attributes[attr]['to'];
3235             } else if (isset(attributes[attr]['by'])) {
3236                 if (start.constructor == Array) {
3237                     end = [];
3238                     for (var i = 0, len = start.length; i < len; ++i) {
3239                         end[i] = start[i] + attributes[attr]['by'][i];
3240                     }
3241                 } else {
3242                     end = start + attributes[attr]['by'];
3243                 }
3244             }
3245
3246             this.runtimeAttributes[attr].start = start;
3247             this.runtimeAttributes[attr].end = end;
3248
3249
3250             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3251         },
3252
3253
3254         init: function(el, attributes, duration, method) {
3255
3256             var isAnimated = false;
3257
3258
3259             var startTime = null;
3260
3261
3262             var actualFrames = 0;
3263
3264
3265             el = Roo.getDom(el);
3266
3267
3268             this.attributes = attributes || {};
3269
3270
3271             this.duration = duration || 1;
3272
3273
3274             this.method = method || Roo.lib.Easing.easeNone;
3275
3276
3277             this.useSeconds = true;
3278
3279
3280             this.currentFrame = 0;
3281
3282
3283             this.totalFrames = Roo.lib.AnimMgr.fps;
3284
3285
3286             this.getEl = function() {
3287                 return el;
3288             };
3289
3290
3291             this.isAnimated = function() {
3292                 return isAnimated;
3293             };
3294
3295
3296             this.getStartTime = function() {
3297                 return startTime;
3298             };
3299
3300             this.runtimeAttributes = {};
3301
3302
3303             this.animate = function() {
3304                 if (this.isAnimated()) {
3305                     return false;
3306                 }
3307
3308                 this.currentFrame = 0;
3309
3310                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3311
3312                 Roo.lib.AnimMgr.registerElement(this);
3313             };
3314
3315
3316             this.stop = function(finish) {
3317                 if (finish) {
3318                     this.currentFrame = this.totalFrames;
3319                     this._onTween.fire();
3320                 }
3321                 Roo.lib.AnimMgr.stop(this);
3322             };
3323
3324             var onStart = function() {
3325                 this.onStart.fire();
3326
3327                 this.runtimeAttributes = {};
3328                 for (var attr in this.attributes) {
3329                     this.setRuntimeAttribute(attr);
3330                 }
3331
3332                 isAnimated = true;
3333                 actualFrames = 0;
3334                 startTime = new Date();
3335             };
3336
3337
3338             var onTween = function() {
3339                 var data = {
3340                     duration: new Date() - this.getStartTime(),
3341                     currentFrame: this.currentFrame
3342                 };
3343
3344                 data.toString = function() {
3345                     return (
3346                             'duration: ' + data.duration +
3347                             ', currentFrame: ' + data.currentFrame
3348                             );
3349                 };
3350
3351                 this.onTween.fire(data);
3352
3353                 var runtimeAttributes = this.runtimeAttributes;
3354
3355                 for (var attr in runtimeAttributes) {
3356                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3357                 }
3358
3359                 actualFrames += 1;
3360             };
3361
3362             var onComplete = function() {
3363                 var actual_duration = (new Date() - startTime) / 1000 ;
3364
3365                 var data = {
3366                     duration: actual_duration,
3367                     frames: actualFrames,
3368                     fps: actualFrames / actual_duration
3369                 };
3370
3371                 data.toString = function() {
3372                     return (
3373                             'duration: ' + data.duration +
3374                             ', frames: ' + data.frames +
3375                             ', fps: ' + data.fps
3376                             );
3377                 };
3378
3379                 isAnimated = false;
3380                 actualFrames = 0;
3381                 this.onComplete.fire(data);
3382             };
3383
3384
3385             this._onStart = new Roo.util.Event(this);
3386             this.onStart = new Roo.util.Event(this);
3387             this.onTween = new Roo.util.Event(this);
3388             this._onTween = new Roo.util.Event(this);
3389             this.onComplete = new Roo.util.Event(this);
3390             this._onComplete = new Roo.util.Event(this);
3391             this._onStart.addListener(onStart);
3392             this._onTween.addListener(onTween);
3393             this._onComplete.addListener(onComplete);
3394         }
3395     };
3396 })();
3397 /*
3398  * Portions of this file are based on pieces of Yahoo User Interface Library
3399  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3400  * YUI licensed under the BSD License:
3401  * http://developer.yahoo.net/yui/license.txt
3402  * <script type="text/javascript">
3403  *
3404  */
3405
3406 Roo.lib.AnimMgr = new function() {
3407
3408     var thread = null;
3409
3410
3411     var queue = [];
3412
3413
3414     var tweenCount = 0;
3415
3416
3417     this.fps = 1000;
3418
3419
3420     this.delay = 1;
3421
3422
3423     this.registerElement = function(tween) {
3424         queue[queue.length] = tween;
3425         tweenCount += 1;
3426         tween._onStart.fire();
3427         this.start();
3428     };
3429
3430
3431     this.unRegister = function(tween, index) {
3432         tween._onComplete.fire();
3433         index = index || getIndex(tween);
3434         if (index != -1) {
3435             queue.splice(index, 1);
3436         }
3437
3438         tweenCount -= 1;
3439         if (tweenCount <= 0) {
3440             this.stop();
3441         }
3442     };
3443
3444
3445     this.start = function() {
3446         if (thread === null) {
3447             thread = setInterval(this.run, this.delay);
3448         }
3449     };
3450
3451
3452     this.stop = function(tween) {
3453         if (!tween) {
3454             clearInterval(thread);
3455
3456             for (var i = 0, len = queue.length; i < len; ++i) {
3457                 if (queue[0].isAnimated()) {
3458                     this.unRegister(queue[0], 0);
3459                 }
3460             }
3461
3462             queue = [];
3463             thread = null;
3464             tweenCount = 0;
3465         }
3466         else {
3467             this.unRegister(tween);
3468         }
3469     };
3470
3471
3472     this.run = function() {
3473         for (var i = 0, len = queue.length; i < len; ++i) {
3474             var tween = queue[i];
3475             if (!tween || !tween.isAnimated()) {
3476                 continue;
3477             }
3478
3479             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3480             {
3481                 tween.currentFrame += 1;
3482
3483                 if (tween.useSeconds) {
3484                     correctFrame(tween);
3485                 }
3486                 tween._onTween.fire();
3487             }
3488             else {
3489                 Roo.lib.AnimMgr.stop(tween, i);
3490             }
3491         }
3492     };
3493
3494     var getIndex = function(anim) {
3495         for (var i = 0, len = queue.length; i < len; ++i) {
3496             if (queue[i] == anim) {
3497                 return i;
3498             }
3499         }
3500         return -1;
3501     };
3502
3503
3504     var correctFrame = function(tween) {
3505         var frames = tween.totalFrames;
3506         var frame = tween.currentFrame;
3507         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3508         var elapsed = (new Date() - tween.getStartTime());
3509         var tweak = 0;
3510
3511         if (elapsed < tween.duration * 1000) {
3512             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3513         } else {
3514             tweak = frames - (frame + 1);
3515         }
3516         if (tweak > 0 && isFinite(tweak)) {
3517             if (tween.currentFrame + tweak >= frames) {
3518                 tweak = frames - (frame + 1);
3519             }
3520
3521             tween.currentFrame += tweak;
3522         }
3523     };
3524 };
3525
3526     /*
3527  * Portions of this file are based on pieces of Yahoo User Interface Library
3528  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3529  * YUI licensed under the BSD License:
3530  * http://developer.yahoo.net/yui/license.txt
3531  * <script type="text/javascript">
3532  *
3533  */
3534 Roo.lib.Bezier = new function() {
3535
3536         this.getPosition = function(points, t) {
3537             var n = points.length;
3538             var tmp = [];
3539
3540             for (var i = 0; i < n; ++i) {
3541                 tmp[i] = [points[i][0], points[i][1]];
3542             }
3543
3544             for (var j = 1; j < n; ++j) {
3545                 for (i = 0; i < n - j; ++i) {
3546                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3547                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3548                 }
3549             }
3550
3551             return [ tmp[0][0], tmp[0][1] ];
3552
3553         };
3554     };/*
3555  * Portions of this file are based on pieces of Yahoo User Interface Library
3556  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557  * YUI licensed under the BSD License:
3558  * http://developer.yahoo.net/yui/license.txt
3559  * <script type="text/javascript">
3560  *
3561  */
3562 (function() {
3563
3564     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3565         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3566     };
3567
3568     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3569
3570     var fly = Roo.lib.AnimBase.fly;
3571     var Y = Roo.lib;
3572     var superclass = Y.ColorAnim.superclass;
3573     var proto = Y.ColorAnim.prototype;
3574
3575     proto.toString = function() {
3576         var el = this.getEl();
3577         var id = el.id || el.tagName;
3578         return ("ColorAnim " + id);
3579     };
3580
3581     proto.patterns.color = /color$/i;
3582     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3583     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3584     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3585     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3586
3587
3588     proto.parseColor = function(s) {
3589         if (s.length == 3) {
3590             return s;
3591         }
3592
3593         var c = this.patterns.hex.exec(s);
3594         if (c && c.length == 4) {
3595             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3596         }
3597
3598         c = this.patterns.rgb.exec(s);
3599         if (c && c.length == 4) {
3600             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3601         }
3602
3603         c = this.patterns.hex3.exec(s);
3604         if (c && c.length == 4) {
3605             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606         }
3607
3608         return null;
3609     };
3610     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3611     proto.getAttribute = function(attr) {
3612         var el = this.getEl();
3613         if (this.patterns.color.test(attr)) {
3614             var val = fly(el).getStyle(attr);
3615
3616             if (this.patterns.transparent.test(val)) {
3617                 var parent = el.parentNode;
3618                 val = fly(parent).getStyle(attr);
3619
3620                 while (parent && this.patterns.transparent.test(val)) {
3621                     parent = parent.parentNode;
3622                     val = fly(parent).getStyle(attr);
3623                     if (parent.tagName.toUpperCase() == 'HTML') {
3624                         val = '#fff';
3625                     }
3626                 }
3627             }
3628         } else {
3629             val = superclass.getAttribute.call(this, attr);
3630         }
3631
3632         return val;
3633     };
3634     proto.getAttribute = function(attr) {
3635         var el = this.getEl();
3636         if (this.patterns.color.test(attr)) {
3637             var val = fly(el).getStyle(attr);
3638
3639             if (this.patterns.transparent.test(val)) {
3640                 var parent = el.parentNode;
3641                 val = fly(parent).getStyle(attr);
3642
3643                 while (parent && this.patterns.transparent.test(val)) {
3644                     parent = parent.parentNode;
3645                     val = fly(parent).getStyle(attr);
3646                     if (parent.tagName.toUpperCase() == 'HTML') {
3647                         val = '#fff';
3648                     }
3649                 }
3650             }
3651         } else {
3652             val = superclass.getAttribute.call(this, attr);
3653         }
3654
3655         return val;
3656     };
3657
3658     proto.doMethod = function(attr, start, end) {
3659         var val;
3660
3661         if (this.patterns.color.test(attr)) {
3662             val = [];
3663             for (var i = 0, len = start.length; i < len; ++i) {
3664                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3665             }
3666
3667             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3668         }
3669         else {
3670             val = superclass.doMethod.call(this, attr, start, end);
3671         }
3672
3673         return val;
3674     };
3675
3676     proto.setRuntimeAttribute = function(attr) {
3677         superclass.setRuntimeAttribute.call(this, attr);
3678
3679         if (this.patterns.color.test(attr)) {
3680             var attributes = this.attributes;
3681             var start = this.parseColor(this.runtimeAttributes[attr].start);
3682             var end = this.parseColor(this.runtimeAttributes[attr].end);
3683
3684             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3685                 end = this.parseColor(attributes[attr].by);
3686
3687                 for (var i = 0, len = start.length; i < len; ++i) {
3688                     end[i] = start[i] + end[i];
3689                 }
3690             }
3691
3692             this.runtimeAttributes[attr].start = start;
3693             this.runtimeAttributes[attr].end = end;
3694         }
3695     };
3696 })();
3697
3698 /*
3699  * Portions of this file are based on pieces of Yahoo User Interface Library
3700  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3701  * YUI licensed under the BSD License:
3702  * http://developer.yahoo.net/yui/license.txt
3703  * <script type="text/javascript">
3704  *
3705  */
3706 Roo.lib.Easing = {
3707
3708
3709     easeNone: function (t, b, c, d) {
3710         return c * t / d + b;
3711     },
3712
3713
3714     easeIn: function (t, b, c, d) {
3715         return c * (t /= d) * t + b;
3716     },
3717
3718
3719     easeOut: function (t, b, c, d) {
3720         return -c * (t /= d) * (t - 2) + b;
3721     },
3722
3723
3724     easeBoth: function (t, b, c, d) {
3725         if ((t /= d / 2) < 1) {
3726             return c / 2 * t * t + b;
3727         }
3728
3729         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3730     },
3731
3732
3733     easeInStrong: function (t, b, c, d) {
3734         return c * (t /= d) * t * t * t + b;
3735     },
3736
3737
3738     easeOutStrong: function (t, b, c, d) {
3739         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3740     },
3741
3742
3743     easeBothStrong: function (t, b, c, d) {
3744         if ((t /= d / 2) < 1) {
3745             return c / 2 * t * t * t * t + b;
3746         }
3747
3748         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749     },
3750
3751
3752
3753     elasticIn: function (t, b, c, d, a, p) {
3754         if (t == 0) {
3755             return b;
3756         }
3757         if ((t /= d) == 1) {
3758             return b + c;
3759         }
3760         if (!p) {
3761             p = d * .3;
3762         }
3763
3764         if (!a || a < Math.abs(c)) {
3765             a = c;
3766             var s = p / 4;
3767         }
3768         else {
3769             var s = p / (2 * Math.PI) * Math.asin(c / a);
3770         }
3771
3772         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3773     },
3774
3775
3776     elasticOut: function (t, b, c, d, a, p) {
3777         if (t == 0) {
3778             return b;
3779         }
3780         if ((t /= d) == 1) {
3781             return b + c;
3782         }
3783         if (!p) {
3784             p = d * .3;
3785         }
3786
3787         if (!a || a < Math.abs(c)) {
3788             a = c;
3789             var s = p / 4;
3790         }
3791         else {
3792             var s = p / (2 * Math.PI) * Math.asin(c / a);
3793         }
3794
3795         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3796     },
3797
3798
3799     elasticBoth: function (t, b, c, d, a, p) {
3800         if (t == 0) {
3801             return b;
3802         }
3803
3804         if ((t /= d / 2) == 2) {
3805             return b + c;
3806         }
3807
3808         if (!p) {
3809             p = d * (.3 * 1.5);
3810         }
3811
3812         if (!a || a < Math.abs(c)) {
3813             a = c;
3814             var s = p / 4;
3815         }
3816         else {
3817             var s = p / (2 * Math.PI) * Math.asin(c / a);
3818         }
3819
3820         if (t < 1) {
3821             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3822                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3823         }
3824         return a * Math.pow(2, -10 * (t -= 1)) *
3825                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826     },
3827
3828
3829
3830     backIn: function (t, b, c, d, s) {
3831         if (typeof s == 'undefined') {
3832             s = 1.70158;
3833         }
3834         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3835     },
3836
3837
3838     backOut: function (t, b, c, d, s) {
3839         if (typeof s == 'undefined') {
3840             s = 1.70158;
3841         }
3842         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3843     },
3844
3845
3846     backBoth: function (t, b, c, d, s) {
3847         if (typeof s == 'undefined') {
3848             s = 1.70158;
3849         }
3850
3851         if ((t /= d / 2 ) < 1) {
3852             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3853         }
3854         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3855     },
3856
3857
3858     bounceIn: function (t, b, c, d) {
3859         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3860     },
3861
3862
3863     bounceOut: function (t, b, c, d) {
3864         if ((t /= d) < (1 / 2.75)) {
3865             return c * (7.5625 * t * t) + b;
3866         } else if (t < (2 / 2.75)) {
3867             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3868         } else if (t < (2.5 / 2.75)) {
3869             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3870         }
3871         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3872     },
3873
3874
3875     bounceBoth: function (t, b, c, d) {
3876         if (t < d / 2) {
3877             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3878         }
3879         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3880     }
3881 };/*
3882  * Portions of this file are based on pieces of Yahoo User Interface Library
3883  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3884  * YUI licensed under the BSD License:
3885  * http://developer.yahoo.net/yui/license.txt
3886  * <script type="text/javascript">
3887  *
3888  */
3889     (function() {
3890         Roo.lib.Motion = function(el, attributes, duration, method) {
3891             if (el) {
3892                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3893             }
3894         };
3895
3896         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3897
3898
3899         var Y = Roo.lib;
3900         var superclass = Y.Motion.superclass;
3901         var proto = Y.Motion.prototype;
3902
3903         proto.toString = function() {
3904             var el = this.getEl();
3905             var id = el.id || el.tagName;
3906             return ("Motion " + id);
3907         };
3908
3909         proto.patterns.points = /^points$/i;
3910
3911         proto.setAttribute = function(attr, val, unit) {
3912             if (this.patterns.points.test(attr)) {
3913                 unit = unit || 'px';
3914                 superclass.setAttribute.call(this, 'left', val[0], unit);
3915                 superclass.setAttribute.call(this, 'top', val[1], unit);
3916             } else {
3917                 superclass.setAttribute.call(this, attr, val, unit);
3918             }
3919         };
3920
3921         proto.getAttribute = function(attr) {
3922             if (this.patterns.points.test(attr)) {
3923                 var val = [
3924                         superclass.getAttribute.call(this, 'left'),
3925                         superclass.getAttribute.call(this, 'top')
3926                         ];
3927             } else {
3928                 val = superclass.getAttribute.call(this, attr);
3929             }
3930
3931             return val;
3932         };
3933
3934         proto.doMethod = function(attr, start, end) {
3935             var val = null;
3936
3937             if (this.patterns.points.test(attr)) {
3938                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3939                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3940             } else {
3941                 val = superclass.doMethod.call(this, attr, start, end);
3942             }
3943             return val;
3944         };
3945
3946         proto.setRuntimeAttribute = function(attr) {
3947             if (this.patterns.points.test(attr)) {
3948                 var el = this.getEl();
3949                 var attributes = this.attributes;
3950                 var start;
3951                 var control = attributes['points']['control'] || [];
3952                 var end;
3953                 var i, len;
3954
3955                 if (control.length > 0 && !(control[0] instanceof Array)) {
3956                     control = [control];
3957                 } else {
3958                     var tmp = [];
3959                     for (i = 0,len = control.length; i < len; ++i) {
3960                         tmp[i] = control[i];
3961                     }
3962                     control = tmp;
3963                 }
3964
3965                 Roo.fly(el).position();
3966
3967                 if (isset(attributes['points']['from'])) {
3968                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3969                 }
3970                 else {
3971                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3972                 }
3973
3974                 start = this.getAttribute('points');
3975
3976
3977                 if (isset(attributes['points']['to'])) {
3978                     end = translateValues.call(this, attributes['points']['to'], start);
3979
3980                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3981                     for (i = 0,len = control.length; i < len; ++i) {
3982                         control[i] = translateValues.call(this, control[i], start);
3983                     }
3984
3985
3986                 } else if (isset(attributes['points']['by'])) {
3987                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3988
3989                     for (i = 0,len = control.length; i < len; ++i) {
3990                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3991                     }
3992                 }
3993
3994                 this.runtimeAttributes[attr] = [start];
3995
3996                 if (control.length > 0) {
3997                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3998                 }
3999
4000                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4001             }
4002             else {
4003                 superclass.setRuntimeAttribute.call(this, attr);
4004             }
4005         };
4006
4007         var translateValues = function(val, start) {
4008             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010
4011             return val;
4012         };
4013
4014         var isset = function(prop) {
4015             return (typeof prop !== 'undefined');
4016         };
4017     })();
4018 /*
4019  * Portions of this file are based on pieces of Yahoo User Interface Library
4020  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4021  * YUI licensed under the BSD License:
4022  * http://developer.yahoo.net/yui/license.txt
4023  * <script type="text/javascript">
4024  *
4025  */
4026     (function() {
4027         Roo.lib.Scroll = function(el, attributes, duration, method) {
4028             if (el) {
4029                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4030             }
4031         };
4032
4033         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4034
4035
4036         var Y = Roo.lib;
4037         var superclass = Y.Scroll.superclass;
4038         var proto = Y.Scroll.prototype;
4039
4040         proto.toString = function() {
4041             var el = this.getEl();
4042             var id = el.id || el.tagName;
4043             return ("Scroll " + id);
4044         };
4045
4046         proto.doMethod = function(attr, start, end) {
4047             var val = null;
4048
4049             if (attr == 'scroll') {
4050                 val = [
4051                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4052                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4053                         ];
4054
4055             } else {
4056                 val = superclass.doMethod.call(this, attr, start, end);
4057             }
4058             return val;
4059         };
4060
4061         proto.getAttribute = function(attr) {
4062             var val = null;
4063             var el = this.getEl();
4064
4065             if (attr == 'scroll') {
4066                 val = [ el.scrollLeft, el.scrollTop ];
4067             } else {
4068                 val = superclass.getAttribute.call(this, attr);
4069             }
4070
4071             return val;
4072         };
4073
4074         proto.setAttribute = function(attr, val, unit) {
4075             var el = this.getEl();
4076
4077             if (attr == 'scroll') {
4078                 el.scrollLeft = val[0];
4079                 el.scrollTop = val[1];
4080             } else {
4081                 superclass.setAttribute.call(this, attr, val, unit);
4082             }
4083         };
4084     })();
4085 /*
4086  * Based on:
4087  * Ext JS Library 1.1.1
4088  * Copyright(c) 2006-2007, Ext JS, LLC.
4089  *
4090  * Originally Released Under LGPL - original licence link has changed is not relivant.
4091  *
4092  * Fork - LGPL
4093  * <script type="text/javascript">
4094  */
4095
4096
4097 // nasty IE9 hack - what a pile of crap that is..
4098
4099  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4100     Range.prototype.createContextualFragment = function (html) {
4101         var doc = window.document;
4102         var container = doc.createElement("div");
4103         container.innerHTML = html;
4104         var frag = doc.createDocumentFragment(), n;
4105         while ((n = container.firstChild)) {
4106             frag.appendChild(n);
4107         }
4108         return frag;
4109     };
4110 }
4111
4112 /**
4113  * @class Roo.DomHelper
4114  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4115  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4116  * @singleton
4117  */
4118 Roo.DomHelper = function(){
4119     var tempTableEl = null;
4120     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4121     var tableRe = /^table|tbody|tr|td$/i;
4122     var xmlns = {};
4123     // build as innerHTML where available
4124     /** @ignore */
4125     var createHtml = function(o){
4126         if(typeof o == 'string'){
4127             return o;
4128         }
4129         var b = "";
4130         if(!o.tag){
4131             o.tag = "div";
4132         }
4133         b += "<" + o.tag;
4134         for(var attr in o){
4135             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4136             if(attr == "style"){
4137                 var s = o["style"];
4138                 if(typeof s == "function"){
4139                     s = s.call();
4140                 }
4141                 if(typeof s == "string"){
4142                     b += ' style="' + s + '"';
4143                 }else if(typeof s == "object"){
4144                     b += ' style="';
4145                     for(var key in s){
4146                         if(typeof s[key] != "function"){
4147                             b += key + ":" + s[key] + ";";
4148                         }
4149                     }
4150                     b += '"';
4151                 }
4152             }else{
4153                 if(attr == "cls"){
4154                     b += ' class="' + o["cls"] + '"';
4155                 }else if(attr == "htmlFor"){
4156                     b += ' for="' + o["htmlFor"] + '"';
4157                 }else{
4158                     b += " " + attr + '="' + o[attr] + '"';
4159                 }
4160             }
4161         }
4162         if(emptyTags.test(o.tag)){
4163             b += "/>";
4164         }else{
4165             b += ">";
4166             var cn = o.children || o.cn;
4167             if(cn){
4168                 //http://bugs.kde.org/show_bug.cgi?id=71506
4169                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4170                     for(var i = 0, len = cn.length; i < len; i++) {
4171                         b += createHtml(cn[i], b);
4172                     }
4173                 }else{
4174                     b += createHtml(cn, b);
4175                 }
4176             }
4177             if(o.html){
4178                 b += o.html;
4179             }
4180             b += "</" + o.tag + ">";
4181         }
4182         return b;
4183     };
4184
4185     // build as dom
4186     /** @ignore */
4187     var createDom = function(o, parentNode){
4188          
4189         // defininition craeted..
4190         var ns = false;
4191         if (o.ns && o.ns != 'html') {
4192                
4193             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4194                 xmlns[o.ns] = o.xmlns;
4195                 ns = o.xmlns;
4196             }
4197             if (typeof(xmlns[o.ns]) == 'undefined') {
4198                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4199             }
4200             ns = xmlns[o.ns];
4201         }
4202         
4203         
4204         if (typeof(o) == 'string') {
4205             return parentNode.appendChild(document.createTextNode(o));
4206         }
4207         o.tag = o.tag || div;
4208         if (o.ns && Roo.isIE) {
4209             ns = false;
4210             o.tag = o.ns + ':' + o.tag;
4211             
4212         }
4213         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4214         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4215         for(var attr in o){
4216             
4217             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4218                     attr == "style" || typeof o[attr] == "function") continue;
4219                     
4220             if(attr=="cls" && Roo.isIE){
4221                 el.className = o["cls"];
4222             }else{
4223                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4224                 else el[attr] = o[attr];
4225             }
4226         }
4227         Roo.DomHelper.applyStyles(el, o.style);
4228         var cn = o.children || o.cn;
4229         if(cn){
4230             //http://bugs.kde.org/show_bug.cgi?id=71506
4231              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4232                 for(var i = 0, len = cn.length; i < len; i++) {
4233                     createDom(cn[i], el);
4234                 }
4235             }else{
4236                 createDom(cn, el);
4237             }
4238         }
4239         if(o.html){
4240             el.innerHTML = o.html;
4241         }
4242         if(parentNode){
4243            parentNode.appendChild(el);
4244         }
4245         return el;
4246     };
4247
4248     var ieTable = function(depth, s, h, e){
4249         tempTableEl.innerHTML = [s, h, e].join('');
4250         var i = -1, el = tempTableEl;
4251         while(++i < depth){
4252             el = el.firstChild;
4253         }
4254         return el;
4255     };
4256
4257     // kill repeat to save bytes
4258     var ts = '<table>',
4259         te = '</table>',
4260         tbs = ts+'<tbody>',
4261         tbe = '</tbody>'+te,
4262         trs = tbs + '<tr>',
4263         tre = '</tr>'+tbe;
4264
4265     /**
4266      * @ignore
4267      * Nasty code for IE's broken table implementation
4268      */
4269     var insertIntoTable = function(tag, where, el, html){
4270         if(!tempTableEl){
4271             tempTableEl = document.createElement('div');
4272         }
4273         var node;
4274         var before = null;
4275         if(tag == 'td'){
4276             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4277                 return;
4278             }
4279             if(where == 'beforebegin'){
4280                 before = el;
4281                 el = el.parentNode;
4282             } else{
4283                 before = el.nextSibling;
4284                 el = el.parentNode;
4285             }
4286             node = ieTable(4, trs, html, tre);
4287         }
4288         else if(tag == 'tr'){
4289             if(where == 'beforebegin'){
4290                 before = el;
4291                 el = el.parentNode;
4292                 node = ieTable(3, tbs, html, tbe);
4293             } else if(where == 'afterend'){
4294                 before = el.nextSibling;
4295                 el = el.parentNode;
4296                 node = ieTable(3, tbs, html, tbe);
4297             } else{ // INTO a TR
4298                 if(where == 'afterbegin'){
4299                     before = el.firstChild;
4300                 }
4301                 node = ieTable(4, trs, html, tre);
4302             }
4303         } else if(tag == 'tbody'){
4304             if(where == 'beforebegin'){
4305                 before = el;
4306                 el = el.parentNode;
4307                 node = ieTable(2, ts, html, te);
4308             } else if(where == 'afterend'){
4309                 before = el.nextSibling;
4310                 el = el.parentNode;
4311                 node = ieTable(2, ts, html, te);
4312             } else{
4313                 if(where == 'afterbegin'){
4314                     before = el.firstChild;
4315                 }
4316                 node = ieTable(3, tbs, html, tbe);
4317             }
4318         } else{ // TABLE
4319             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4320                 return;
4321             }
4322             if(where == 'afterbegin'){
4323                 before = el.firstChild;
4324             }
4325             node = ieTable(2, ts, html, te);
4326         }
4327         el.insertBefore(node, before);
4328         return node;
4329     };
4330
4331     return {
4332     /** True to force the use of DOM instead of html fragments @type Boolean */
4333     useDom : false,
4334
4335     /**
4336      * Returns the markup for the passed Element(s) config
4337      * @param {Object} o The Dom object spec (and children)
4338      * @return {String}
4339      */
4340     markup : function(o){
4341         return createHtml(o);
4342     },
4343
4344     /**
4345      * Applies a style specification to an element
4346      * @param {String/HTMLElement} el The element to apply styles to
4347      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4348      * a function which returns such a specification.
4349      */
4350     applyStyles : function(el, styles){
4351         if(styles){
4352            el = Roo.fly(el);
4353            if(typeof styles == "string"){
4354                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4355                var matches;
4356                while ((matches = re.exec(styles)) != null){
4357                    el.setStyle(matches[1], matches[2]);
4358                }
4359            }else if (typeof styles == "object"){
4360                for (var style in styles){
4361                   el.setStyle(style, styles[style]);
4362                }
4363            }else if (typeof styles == "function"){
4364                 Roo.DomHelper.applyStyles(el, styles.call());
4365            }
4366         }
4367     },
4368
4369     /**
4370      * Inserts an HTML fragment into the Dom
4371      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4372      * @param {HTMLElement} el The context element
4373      * @param {String} html The HTML fragmenet
4374      * @return {HTMLElement} The new node
4375      */
4376     insertHtml : function(where, el, html){
4377         where = where.toLowerCase();
4378         if(el.insertAdjacentHTML){
4379             if(tableRe.test(el.tagName)){
4380                 var rs;
4381                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4382                     return rs;
4383                 }
4384             }
4385             switch(where){
4386                 case "beforebegin":
4387                     el.insertAdjacentHTML('BeforeBegin', html);
4388                     return el.previousSibling;
4389                 case "afterbegin":
4390                     el.insertAdjacentHTML('AfterBegin', html);
4391                     return el.firstChild;
4392                 case "beforeend":
4393                     el.insertAdjacentHTML('BeforeEnd', html);
4394                     return el.lastChild;
4395                 case "afterend":
4396                     el.insertAdjacentHTML('AfterEnd', html);
4397                     return el.nextSibling;
4398             }
4399             throw 'Illegal insertion point -> "' + where + '"';
4400         }
4401         var range = el.ownerDocument.createRange();
4402         var frag;
4403         switch(where){
4404              case "beforebegin":
4405                 range.setStartBefore(el);
4406                 frag = range.createContextualFragment(html);
4407                 el.parentNode.insertBefore(frag, el);
4408                 return el.previousSibling;
4409              case "afterbegin":
4410                 if(el.firstChild){
4411                     range.setStartBefore(el.firstChild);
4412                     frag = range.createContextualFragment(html);
4413                     el.insertBefore(frag, el.firstChild);
4414                     return el.firstChild;
4415                 }else{
4416                     el.innerHTML = html;
4417                     return el.firstChild;
4418                 }
4419             case "beforeend":
4420                 if(el.lastChild){
4421                     range.setStartAfter(el.lastChild);
4422                     frag = range.createContextualFragment(html);
4423                     el.appendChild(frag);
4424                     return el.lastChild;
4425                 }else{
4426                     el.innerHTML = html;
4427                     return el.lastChild;
4428                 }
4429             case "afterend":
4430                 range.setStartAfter(el);
4431                 frag = range.createContextualFragment(html);
4432                 el.parentNode.insertBefore(frag, el.nextSibling);
4433                 return el.nextSibling;
4434             }
4435             throw 'Illegal insertion point -> "' + where + '"';
4436     },
4437
4438     /**
4439      * Creates new Dom element(s) and inserts them before el
4440      * @param {String/HTMLElement/Element} el The context element
4441      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4442      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4443      * @return {HTMLElement/Roo.Element} The new node
4444      */
4445     insertBefore : function(el, o, returnElement){
4446         return this.doInsert(el, o, returnElement, "beforeBegin");
4447     },
4448
4449     /**
4450      * Creates new Dom element(s) and inserts them after el
4451      * @param {String/HTMLElement/Element} el The context element
4452      * @param {Object} o The Dom object spec (and children)
4453      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4454      * @return {HTMLElement/Roo.Element} The new node
4455      */
4456     insertAfter : function(el, o, returnElement){
4457         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4458     },
4459
4460     /**
4461      * Creates new Dom element(s) and inserts them as the first child of el
4462      * @param {String/HTMLElement/Element} el The context element
4463      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4464      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4465      * @return {HTMLElement/Roo.Element} The new node
4466      */
4467     insertFirst : function(el, o, returnElement){
4468         return this.doInsert(el, o, returnElement, "afterBegin");
4469     },
4470
4471     // private
4472     doInsert : function(el, o, returnElement, pos, sibling){
4473         el = Roo.getDom(el);
4474         var newNode;
4475         if(this.useDom || o.ns){
4476             newNode = createDom(o, null);
4477             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4478         }else{
4479             var html = createHtml(o);
4480             newNode = this.insertHtml(pos, el, html);
4481         }
4482         return returnElement ? Roo.get(newNode, true) : newNode;
4483     },
4484
4485     /**
4486      * Creates new Dom element(s) and appends them to el
4487      * @param {String/HTMLElement/Element} el The context element
4488      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4489      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4490      * @return {HTMLElement/Roo.Element} The new node
4491      */
4492     append : function(el, o, returnElement){
4493         el = Roo.getDom(el);
4494         var newNode;
4495         if(this.useDom || o.ns){
4496             newNode = createDom(o, null);
4497             el.appendChild(newNode);
4498         }else{
4499             var html = createHtml(o);
4500             newNode = this.insertHtml("beforeEnd", el, html);
4501         }
4502         return returnElement ? Roo.get(newNode, true) : newNode;
4503     },
4504
4505     /**
4506      * Creates new Dom element(s) and overwrites the contents of el with them
4507      * @param {String/HTMLElement/Element} el The context element
4508      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4509      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4510      * @return {HTMLElement/Roo.Element} The new node
4511      */
4512     overwrite : function(el, o, returnElement){
4513         el = Roo.getDom(el);
4514         if (o.ns) {
4515           
4516             while (el.childNodes.length) {
4517                 el.removeChild(el.firstChild);
4518             }
4519             createDom(o, el);
4520         } else {
4521             el.innerHTML = createHtml(o);   
4522         }
4523         
4524         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4525     },
4526
4527     /**
4528      * Creates a new Roo.DomHelper.Template from the Dom object spec
4529      * @param {Object} o The Dom object spec (and children)
4530      * @return {Roo.DomHelper.Template} The new template
4531      */
4532     createTemplate : function(o){
4533         var html = createHtml(o);
4534         return new Roo.Template(html);
4535     }
4536     };
4537 }();
4538 /*
4539  * Based on:
4540  * Ext JS Library 1.1.1
4541  * Copyright(c) 2006-2007, Ext JS, LLC.
4542  *
4543  * Originally Released Under LGPL - original licence link has changed is not relivant.
4544  *
4545  * Fork - LGPL
4546  * <script type="text/javascript">
4547  */
4548  
4549 /**
4550 * @class Roo.Template
4551 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4552 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4553 * Usage:
4554 <pre><code>
4555 var t = new Roo.Template({
4556     html :  '&lt;div name="{id}"&gt;' + 
4557         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4558         '&lt;/div&gt;',
4559     myformat: function (value, allValues) {
4560         return 'XX' + value;
4561     }
4562 });
4563 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4564 </code></pre>
4565 * For more information see this blog post with examples:
4566 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4567      - Create Elements using DOM, HTML fragments and Templates</a>. 
4568 * @constructor
4569 * @param {Object} cfg - Configuration object.
4570 */
4571 Roo.Template = function(cfg){
4572     // BC!
4573     if(cfg instanceof Array){
4574         cfg = cfg.join("");
4575     }else if(arguments.length > 1){
4576         cfg = Array.prototype.join.call(arguments, "");
4577     }
4578     
4579     
4580     if (typeof(cfg) == 'object') {
4581         Roo.apply(this,cfg)
4582     } else {
4583         // bc
4584         this.html = cfg;
4585     }
4586     if (this.url) {
4587         this.load();
4588     }
4589     
4590 };
4591 Roo.Template.prototype = {
4592     
4593     /**
4594      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4595      *                    it should be fixed so that template is observable...
4596      */
4597     url : false,
4598     /**
4599      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4600      */
4601     html : '',
4602     /**
4603      * Returns an HTML fragment of this template with the specified values applied.
4604      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4605      * @return {String} The HTML fragment
4606      */
4607     applyTemplate : function(values){
4608         try {
4609            
4610             if(this.compiled){
4611                 return this.compiled(values);
4612             }
4613             var useF = this.disableFormats !== true;
4614             var fm = Roo.util.Format, tpl = this;
4615             var fn = function(m, name, format, args){
4616                 if(format && useF){
4617                     if(format.substr(0, 5) == "this."){
4618                         return tpl.call(format.substr(5), values[name], values);
4619                     }else{
4620                         if(args){
4621                             // quoted values are required for strings in compiled templates, 
4622                             // but for non compiled we need to strip them
4623                             // quoted reversed for jsmin
4624                             var re = /^\s*['"](.*)["']\s*$/;
4625                             args = args.split(',');
4626                             for(var i = 0, len = args.length; i < len; i++){
4627                                 args[i] = args[i].replace(re, "$1");
4628                             }
4629                             args = [values[name]].concat(args);
4630                         }else{
4631                             args = [values[name]];
4632                         }
4633                         return fm[format].apply(fm, args);
4634                     }
4635                 }else{
4636                     return values[name] !== undefined ? values[name] : "";
4637                 }
4638             };
4639             return this.html.replace(this.re, fn);
4640         } catch (e) {
4641             Roo.log(e);
4642             throw e;
4643         }
4644          
4645     },
4646     
4647     loading : false,
4648       
4649     load : function ()
4650     {
4651          
4652         if (this.loading) {
4653             return;
4654         }
4655         var _t = this;
4656         
4657         this.loading = true;
4658         this.compiled = false;
4659         
4660         var cx = new Roo.data.Connection();
4661         cx.request({
4662             url : this.url,
4663             method : 'GET',
4664             success : function (response) {
4665                 _t.loading = false;
4666                 _t.html = response.responseText;
4667                 _t.url = false;
4668                 _t.compile();
4669              },
4670             failure : function(response) {
4671                 Roo.log("Template failed to load from " + _t.url);
4672                 _t.loading = false;
4673             }
4674         });
4675     },
4676
4677     /**
4678      * Sets the HTML used as the template and optionally compiles it.
4679      * @param {String} html
4680      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4681      * @return {Roo.Template} this
4682      */
4683     set : function(html, compile){
4684         this.html = html;
4685         this.compiled = null;
4686         if(compile){
4687             this.compile();
4688         }
4689         return this;
4690     },
4691     
4692     /**
4693      * True to disable format functions (defaults to false)
4694      * @type Boolean
4695      */
4696     disableFormats : false,
4697     
4698     /**
4699     * The regular expression used to match template variables 
4700     * @type RegExp
4701     * @property 
4702     */
4703     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4704     
4705     /**
4706      * Compiles the template into an internal function, eliminating the RegEx overhead.
4707      * @return {Roo.Template} this
4708      */
4709     compile : function(){
4710         var fm = Roo.util.Format;
4711         var useF = this.disableFormats !== true;
4712         var sep = Roo.isGecko ? "+" : ",";
4713         var fn = function(m, name, format, args){
4714             if(format && useF){
4715                 args = args ? ',' + args : "";
4716                 if(format.substr(0, 5) != "this."){
4717                     format = "fm." + format + '(';
4718                 }else{
4719                     format = 'this.call("'+ format.substr(5) + '", ';
4720                     args = ", values";
4721                 }
4722             }else{
4723                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4724             }
4725             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4726         };
4727         var body;
4728         // branched to use + in gecko and [].join() in others
4729         if(Roo.isGecko){
4730             body = "this.compiled = function(values){ return '" +
4731                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4732                     "';};";
4733         }else{
4734             body = ["this.compiled = function(values){ return ['"];
4735             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4736             body.push("'].join('');};");
4737             body = body.join('');
4738         }
4739         /**
4740          * eval:var:values
4741          * eval:var:fm
4742          */
4743         eval(body);
4744         return this;
4745     },
4746     
4747     // private function used to call members
4748     call : function(fnName, value, allValues){
4749         return this[fnName](value, allValues);
4750     },
4751     
4752     /**
4753      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4754      * @param {String/HTMLElement/Roo.Element} el The context element
4755      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4756      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4757      * @return {HTMLElement/Roo.Element} The new node or Element
4758      */
4759     insertFirst: function(el, values, returnElement){
4760         return this.doInsert('afterBegin', el, values, returnElement);
4761     },
4762
4763     /**
4764      * Applies the supplied values to the template and inserts the new node(s) before el.
4765      * @param {String/HTMLElement/Roo.Element} el The context element
4766      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4767      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4768      * @return {HTMLElement/Roo.Element} The new node or Element
4769      */
4770     insertBefore: function(el, values, returnElement){
4771         return this.doInsert('beforeBegin', el, values, returnElement);
4772     },
4773
4774     /**
4775      * Applies the supplied values to the template and inserts the new node(s) after el.
4776      * @param {String/HTMLElement/Roo.Element} el The context element
4777      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4778      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4779      * @return {HTMLElement/Roo.Element} The new node or Element
4780      */
4781     insertAfter : function(el, values, returnElement){
4782         return this.doInsert('afterEnd', el, values, returnElement);
4783     },
4784     
4785     /**
4786      * Applies the supplied values to the template and appends the new node(s) to el.
4787      * @param {String/HTMLElement/Roo.Element} el The context element
4788      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4789      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790      * @return {HTMLElement/Roo.Element} The new node or Element
4791      */
4792     append : function(el, values, returnElement){
4793         return this.doInsert('beforeEnd', el, values, returnElement);
4794     },
4795
4796     doInsert : function(where, el, values, returnEl){
4797         el = Roo.getDom(el);
4798         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4799         return returnEl ? Roo.get(newNode, true) : newNode;
4800     },
4801
4802     /**
4803      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4804      * @param {String/HTMLElement/Roo.Element} el The context element
4805      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4806      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4807      * @return {HTMLElement/Roo.Element} The new node or Element
4808      */
4809     overwrite : function(el, values, returnElement){
4810         el = Roo.getDom(el);
4811         el.innerHTML = this.applyTemplate(values);
4812         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4813     }
4814 };
4815 /**
4816  * Alias for {@link #applyTemplate}
4817  * @method
4818  */
4819 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4820
4821 // backwards compat
4822 Roo.DomHelper.Template = Roo.Template;
4823
4824 /**
4825  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4826  * @param {String/HTMLElement} el A DOM element or its id
4827  * @returns {Roo.Template} The created template
4828  * @static
4829  */
4830 Roo.Template.from = function(el){
4831     el = Roo.getDom(el);
4832     return new Roo.Template(el.value || el.innerHTML);
4833 };/*
4834  * Based on:
4835  * Ext JS Library 1.1.1
4836  * Copyright(c) 2006-2007, Ext JS, LLC.
4837  *
4838  * Originally Released Under LGPL - original licence link has changed is not relivant.
4839  *
4840  * Fork - LGPL
4841  * <script type="text/javascript">
4842  */
4843  
4844
4845 /*
4846  * This is code is also distributed under MIT license for use
4847  * with jQuery and prototype JavaScript libraries.
4848  */
4849 /**
4850  * @class Roo.DomQuery
4851 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4852 <p>
4853 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4854
4855 <p>
4856 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4857 </p>
4858 <h4>Element Selectors:</h4>
4859 <ul class="list">
4860     <li> <b>*</b> any element</li>
4861     <li> <b>E</b> an element with the tag E</li>
4862     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4863     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4864     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4865     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4866 </ul>
4867 <h4>Attribute Selectors:</h4>
4868 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4869 <ul class="list">
4870     <li> <b>E[foo]</b> has an attribute "foo"</li>
4871     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4872     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4873     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4874     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4875     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4876     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4877 </ul>
4878 <h4>Pseudo Classes:</h4>
4879 <ul class="list">
4880     <li> <b>E:first-child</b> E is the first child of its parent</li>
4881     <li> <b>E:last-child</b> E is the last child of its parent</li>
4882     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4883     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4884     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4885     <li> <b>E:only-child</b> E is the only child of its parent</li>
4886     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4887     <li> <b>E:first</b> the first E in the resultset</li>
4888     <li> <b>E:last</b> the last E in the resultset</li>
4889     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4890     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4891     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4892     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4893     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4894     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4895     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4896     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4897     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4898 </ul>
4899 <h4>CSS Value Selectors:</h4>
4900 <ul class="list">
4901     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4902     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4903     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4904     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4905     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4906     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4907 </ul>
4908  * @singleton
4909  */
4910 Roo.DomQuery = function(){
4911     var cache = {}, simpleCache = {}, valueCache = {};
4912     var nonSpace = /\S/;
4913     var trimRe = /^\s+|\s+$/g;
4914     var tplRe = /\{(\d+)\}/g;
4915     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4916     var tagTokenRe = /^(#)?([\w-\*]+)/;
4917     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4918
4919     function child(p, index){
4920         var i = 0;
4921         var n = p.firstChild;
4922         while(n){
4923             if(n.nodeType == 1){
4924                if(++i == index){
4925                    return n;
4926                }
4927             }
4928             n = n.nextSibling;
4929         }
4930         return null;
4931     };
4932
4933     function next(n){
4934         while((n = n.nextSibling) && n.nodeType != 1);
4935         return n;
4936     };
4937
4938     function prev(n){
4939         while((n = n.previousSibling) && n.nodeType != 1);
4940         return n;
4941     };
4942
4943     function children(d){
4944         var n = d.firstChild, ni = -1;
4945             while(n){
4946                 var nx = n.nextSibling;
4947                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4948                     d.removeChild(n);
4949                 }else{
4950                     n.nodeIndex = ++ni;
4951                 }
4952                 n = nx;
4953             }
4954             return this;
4955         };
4956
4957     function byClassName(c, a, v){
4958         if(!v){
4959             return c;
4960         }
4961         var r = [], ri = -1, cn;
4962         for(var i = 0, ci; ci = c[i]; i++){
4963             if((' '+ci.className+' ').indexOf(v) != -1){
4964                 r[++ri] = ci;
4965             }
4966         }
4967         return r;
4968     };
4969
4970     function attrValue(n, attr){
4971         if(!n.tagName && typeof n.length != "undefined"){
4972             n = n[0];
4973         }
4974         if(!n){
4975             return null;
4976         }
4977         if(attr == "for"){
4978             return n.htmlFor;
4979         }
4980         if(attr == "class" || attr == "className"){
4981             return n.className;
4982         }
4983         return n.getAttribute(attr) || n[attr];
4984
4985     };
4986
4987     function getNodes(ns, mode, tagName){
4988         var result = [], ri = -1, cs;
4989         if(!ns){
4990             return result;
4991         }
4992         tagName = tagName || "*";
4993         if(typeof ns.getElementsByTagName != "undefined"){
4994             ns = [ns];
4995         }
4996         if(!mode){
4997             for(var i = 0, ni; ni = ns[i]; i++){
4998                 cs = ni.getElementsByTagName(tagName);
4999                 for(var j = 0, ci; ci = cs[j]; j++){
5000                     result[++ri] = ci;
5001                 }
5002             }
5003         }else if(mode == "/" || mode == ">"){
5004             var utag = tagName.toUpperCase();
5005             for(var i = 0, ni, cn; ni = ns[i]; i++){
5006                 cn = ni.children || ni.childNodes;
5007                 for(var j = 0, cj; cj = cn[j]; j++){
5008                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5009                         result[++ri] = cj;
5010                     }
5011                 }
5012             }
5013         }else if(mode == "+"){
5014             var utag = tagName.toUpperCase();
5015             for(var i = 0, n; n = ns[i]; i++){
5016                 while((n = n.nextSibling) && n.nodeType != 1);
5017                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5018                     result[++ri] = n;
5019                 }
5020             }
5021         }else if(mode == "~"){
5022             for(var i = 0, n; n = ns[i]; i++){
5023                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5024                 if(n){
5025                     result[++ri] = n;
5026                 }
5027             }
5028         }
5029         return result;
5030     };
5031
5032     function concat(a, b){
5033         if(b.slice){
5034             return a.concat(b);
5035         }
5036         for(var i = 0, l = b.length; i < l; i++){
5037             a[a.length] = b[i];
5038         }
5039         return a;
5040     }
5041
5042     function byTag(cs, tagName){
5043         if(cs.tagName || cs == document){
5044             cs = [cs];
5045         }
5046         if(!tagName){
5047             return cs;
5048         }
5049         var r = [], ri = -1;
5050         tagName = tagName.toLowerCase();
5051         for(var i = 0, ci; ci = cs[i]; i++){
5052             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5053                 r[++ri] = ci;
5054             }
5055         }
5056         return r;
5057     };
5058
5059     function byId(cs, attr, id){
5060         if(cs.tagName || cs == document){
5061             cs = [cs];
5062         }
5063         if(!id){
5064             return cs;
5065         }
5066         var r = [], ri = -1;
5067         for(var i = 0,ci; ci = cs[i]; i++){
5068             if(ci && ci.id == id){
5069                 r[++ri] = ci;
5070                 return r;
5071             }
5072         }
5073         return r;
5074     };
5075
5076     function byAttribute(cs, attr, value, op, custom){
5077         var r = [], ri = -1, st = custom=="{";
5078         var f = Roo.DomQuery.operators[op];
5079         for(var i = 0, ci; ci = cs[i]; i++){
5080             var a;
5081             if(st){
5082                 a = Roo.DomQuery.getStyle(ci, attr);
5083             }
5084             else if(attr == "class" || attr == "className"){
5085                 a = ci.className;
5086             }else if(attr == "for"){
5087                 a = ci.htmlFor;
5088             }else if(attr == "href"){
5089                 a = ci.getAttribute("href", 2);
5090             }else{
5091                 a = ci.getAttribute(attr);
5092             }
5093             if((f && f(a, value)) || (!f && a)){
5094                 r[++ri] = ci;
5095             }
5096         }
5097         return r;
5098     };
5099
5100     function byPseudo(cs, name, value){
5101         return Roo.DomQuery.pseudos[name](cs, value);
5102     };
5103
5104     // This is for IE MSXML which does not support expandos.
5105     // IE runs the same speed using setAttribute, however FF slows way down
5106     // and Safari completely fails so they need to continue to use expandos.
5107     var isIE = window.ActiveXObject ? true : false;
5108
5109     // this eval is stop the compressor from
5110     // renaming the variable to something shorter
5111     
5112     /** eval:var:batch */
5113     var batch = 30803; 
5114
5115     var key = 30803;
5116
5117     function nodupIEXml(cs){
5118         var d = ++key;
5119         cs[0].setAttribute("_nodup", d);
5120         var r = [cs[0]];
5121         for(var i = 1, len = cs.length; i < len; i++){
5122             var c = cs[i];
5123             if(!c.getAttribute("_nodup") != d){
5124                 c.setAttribute("_nodup", d);
5125                 r[r.length] = c;
5126             }
5127         }
5128         for(var i = 0, len = cs.length; i < len; i++){
5129             cs[i].removeAttribute("_nodup");
5130         }
5131         return r;
5132     }
5133
5134     function nodup(cs){
5135         if(!cs){
5136             return [];
5137         }
5138         var len = cs.length, c, i, r = cs, cj, ri = -1;
5139         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5140             return cs;
5141         }
5142         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5143             return nodupIEXml(cs);
5144         }
5145         var d = ++key;
5146         cs[0]._nodup = d;
5147         for(i = 1; c = cs[i]; i++){
5148             if(c._nodup != d){
5149                 c._nodup = d;
5150             }else{
5151                 r = [];
5152                 for(var j = 0; j < i; j++){
5153                     r[++ri] = cs[j];
5154                 }
5155                 for(j = i+1; cj = cs[j]; j++){
5156                     if(cj._nodup != d){
5157                         cj._nodup = d;
5158                         r[++ri] = cj;
5159                     }
5160                 }
5161                 return r;
5162             }
5163         }
5164         return r;
5165     }
5166
5167     function quickDiffIEXml(c1, c2){
5168         var d = ++key;
5169         for(var i = 0, len = c1.length; i < len; i++){
5170             c1[i].setAttribute("_qdiff", d);
5171         }
5172         var r = [];
5173         for(var i = 0, len = c2.length; i < len; i++){
5174             if(c2[i].getAttribute("_qdiff") != d){
5175                 r[r.length] = c2[i];
5176             }
5177         }
5178         for(var i = 0, len = c1.length; i < len; i++){
5179            c1[i].removeAttribute("_qdiff");
5180         }
5181         return r;
5182     }
5183
5184     function quickDiff(c1, c2){
5185         var len1 = c1.length;
5186         if(!len1){
5187             return c2;
5188         }
5189         if(isIE && c1[0].selectSingleNode){
5190             return quickDiffIEXml(c1, c2);
5191         }
5192         var d = ++key;
5193         for(var i = 0; i < len1; i++){
5194             c1[i]._qdiff = d;
5195         }
5196         var r = [];
5197         for(var i = 0, len = c2.length; i < len; i++){
5198             if(c2[i]._qdiff != d){
5199                 r[r.length] = c2[i];
5200             }
5201         }
5202         return r;
5203     }
5204
5205     function quickId(ns, mode, root, id){
5206         if(ns == root){
5207            var d = root.ownerDocument || root;
5208            return d.getElementById(id);
5209         }
5210         ns = getNodes(ns, mode, "*");
5211         return byId(ns, null, id);
5212     }
5213
5214     return {
5215         getStyle : function(el, name){
5216             return Roo.fly(el).getStyle(name);
5217         },
5218         /**
5219          * Compiles a selector/xpath query into a reusable function. The returned function
5220          * takes one parameter "root" (optional), which is the context node from where the query should start.
5221          * @param {String} selector The selector/xpath query
5222          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5223          * @return {Function}
5224          */
5225         compile : function(path, type){
5226             type = type || "select";
5227             
5228             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5229             var q = path, mode, lq;
5230             var tk = Roo.DomQuery.matchers;
5231             var tklen = tk.length;
5232             var mm;
5233
5234             // accept leading mode switch
5235             var lmode = q.match(modeRe);
5236             if(lmode && lmode[1]){
5237                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5238                 q = q.replace(lmode[1], "");
5239             }
5240             // strip leading slashes
5241             while(path.substr(0, 1)=="/"){
5242                 path = path.substr(1);
5243             }
5244
5245             while(q && lq != q){
5246                 lq = q;
5247                 var tm = q.match(tagTokenRe);
5248                 if(type == "select"){
5249                     if(tm){
5250                         if(tm[1] == "#"){
5251                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5252                         }else{
5253                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5254                         }
5255                         q = q.replace(tm[0], "");
5256                     }else if(q.substr(0, 1) != '@'){
5257                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258                     }
5259                 }else{
5260                     if(tm){
5261                         if(tm[1] == "#"){
5262                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5263                         }else{
5264                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5265                         }
5266                         q = q.replace(tm[0], "");
5267                     }
5268                 }
5269                 while(!(mm = q.match(modeRe))){
5270                     var matched = false;
5271                     for(var j = 0; j < tklen; j++){
5272                         var t = tk[j];
5273                         var m = q.match(t.re);
5274                         if(m){
5275                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5276                                                     return m[i];
5277                                                 });
5278                             q = q.replace(m[0], "");
5279                             matched = true;
5280                             break;
5281                         }
5282                     }
5283                     // prevent infinite loop on bad selector
5284                     if(!matched){
5285                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5286                     }
5287                 }
5288                 if(mm[1]){
5289                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5290                     q = q.replace(mm[1], "");
5291                 }
5292             }
5293             fn[fn.length] = "return nodup(n);\n}";
5294             
5295              /** 
5296               * list of variables that need from compression as they are used by eval.
5297              *  eval:var:batch 
5298              *  eval:var:nodup
5299              *  eval:var:byTag
5300              *  eval:var:ById
5301              *  eval:var:getNodes
5302              *  eval:var:quickId
5303              *  eval:var:mode
5304              *  eval:var:root
5305              *  eval:var:n
5306              *  eval:var:byClassName
5307              *  eval:var:byPseudo
5308              *  eval:var:byAttribute
5309              *  eval:var:attrValue
5310              * 
5311              **/ 
5312             eval(fn.join(""));
5313             return f;
5314         },
5315
5316         /**
5317          * Selects a group of elements.
5318          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5319          * @param {Node} root (optional) The start of the query (defaults to document).
5320          * @return {Array}
5321          */
5322         select : function(path, root, type){
5323             if(!root || root == document){
5324                 root = document;
5325             }
5326             if(typeof root == "string"){
5327                 root = document.getElementById(root);
5328             }
5329             var paths = path.split(",");
5330             var results = [];
5331             for(var i = 0, len = paths.length; i < len; i++){
5332                 var p = paths[i].replace(trimRe, "");
5333                 if(!cache[p]){
5334                     cache[p] = Roo.DomQuery.compile(p);
5335                     if(!cache[p]){
5336                         throw p + " is not a valid selector";
5337                     }
5338                 }
5339                 var result = cache[p](root);
5340                 if(result && result != document){
5341                     results = results.concat(result);
5342                 }
5343             }
5344             if(paths.length > 1){
5345                 return nodup(results);
5346             }
5347             return results;
5348         },
5349
5350         /**
5351          * Selects a single element.
5352          * @param {String} selector The selector/xpath query
5353          * @param {Node} root (optional) The start of the query (defaults to document).
5354          * @return {Element}
5355          */
5356         selectNode : function(path, root){
5357             return Roo.DomQuery.select(path, root)[0];
5358         },
5359
5360         /**
5361          * Selects the value of a node, optionally replacing null with the defaultValue.
5362          * @param {String} selector The selector/xpath query
5363          * @param {Node} root (optional) The start of the query (defaults to document).
5364          * @param {String} defaultValue
5365          */
5366         selectValue : function(path, root, defaultValue){
5367             path = path.replace(trimRe, "");
5368             if(!valueCache[path]){
5369                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5370             }
5371             var n = valueCache[path](root);
5372             n = n[0] ? n[0] : n;
5373             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5374             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5375         },
5376
5377         /**
5378          * Selects the value of a node, parsing integers and floats.
5379          * @param {String} selector The selector/xpath query
5380          * @param {Node} root (optional) The start of the query (defaults to document).
5381          * @param {Number} defaultValue
5382          * @return {Number}
5383          */
5384         selectNumber : function(path, root, defaultValue){
5385             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5386             return parseFloat(v);
5387         },
5388
5389         /**
5390          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5391          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5392          * @param {String} selector The simple selector to test
5393          * @return {Boolean}
5394          */
5395         is : function(el, ss){
5396             if(typeof el == "string"){
5397                 el = document.getElementById(el);
5398             }
5399             var isArray = (el instanceof Array);
5400             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5401             return isArray ? (result.length == el.length) : (result.length > 0);
5402         },
5403
5404         /**
5405          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5406          * @param {Array} el An array of elements to filter
5407          * @param {String} selector The simple selector to test
5408          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5409          * the selector instead of the ones that match
5410          * @return {Array}
5411          */
5412         filter : function(els, ss, nonMatches){
5413             ss = ss.replace(trimRe, "");
5414             if(!simpleCache[ss]){
5415                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5416             }
5417             var result = simpleCache[ss](els);
5418             return nonMatches ? quickDiff(result, els) : result;
5419         },
5420
5421         /**
5422          * Collection of matching regular expressions and code snippets.
5423          */
5424         matchers : [{
5425                 re: /^\.([\w-]+)/,
5426                 select: 'n = byClassName(n, null, " {1} ");'
5427             }, {
5428                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5429                 select: 'n = byPseudo(n, "{1}", "{2}");'
5430             },{
5431                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5432                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5433             }, {
5434                 re: /^#([\w-]+)/,
5435                 select: 'n = byId(n, null, "{1}");'
5436             },{
5437                 re: /^@([\w-]+)/,
5438                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439             }
5440         ],
5441
5442         /**
5443          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5444          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5445          */
5446         operators : {
5447             "=" : function(a, v){
5448                 return a == v;
5449             },
5450             "!=" : function(a, v){
5451                 return a != v;
5452             },
5453             "^=" : function(a, v){
5454                 return a && a.substr(0, v.length) == v;
5455             },
5456             "$=" : function(a, v){
5457                 return a && a.substr(a.length-v.length) == v;
5458             },
5459             "*=" : function(a, v){
5460                 return a && a.indexOf(v) !== -1;
5461             },
5462             "%=" : function(a, v){
5463                 return (a % v) == 0;
5464             },
5465             "|=" : function(a, v){
5466                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5467             },
5468             "~=" : function(a, v){
5469                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470             }
5471         },
5472
5473         /**
5474          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5475          * and the argument (if any) supplied in the selector.
5476          */
5477         pseudos : {
5478             "first-child" : function(c){
5479                 var r = [], ri = -1, n;
5480                 for(var i = 0, ci; ci = n = c[i]; i++){
5481                     while((n = n.previousSibling) && n.nodeType != 1);
5482                     if(!n){
5483                         r[++ri] = ci;
5484                     }
5485                 }
5486                 return r;
5487             },
5488
5489             "last-child" : function(c){
5490                 var r = [], ri = -1, n;
5491                 for(var i = 0, ci; ci = n = c[i]; i++){
5492                     while((n = n.nextSibling) && n.nodeType != 1);
5493                     if(!n){
5494                         r[++ri] = ci;
5495                     }
5496                 }
5497                 return r;
5498             },
5499
5500             "nth-child" : function(c, a) {
5501                 var r = [], ri = -1;
5502                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5503                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5504                 for(var i = 0, n; n = c[i]; i++){
5505                     var pn = n.parentNode;
5506                     if (batch != pn._batch) {
5507                         var j = 0;
5508                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5509                             if(cn.nodeType == 1){
5510                                cn.nodeIndex = ++j;
5511                             }
5512                         }
5513                         pn._batch = batch;
5514                     }
5515                     if (f == 1) {
5516                         if (l == 0 || n.nodeIndex == l){
5517                             r[++ri] = n;
5518                         }
5519                     } else if ((n.nodeIndex + l) % f == 0){
5520                         r[++ri] = n;
5521                     }
5522                 }
5523
5524                 return r;
5525             },
5526
5527             "only-child" : function(c){
5528                 var r = [], ri = -1;;
5529                 for(var i = 0, ci; ci = c[i]; i++){
5530                     if(!prev(ci) && !next(ci)){
5531                         r[++ri] = ci;
5532                     }
5533                 }
5534                 return r;
5535             },
5536
5537             "empty" : function(c){
5538                 var r = [], ri = -1;
5539                 for(var i = 0, ci; ci = c[i]; i++){
5540                     var cns = ci.childNodes, j = 0, cn, empty = true;
5541                     while(cn = cns[j]){
5542                         ++j;
5543                         if(cn.nodeType == 1 || cn.nodeType == 3){
5544                             empty = false;
5545                             break;
5546                         }
5547                     }
5548                     if(empty){
5549                         r[++ri] = ci;
5550                     }
5551                 }
5552                 return r;
5553             },
5554
5555             "contains" : function(c, v){
5556                 var r = [], ri = -1;
5557                 for(var i = 0, ci; ci = c[i]; i++){
5558                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5559                         r[++ri] = ci;
5560                     }
5561                 }
5562                 return r;
5563             },
5564
5565             "nodeValue" : function(c, v){
5566                 var r = [], ri = -1;
5567                 for(var i = 0, ci; ci = c[i]; i++){
5568                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5569                         r[++ri] = ci;
5570                     }
5571                 }
5572                 return r;
5573             },
5574
5575             "checked" : function(c){
5576                 var r = [], ri = -1;
5577                 for(var i = 0, ci; ci = c[i]; i++){
5578                     if(ci.checked == true){
5579                         r[++ri] = ci;
5580                     }
5581                 }
5582                 return r;
5583             },
5584
5585             "not" : function(c, ss){
5586                 return Roo.DomQuery.filter(c, ss, true);
5587             },
5588
5589             "odd" : function(c){
5590                 return this["nth-child"](c, "odd");
5591             },
5592
5593             "even" : function(c){
5594                 return this["nth-child"](c, "even");
5595             },
5596
5597             "nth" : function(c, a){
5598                 return c[a-1] || [];
5599             },
5600
5601             "first" : function(c){
5602                 return c[0] || [];
5603             },
5604
5605             "last" : function(c){
5606                 return c[c.length-1] || [];
5607             },
5608
5609             "has" : function(c, ss){
5610                 var s = Roo.DomQuery.select;
5611                 var r = [], ri = -1;
5612                 for(var i = 0, ci; ci = c[i]; i++){
5613                     if(s(ss, ci).length > 0){
5614                         r[++ri] = ci;
5615                     }
5616                 }
5617                 return r;
5618             },
5619
5620             "next" : function(c, ss){
5621                 var is = Roo.DomQuery.is;
5622                 var r = [], ri = -1;
5623                 for(var i = 0, ci; ci = c[i]; i++){
5624                     var n = next(ci);
5625                     if(n && is(n, ss)){
5626                         r[++ri] = ci;
5627                     }
5628                 }
5629                 return r;
5630             },
5631
5632             "prev" : function(c, ss){
5633                 var is = Roo.DomQuery.is;
5634                 var r = [], ri = -1;
5635                 for(var i = 0, ci; ci = c[i]; i++){
5636                     var n = prev(ci);
5637                     if(n && is(n, ss)){
5638                         r[++ri] = ci;
5639                     }
5640                 }
5641                 return r;
5642             }
5643         }
5644     };
5645 }();
5646
5647 /**
5648  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5649  * @param {String} path The selector/xpath query
5650  * @param {Node} root (optional) The start of the query (defaults to document).
5651  * @return {Array}
5652  * @member Roo
5653  * @method query
5654  */
5655 Roo.query = Roo.DomQuery.select;
5656 /*
5657  * Based on:
5658  * Ext JS Library 1.1.1
5659  * Copyright(c) 2006-2007, Ext JS, LLC.
5660  *
5661  * Originally Released Under LGPL - original licence link has changed is not relivant.
5662  *
5663  * Fork - LGPL
5664  * <script type="text/javascript">
5665  */
5666
5667 /**
5668  * @class Roo.util.Observable
5669  * Base class that provides a common interface for publishing events. Subclasses are expected to
5670  * to have a property "events" with all the events defined.<br>
5671  * For example:
5672  * <pre><code>
5673  Employee = function(name){
5674     this.name = name;
5675     this.addEvents({
5676         "fired" : true,
5677         "quit" : true
5678     });
5679  }
5680  Roo.extend(Employee, Roo.util.Observable);
5681 </code></pre>
5682  * @param {Object} config properties to use (incuding events / listeners)
5683  */
5684
5685 Roo.util.Observable = function(cfg){
5686     
5687     cfg = cfg|| {};
5688     this.addEvents(cfg.events || {});
5689     if (cfg.events) {
5690         delete cfg.events; // make sure
5691     }
5692      
5693     Roo.apply(this, cfg);
5694     
5695     if(this.listeners){
5696         this.on(this.listeners);
5697         delete this.listeners;
5698     }
5699 };
5700 Roo.util.Observable.prototype = {
5701     /** 
5702  * @cfg {Object} listeners  list of events and functions to call for this object, 
5703  * For example :
5704  * <pre><code>
5705     listeners :  { 
5706        'click' : function(e) {
5707            ..... 
5708         } ,
5709         .... 
5710     } 
5711   </code></pre>
5712  */
5713     
5714     
5715     /**
5716      * Fires the specified event with the passed parameters (minus the event name).
5717      * @param {String} eventName
5718      * @param {Object...} args Variable number of parameters are passed to handlers
5719      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5720      */
5721     fireEvent : function(){
5722         var ce = this.events[arguments[0].toLowerCase()];
5723         if(typeof ce == "object"){
5724             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5725         }else{
5726             return true;
5727         }
5728     },
5729
5730     // private
5731     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5732
5733     /**
5734      * Appends an event handler to this component
5735      * @param {String}   eventName The type of event to listen for
5736      * @param {Function} handler The method the event invokes
5737      * @param {Object}   scope (optional) The scope in which to execute the handler
5738      * function. The handler function's "this" context.
5739      * @param {Object}   options (optional) An object containing handler configuration
5740      * properties. This may contain any of the following properties:<ul>
5741      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5742      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5743      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5744      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5745      * by the specified number of milliseconds. If the event fires again within that time, the original
5746      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5747      * </ul><br>
5748      * <p>
5749      * <b>Combining Options</b><br>
5750      * Using the options argument, it is possible to combine different types of listeners:<br>
5751      * <br>
5752      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5753                 <pre><code>
5754                 el.on('click', this.onClick, this, {
5755                         single: true,
5756                 delay: 100,
5757                 forumId: 4
5758                 });
5759                 </code></pre>
5760      * <p>
5761      * <b>Attaching multiple handlers in 1 call</b><br>
5762      * The method also allows for a single argument to be passed which is a config object containing properties
5763      * which specify multiple handlers.
5764      * <pre><code>
5765                 el.on({
5766                         'click': {
5767                         fn: this.onClick,
5768                         scope: this,
5769                         delay: 100
5770                 }, 
5771                 'mouseover': {
5772                         fn: this.onMouseOver,
5773                         scope: this
5774                 },
5775                 'mouseout': {
5776                         fn: this.onMouseOut,
5777                         scope: this
5778                 }
5779                 });
5780                 </code></pre>
5781      * <p>
5782      * Or a shorthand syntax which passes the same scope object to all handlers:
5783         <pre><code>
5784                 el.on({
5785                         'click': this.onClick,
5786                 'mouseover': this.onMouseOver,
5787                 'mouseout': this.onMouseOut,
5788                 scope: this
5789                 });
5790                 </code></pre>
5791      */
5792     addListener : function(eventName, fn, scope, o){
5793         if(typeof eventName == "object"){
5794             o = eventName;
5795             for(var e in o){
5796                 if(this.filterOptRe.test(e)){
5797                     continue;
5798                 }
5799                 if(typeof o[e] == "function"){
5800                     // shared options
5801                     this.addListener(e, o[e], o.scope,  o);
5802                 }else{
5803                     // individual options
5804                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805                 }
5806             }
5807             return;
5808         }
5809         o = (!o || typeof o == "boolean") ? {} : o;
5810         eventName = eventName.toLowerCase();
5811         var ce = this.events[eventName] || true;
5812         if(typeof ce == "boolean"){
5813             ce = new Roo.util.Event(this, eventName);
5814             this.events[eventName] = ce;
5815         }
5816         ce.addListener(fn, scope, o);
5817     },
5818
5819     /**
5820      * Removes a listener
5821      * @param {String}   eventName     The type of event to listen for
5822      * @param {Function} handler        The handler to remove
5823      * @param {Object}   scope  (optional) The scope (this object) for the handler
5824      */
5825     removeListener : function(eventName, fn, scope){
5826         var ce = this.events[eventName.toLowerCase()];
5827         if(typeof ce == "object"){
5828             ce.removeListener(fn, scope);
5829         }
5830     },
5831
5832     /**
5833      * Removes all listeners for this object
5834      */
5835     purgeListeners : function(){
5836         for(var evt in this.events){
5837             if(typeof this.events[evt] == "object"){
5838                  this.events[evt].clearListeners();
5839             }
5840         }
5841     },
5842
5843     relayEvents : function(o, events){
5844         var createHandler = function(ename){
5845             return function(){
5846                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5847             };
5848         };
5849         for(var i = 0, len = events.length; i < len; i++){
5850             var ename = events[i];
5851             if(!this.events[ename]){ this.events[ename] = true; };
5852             o.on(ename, createHandler(ename), this);
5853         }
5854     },
5855
5856     /**
5857      * Used to define events on this Observable
5858      * @param {Object} object The object with the events defined
5859      */
5860     addEvents : function(o){
5861         if(!this.events){
5862             this.events = {};
5863         }
5864         Roo.applyIf(this.events, o);
5865     },
5866
5867     /**
5868      * Checks to see if this object has any listeners for a specified event
5869      * @param {String} eventName The name of the event to check for
5870      * @return {Boolean} True if the event is being listened for, else false
5871      */
5872     hasListener : function(eventName){
5873         var e = this.events[eventName];
5874         return typeof e == "object" && e.listeners.length > 0;
5875     }
5876 };
5877 /**
5878  * Appends an event handler to this element (shorthand for addListener)
5879  * @param {String}   eventName     The type of event to listen for
5880  * @param {Function} handler        The method the event invokes
5881  * @param {Object}   scope (optional) The scope in which to execute the handler
5882  * function. The handler function's "this" context.
5883  * @param {Object}   options  (optional)
5884  * @method
5885  */
5886 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5887 /**
5888  * Removes a listener (shorthand for removeListener)
5889  * @param {String}   eventName     The type of event to listen for
5890  * @param {Function} handler        The handler to remove
5891  * @param {Object}   scope  (optional) The scope (this object) for the handler
5892  * @method
5893  */
5894 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5895
5896 /**
5897  * Starts capture on the specified Observable. All events will be passed
5898  * to the supplied function with the event name + standard signature of the event
5899  * <b>before</b> the event is fired. If the supplied function returns false,
5900  * the event will not fire.
5901  * @param {Observable} o The Observable to capture
5902  * @param {Function} fn The function to call
5903  * @param {Object} scope (optional) The scope (this object) for the fn
5904  * @static
5905  */
5906 Roo.util.Observable.capture = function(o, fn, scope){
5907     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5908 };
5909
5910 /**
5911  * Removes <b>all</b> added captures from the Observable.
5912  * @param {Observable} o The Observable to release
5913  * @static
5914  */
5915 Roo.util.Observable.releaseCapture = function(o){
5916     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 };
5918
5919 (function(){
5920
5921     var createBuffered = function(h, o, scope){
5922         var task = new Roo.util.DelayedTask();
5923         return function(){
5924             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5925         };
5926     };
5927
5928     var createSingle = function(h, e, fn, scope){
5929         return function(){
5930             e.removeListener(fn, scope);
5931             return h.apply(scope, arguments);
5932         };
5933     };
5934
5935     var createDelayed = function(h, o, scope){
5936         return function(){
5937             var args = Array.prototype.slice.call(arguments, 0);
5938             setTimeout(function(){
5939                 h.apply(scope, args);
5940             }, o.delay || 10);
5941         };
5942     };
5943
5944     Roo.util.Event = function(obj, name){
5945         this.name = name;
5946         this.obj = obj;
5947         this.listeners = [];
5948     };
5949
5950     Roo.util.Event.prototype = {
5951         addListener : function(fn, scope, options){
5952             var o = options || {};
5953             scope = scope || this.obj;
5954             if(!this.isListening(fn, scope)){
5955                 var l = {fn: fn, scope: scope, options: o};
5956                 var h = fn;
5957                 if(o.delay){
5958                     h = createDelayed(h, o, scope);
5959                 }
5960                 if(o.single){
5961                     h = createSingle(h, this, fn, scope);
5962                 }
5963                 if(o.buffer){
5964                     h = createBuffered(h, o, scope);
5965                 }
5966                 l.fireFn = h;
5967                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5968                     this.listeners.push(l);
5969                 }else{
5970                     this.listeners = this.listeners.slice(0);
5971                     this.listeners.push(l);
5972                 }
5973             }
5974         },
5975
5976         findListener : function(fn, scope){
5977             scope = scope || this.obj;
5978             var ls = this.listeners;
5979             for(var i = 0, len = ls.length; i < len; i++){
5980                 var l = ls[i];
5981                 if(l.fn == fn && l.scope == scope){
5982                     return i;
5983                 }
5984             }
5985             return -1;
5986         },
5987
5988         isListening : function(fn, scope){
5989             return this.findListener(fn, scope) != -1;
5990         },
5991
5992         removeListener : function(fn, scope){
5993             var index;
5994             if((index = this.findListener(fn, scope)) != -1){
5995                 if(!this.firing){
5996                     this.listeners.splice(index, 1);
5997                 }else{
5998                     this.listeners = this.listeners.slice(0);
5999                     this.listeners.splice(index, 1);
6000                 }
6001                 return true;
6002             }
6003             return false;
6004         },
6005
6006         clearListeners : function(){
6007             this.listeners = [];
6008         },
6009
6010         fire : function(){
6011             var ls = this.listeners, scope, len = ls.length;
6012             if(len > 0){
6013                 this.firing = true;
6014                 var args = Array.prototype.slice.call(arguments, 0);
6015                 for(var i = 0; i < len; i++){
6016                     var l = ls[i];
6017                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6018                         this.firing = false;
6019                         return false;
6020                     }
6021                 }
6022                 this.firing = false;
6023             }
6024             return true;
6025         }
6026     };
6027 })();/*
6028  * Based on:
6029  * Ext JS Library 1.1.1
6030  * Copyright(c) 2006-2007, Ext JS, LLC.
6031  *
6032  * Originally Released Under LGPL - original licence link has changed is not relivant.
6033  *
6034  * Fork - LGPL
6035  * <script type="text/javascript">
6036  */
6037
6038 /**
6039  * @class Roo.EventManager
6040  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6041  * several useful events directly.
6042  * See {@link Roo.EventObject} for more details on normalized event objects.
6043  * @singleton
6044  */
6045 Roo.EventManager = function(){
6046     var docReadyEvent, docReadyProcId, docReadyState = false;
6047     var resizeEvent, resizeTask, textEvent, textSize;
6048     var E = Roo.lib.Event;
6049     var D = Roo.lib.Dom;
6050
6051     
6052     
6053
6054     var fireDocReady = function(){
6055         if(!docReadyState){
6056             docReadyState = true;
6057             Roo.isReady = true;
6058             if(docReadyProcId){
6059                 clearInterval(docReadyProcId);
6060             }
6061             if(Roo.isGecko || Roo.isOpera) {
6062                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6063             }
6064             if(Roo.isIE){
6065                 var defer = document.getElementById("ie-deferred-loader");
6066                 if(defer){
6067                     defer.onreadystatechange = null;
6068                     defer.parentNode.removeChild(defer);
6069                 }
6070             }
6071             if(docReadyEvent){
6072                 docReadyEvent.fire();
6073                 docReadyEvent.clearListeners();
6074             }
6075         }
6076     };
6077     
6078     var initDocReady = function(){
6079         docReadyEvent = new Roo.util.Event();
6080         if(Roo.isGecko || Roo.isOpera) {
6081             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6082         }else if(Roo.isIE){
6083             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6084             var defer = document.getElementById("ie-deferred-loader");
6085             defer.onreadystatechange = function(){
6086                 if(this.readyState == "complete"){
6087                     fireDocReady();
6088                 }
6089             };
6090         }else if(Roo.isSafari){ 
6091             docReadyProcId = setInterval(function(){
6092                 var rs = document.readyState;
6093                 if(rs == "complete") {
6094                     fireDocReady();     
6095                  }
6096             }, 10);
6097         }
6098         // no matter what, make sure it fires on load
6099         E.on(window, "load", fireDocReady);
6100     };
6101
6102     var createBuffered = function(h, o){
6103         var task = new Roo.util.DelayedTask(h);
6104         return function(e){
6105             // create new event object impl so new events don't wipe out properties
6106             e = new Roo.EventObjectImpl(e);
6107             task.delay(o.buffer, h, null, [e]);
6108         };
6109     };
6110
6111     var createSingle = function(h, el, ename, fn){
6112         return function(e){
6113             Roo.EventManager.removeListener(el, ename, fn);
6114             h(e);
6115         };
6116     };
6117
6118     var createDelayed = function(h, o){
6119         return function(e){
6120             // create new event object impl so new events don't wipe out properties
6121             e = new Roo.EventObjectImpl(e);
6122             setTimeout(function(){
6123                 h(e);
6124             }, o.delay || 10);
6125         };
6126     };
6127     var transitionEndVal = false;
6128     
6129     var transitionEnd = function()
6130     {
6131         if (transitionEndVal) {
6132             return transitionEndVal;
6133         }
6134         var el = document.createElement('div');
6135
6136         var transEndEventNames = {
6137             WebkitTransition : 'webkitTransitionEnd',
6138             MozTransition    : 'transitionend',
6139             OTransition      : 'oTransitionEnd otransitionend',
6140             transition       : 'transitionend'
6141         };
6142     
6143         for (var name in transEndEventNames) {
6144             if (el.style[name] !== undefined) {
6145                 transitionEndVal = transEndEventNames[name];
6146                 return  transitionEndVal ;
6147             }
6148         }
6149     }
6150     
6151
6152     var listen = function(element, ename, opt, fn, scope){
6153         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6154         fn = fn || o.fn; scope = scope || o.scope;
6155         var el = Roo.getDom(element);
6156         
6157         
6158         if(!el){
6159             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6160         }
6161         
6162         if (ename == 'transitionend') {
6163             ename = transitionEnd();
6164         }
6165         var h = function(e){
6166             e = Roo.EventObject.setEvent(e);
6167             var t;
6168             if(o.delegate){
6169                 t = e.getTarget(o.delegate, el);
6170                 if(!t){
6171                     return;
6172                 }
6173             }else{
6174                 t = e.target;
6175             }
6176             if(o.stopEvent === true){
6177                 e.stopEvent();
6178             }
6179             if(o.preventDefault === true){
6180                e.preventDefault();
6181             }
6182             if(o.stopPropagation === true){
6183                 e.stopPropagation();
6184             }
6185
6186             if(o.normalized === false){
6187                 e = e.browserEvent;
6188             }
6189
6190             fn.call(scope || el, e, t, o);
6191         };
6192         if(o.delay){
6193             h = createDelayed(h, o);
6194         }
6195         if(o.single){
6196             h = createSingle(h, el, ename, fn);
6197         }
6198         if(o.buffer){
6199             h = createBuffered(h, o);
6200         }
6201         fn._handlers = fn._handlers || [];
6202         
6203         
6204         fn._handlers.push([Roo.id(el), ename, h]);
6205         
6206         
6207          
6208         E.on(el, ename, h);
6209         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6210             el.addEventListener("DOMMouseScroll", h, false);
6211             E.on(window, 'unload', function(){
6212                 el.removeEventListener("DOMMouseScroll", h, false);
6213             });
6214         }
6215         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6216             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6217         }
6218         return h;
6219     };
6220
6221     var stopListening = function(el, ename, fn){
6222         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6223         if(hds){
6224             for(var i = 0, len = hds.length; i < len; i++){
6225                 var h = hds[i];
6226                 if(h[0] == id && h[1] == ename){
6227                     hd = h[2];
6228                     hds.splice(i, 1);
6229                     break;
6230                 }
6231             }
6232         }
6233         E.un(el, ename, hd);
6234         el = Roo.getDom(el);
6235         if(ename == "mousewheel" && el.addEventListener){
6236             el.removeEventListener("DOMMouseScroll", hd, false);
6237         }
6238         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6239             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6240         }
6241     };
6242
6243     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6244     
6245     var pub = {
6246         
6247         
6248         /** 
6249          * Fix for doc tools
6250          * @scope Roo.EventManager
6251          */
6252         
6253         
6254         /** 
6255          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6256          * object with a Roo.EventObject
6257          * @param {Function} fn        The method the event invokes
6258          * @param {Object}   scope    An object that becomes the scope of the handler
6259          * @param {boolean}  override If true, the obj passed in becomes
6260          *                             the execution scope of the listener
6261          * @return {Function} The wrapped function
6262          * @deprecated
6263          */
6264         wrap : function(fn, scope, override){
6265             return function(e){
6266                 Roo.EventObject.setEvent(e);
6267                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6268             };
6269         },
6270         
6271         /**
6272      * Appends an event handler to an element (shorthand for addListener)
6273      * @param {String/HTMLElement}   element        The html element or id to assign the
6274      * @param {String}   eventName The type of event to listen for
6275      * @param {Function} handler The method the event invokes
6276      * @param {Object}   scope (optional) The scope in which to execute the handler
6277      * function. The handler function's "this" context.
6278      * @param {Object}   options (optional) An object containing handler configuration
6279      * properties. This may contain any of the following properties:<ul>
6280      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6281      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6282      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6283      * <li>preventDefault {Boolean} True to prevent the default action</li>
6284      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6285      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6286      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6287      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6288      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6289      * by the specified number of milliseconds. If the event fires again within that time, the original
6290      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6291      * </ul><br>
6292      * <p>
6293      * <b>Combining Options</b><br>
6294      * Using the options argument, it is possible to combine different types of listeners:<br>
6295      * <br>
6296      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6297      * Code:<pre><code>
6298 el.on('click', this.onClick, this, {
6299     single: true,
6300     delay: 100,
6301     stopEvent : true,
6302     forumId: 4
6303 });</code></pre>
6304      * <p>
6305      * <b>Attaching multiple handlers in 1 call</b><br>
6306       * The method also allows for a single argument to be passed which is a config object containing properties
6307      * which specify multiple handlers.
6308      * <p>
6309      * Code:<pre><code>
6310 el.on({
6311     'click' : {
6312         fn: this.onClick
6313         scope: this,
6314         delay: 100
6315     },
6316     'mouseover' : {
6317         fn: this.onMouseOver
6318         scope: this
6319     },
6320     'mouseout' : {
6321         fn: this.onMouseOut
6322         scope: this
6323     }
6324 });</code></pre>
6325      * <p>
6326      * Or a shorthand syntax:<br>
6327      * Code:<pre><code>
6328 el.on({
6329     'click' : this.onClick,
6330     'mouseover' : this.onMouseOver,
6331     'mouseout' : this.onMouseOut
6332     scope: this
6333 });</code></pre>
6334      */
6335         addListener : function(element, eventName, fn, scope, options){
6336             if(typeof eventName == "object"){
6337                 var o = eventName;
6338                 for(var e in o){
6339                     if(propRe.test(e)){
6340                         continue;
6341                     }
6342                     if(typeof o[e] == "function"){
6343                         // shared options
6344                         listen(element, e, o, o[e], o.scope);
6345                     }else{
6346                         // individual options
6347                         listen(element, e, o[e]);
6348                     }
6349                 }
6350                 return;
6351             }
6352             return listen(element, eventName, options, fn, scope);
6353         },
6354         
6355         /**
6356          * Removes an event handler
6357          *
6358          * @param {String/HTMLElement}   element        The id or html element to remove the 
6359          *                             event from
6360          * @param {String}   eventName     The type of event
6361          * @param {Function} fn
6362          * @return {Boolean} True if a listener was actually removed
6363          */
6364         removeListener : function(element, eventName, fn){
6365             return stopListening(element, eventName, fn);
6366         },
6367         
6368         /**
6369          * Fires when the document is ready (before onload and before images are loaded). Can be 
6370          * accessed shorthanded Roo.onReady().
6371          * @param {Function} fn        The method the event invokes
6372          * @param {Object}   scope    An  object that becomes the scope of the handler
6373          * @param {boolean}  options
6374          */
6375         onDocumentReady : function(fn, scope, options){
6376             if(docReadyState){ // if it already fired
6377                 docReadyEvent.addListener(fn, scope, options);
6378                 docReadyEvent.fire();
6379                 docReadyEvent.clearListeners();
6380                 return;
6381             }
6382             if(!docReadyEvent){
6383                 initDocReady();
6384             }
6385             docReadyEvent.addListener(fn, scope, options);
6386         },
6387         
6388         /**
6389          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6390          * @param {Function} fn        The method the event invokes
6391          * @param {Object}   scope    An object that becomes the scope of the handler
6392          * @param {boolean}  options
6393          */
6394         onWindowResize : function(fn, scope, options){
6395             if(!resizeEvent){
6396                 resizeEvent = new Roo.util.Event();
6397                 resizeTask = new Roo.util.DelayedTask(function(){
6398                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6399                 });
6400                 E.on(window, "resize", function(){
6401                     if(Roo.isIE){
6402                         resizeTask.delay(50);
6403                     }else{
6404                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6405                     }
6406                 });
6407             }
6408             resizeEvent.addListener(fn, scope, options);
6409         },
6410
6411         /**
6412          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6413          * @param {Function} fn        The method the event invokes
6414          * @param {Object}   scope    An object that becomes the scope of the handler
6415          * @param {boolean}  options
6416          */
6417         onTextResize : function(fn, scope, options){
6418             if(!textEvent){
6419                 textEvent = new Roo.util.Event();
6420                 var textEl = new Roo.Element(document.createElement('div'));
6421                 textEl.dom.className = 'x-text-resize';
6422                 textEl.dom.innerHTML = 'X';
6423                 textEl.appendTo(document.body);
6424                 textSize = textEl.dom.offsetHeight;
6425                 setInterval(function(){
6426                     if(textEl.dom.offsetHeight != textSize){
6427                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6428                     }
6429                 }, this.textResizeInterval);
6430             }
6431             textEvent.addListener(fn, scope, options);
6432         },
6433
6434         /**
6435          * Removes the passed window resize listener.
6436          * @param {Function} fn        The method the event invokes
6437          * @param {Object}   scope    The scope of handler
6438          */
6439         removeResizeListener : function(fn, scope){
6440             if(resizeEvent){
6441                 resizeEvent.removeListener(fn, scope);
6442             }
6443         },
6444
6445         // private
6446         fireResize : function(){
6447             if(resizeEvent){
6448                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6449             }   
6450         },
6451         /**
6452          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6453          */
6454         ieDeferSrc : false,
6455         /**
6456          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6457          */
6458         textResizeInterval : 50
6459     };
6460     
6461     /**
6462      * Fix for doc tools
6463      * @scopeAlias pub=Roo.EventManager
6464      */
6465     
6466      /**
6467      * Appends an event handler to an element (shorthand for addListener)
6468      * @param {String/HTMLElement}   element        The html element or id to assign the
6469      * @param {String}   eventName The type of event to listen for
6470      * @param {Function} handler The method the event invokes
6471      * @param {Object}   scope (optional) The scope in which to execute the handler
6472      * function. The handler function's "this" context.
6473      * @param {Object}   options (optional) An object containing handler configuration
6474      * properties. This may contain any of the following properties:<ul>
6475      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6476      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6477      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6478      * <li>preventDefault {Boolean} True to prevent the default action</li>
6479      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6480      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6481      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6482      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6483      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6484      * by the specified number of milliseconds. If the event fires again within that time, the original
6485      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6486      * </ul><br>
6487      * <p>
6488      * <b>Combining Options</b><br>
6489      * Using the options argument, it is possible to combine different types of listeners:<br>
6490      * <br>
6491      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6492      * Code:<pre><code>
6493 el.on('click', this.onClick, this, {
6494     single: true,
6495     delay: 100,
6496     stopEvent : true,
6497     forumId: 4
6498 });</code></pre>
6499      * <p>
6500      * <b>Attaching multiple handlers in 1 call</b><br>
6501       * The method also allows for a single argument to be passed which is a config object containing properties
6502      * which specify multiple handlers.
6503      * <p>
6504      * Code:<pre><code>
6505 el.on({
6506     'click' : {
6507         fn: this.onClick
6508         scope: this,
6509         delay: 100
6510     },
6511     'mouseover' : {
6512         fn: this.onMouseOver
6513         scope: this
6514     },
6515     'mouseout' : {
6516         fn: this.onMouseOut
6517         scope: this
6518     }
6519 });</code></pre>
6520      * <p>
6521      * Or a shorthand syntax:<br>
6522      * Code:<pre><code>
6523 el.on({
6524     'click' : this.onClick,
6525     'mouseover' : this.onMouseOver,
6526     'mouseout' : this.onMouseOut
6527     scope: this
6528 });</code></pre>
6529      */
6530     pub.on = pub.addListener;
6531     pub.un = pub.removeListener;
6532
6533     pub.stoppedMouseDownEvent = new Roo.util.Event();
6534     return pub;
6535 }();
6536 /**
6537   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6538   * @param {Function} fn        The method the event invokes
6539   * @param {Object}   scope    An  object that becomes the scope of the handler
6540   * @param {boolean}  override If true, the obj passed in becomes
6541   *                             the execution scope of the listener
6542   * @member Roo
6543   * @method onReady
6544  */
6545 Roo.onReady = Roo.EventManager.onDocumentReady;
6546
6547 Roo.onReady(function(){
6548     var bd = Roo.get(document.body);
6549     if(!bd){ return; }
6550
6551     var cls = [
6552             Roo.isIE ? "roo-ie"
6553             : Roo.isGecko ? "roo-gecko"
6554             : Roo.isOpera ? "roo-opera"
6555             : Roo.isSafari ? "roo-safari" : ""];
6556
6557     if(Roo.isMac){
6558         cls.push("roo-mac");
6559     }
6560     if(Roo.isLinux){
6561         cls.push("roo-linux");
6562     }
6563     if(Roo.isBorderBox){
6564         cls.push('roo-border-box');
6565     }
6566     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6567         var p = bd.dom.parentNode;
6568         if(p){
6569             p.className += ' roo-strict';
6570         }
6571     }
6572     bd.addClass(cls.join(' '));
6573 });
6574
6575 /**
6576  * @class Roo.EventObject
6577  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6578  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6579  * Example:
6580  * <pre><code>
6581  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6582     e.preventDefault();
6583     var target = e.getTarget();
6584     ...
6585  }
6586  var myDiv = Roo.get("myDiv");
6587  myDiv.on("click", handleClick);
6588  //or
6589  Roo.EventManager.on("myDiv", 'click', handleClick);
6590  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6591  </code></pre>
6592  * @singleton
6593  */
6594 Roo.EventObject = function(){
6595     
6596     var E = Roo.lib.Event;
6597     
6598     // safari keypress events for special keys return bad keycodes
6599     var safariKeys = {
6600         63234 : 37, // left
6601         63235 : 39, // right
6602         63232 : 38, // up
6603         63233 : 40, // down
6604         63276 : 33, // page up
6605         63277 : 34, // page down
6606         63272 : 46, // delete
6607         63273 : 36, // home
6608         63275 : 35  // end
6609     };
6610
6611     // normalize button clicks
6612     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6613                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6614
6615     Roo.EventObjectImpl = function(e){
6616         if(e){
6617             this.setEvent(e.browserEvent || e);
6618         }
6619     };
6620     Roo.EventObjectImpl.prototype = {
6621         /**
6622          * Used to fix doc tools.
6623          * @scope Roo.EventObject.prototype
6624          */
6625             
6626
6627         
6628         
6629         /** The normal browser event */
6630         browserEvent : null,
6631         /** The button pressed in a mouse event */
6632         button : -1,
6633         /** True if the shift key was down during the event */
6634         shiftKey : false,
6635         /** True if the control key was down during the event */
6636         ctrlKey : false,
6637         /** True if the alt key was down during the event */
6638         altKey : false,
6639
6640         /** Key constant 
6641         * @type Number */
6642         BACKSPACE : 8,
6643         /** Key constant 
6644         * @type Number */
6645         TAB : 9,
6646         /** Key constant 
6647         * @type Number */
6648         RETURN : 13,
6649         /** Key constant 
6650         * @type Number */
6651         ENTER : 13,
6652         /** Key constant 
6653         * @type Number */
6654         SHIFT : 16,
6655         /** Key constant 
6656         * @type Number */
6657         CONTROL : 17,
6658         /** Key constant 
6659         * @type Number */
6660         ESC : 27,
6661         /** Key constant 
6662         * @type Number */
6663         SPACE : 32,
6664         /** Key constant 
6665         * @type Number */
6666         PAGEUP : 33,
6667         /** Key constant 
6668         * @type Number */
6669         PAGEDOWN : 34,
6670         /** Key constant 
6671         * @type Number */
6672         END : 35,
6673         /** Key constant 
6674         * @type Number */
6675         HOME : 36,
6676         /** Key constant 
6677         * @type Number */
6678         LEFT : 37,
6679         /** Key constant 
6680         * @type Number */
6681         UP : 38,
6682         /** Key constant 
6683         * @type Number */
6684         RIGHT : 39,
6685         /** Key constant 
6686         * @type Number */
6687         DOWN : 40,
6688         /** Key constant 
6689         * @type Number */
6690         DELETE : 46,
6691         /** Key constant 
6692         * @type Number */
6693         F5 : 116,
6694
6695            /** @private */
6696         setEvent : function(e){
6697             if(e == this || (e && e.browserEvent)){ // already wrapped
6698                 return e;
6699             }
6700             this.browserEvent = e;
6701             if(e){
6702                 // normalize buttons
6703                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6704                 if(e.type == 'click' && this.button == -1){
6705                     this.button = 0;
6706                 }
6707                 this.type = e.type;
6708                 this.shiftKey = e.shiftKey;
6709                 // mac metaKey behaves like ctrlKey
6710                 this.ctrlKey = e.ctrlKey || e.metaKey;
6711                 this.altKey = e.altKey;
6712                 // in getKey these will be normalized for the mac
6713                 this.keyCode = e.keyCode;
6714                 // keyup warnings on firefox.
6715                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6716                 // cache the target for the delayed and or buffered events
6717                 this.target = E.getTarget(e);
6718                 // same for XY
6719                 this.xy = E.getXY(e);
6720             }else{
6721                 this.button = -1;
6722                 this.shiftKey = false;
6723                 this.ctrlKey = false;
6724                 this.altKey = false;
6725                 this.keyCode = 0;
6726                 this.charCode =0;
6727                 this.target = null;
6728                 this.xy = [0, 0];
6729             }
6730             return this;
6731         },
6732
6733         /**
6734          * Stop the event (preventDefault and stopPropagation)
6735          */
6736         stopEvent : function(){
6737             if(this.browserEvent){
6738                 if(this.browserEvent.type == 'mousedown'){
6739                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6740                 }
6741                 E.stopEvent(this.browserEvent);
6742             }
6743         },
6744
6745         /**
6746          * Prevents the browsers default handling of the event.
6747          */
6748         preventDefault : function(){
6749             if(this.browserEvent){
6750                 E.preventDefault(this.browserEvent);
6751             }
6752         },
6753
6754         /** @private */
6755         isNavKeyPress : function(){
6756             var k = this.keyCode;
6757             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6758             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6759         },
6760
6761         isSpecialKey : function(){
6762             var k = this.keyCode;
6763             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6764             (k == 16) || (k == 17) ||
6765             (k >= 18 && k <= 20) ||
6766             (k >= 33 && k <= 35) ||
6767             (k >= 36 && k <= 39) ||
6768             (k >= 44 && k <= 45);
6769         },
6770         /**
6771          * Cancels bubbling of the event.
6772          */
6773         stopPropagation : function(){
6774             if(this.browserEvent){
6775                 if(this.type == 'mousedown'){
6776                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6777                 }
6778                 E.stopPropagation(this.browserEvent);
6779             }
6780         },
6781
6782         /**
6783          * Gets the key code for the event.
6784          * @return {Number}
6785          */
6786         getCharCode : function(){
6787             return this.charCode || this.keyCode;
6788         },
6789
6790         /**
6791          * Returns a normalized keyCode for the event.
6792          * @return {Number} The key code
6793          */
6794         getKey : function(){
6795             var k = this.keyCode || this.charCode;
6796             return Roo.isSafari ? (safariKeys[k] || k) : k;
6797         },
6798
6799         /**
6800          * Gets the x coordinate of the event.
6801          * @return {Number}
6802          */
6803         getPageX : function(){
6804             return this.xy[0];
6805         },
6806
6807         /**
6808          * Gets the y coordinate of the event.
6809          * @return {Number}
6810          */
6811         getPageY : function(){
6812             return this.xy[1];
6813         },
6814
6815         /**
6816          * Gets the time of the event.
6817          * @return {Number}
6818          */
6819         getTime : function(){
6820             if(this.browserEvent){
6821                 return E.getTime(this.browserEvent);
6822             }
6823             return null;
6824         },
6825
6826         /**
6827          * Gets the page coordinates of the event.
6828          * @return {Array} The xy values like [x, y]
6829          */
6830         getXY : function(){
6831             return this.xy;
6832         },
6833
6834         /**
6835          * Gets the target for the event.
6836          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6837          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6838                 search as a number or element (defaults to 10 || document.body)
6839          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6840          * @return {HTMLelement}
6841          */
6842         getTarget : function(selector, maxDepth, returnEl){
6843             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6844         },
6845         /**
6846          * Gets the related target.
6847          * @return {HTMLElement}
6848          */
6849         getRelatedTarget : function(){
6850             if(this.browserEvent){
6851                 return E.getRelatedTarget(this.browserEvent);
6852             }
6853             return null;
6854         },
6855
6856         /**
6857          * Normalizes mouse wheel delta across browsers
6858          * @return {Number} The delta
6859          */
6860         getWheelDelta : function(){
6861             var e = this.browserEvent;
6862             var delta = 0;
6863             if(e.wheelDelta){ /* IE/Opera. */
6864                 delta = e.wheelDelta/120;
6865             }else if(e.detail){ /* Mozilla case. */
6866                 delta = -e.detail/3;
6867             }
6868             return delta;
6869         },
6870
6871         /**
6872          * Returns true if the control, meta, shift or alt key was pressed during this event.
6873          * @return {Boolean}
6874          */
6875         hasModifier : function(){
6876             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6877         },
6878
6879         /**
6880          * Returns true if the target of this event equals el or is a child of el
6881          * @param {String/HTMLElement/Element} el
6882          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6883          * @return {Boolean}
6884          */
6885         within : function(el, related){
6886             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6887             return t && Roo.fly(el).contains(t);
6888         },
6889
6890         getPoint : function(){
6891             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6892         }
6893     };
6894
6895     return new Roo.EventObjectImpl();
6896 }();
6897             
6898     /*
6899  * Based on:
6900  * Ext JS Library 1.1.1
6901  * Copyright(c) 2006-2007, Ext JS, LLC.
6902  *
6903  * Originally Released Under LGPL - original licence link has changed is not relivant.
6904  *
6905  * Fork - LGPL
6906  * <script type="text/javascript">
6907  */
6908
6909  
6910 // was in Composite Element!??!?!
6911  
6912 (function(){
6913     var D = Roo.lib.Dom;
6914     var E = Roo.lib.Event;
6915     var A = Roo.lib.Anim;
6916
6917     // local style camelizing for speed
6918     var propCache = {};
6919     var camelRe = /(-[a-z])/gi;
6920     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6921     var view = document.defaultView;
6922
6923 /**
6924  * @class Roo.Element
6925  * Represents an Element in the DOM.<br><br>
6926  * Usage:<br>
6927 <pre><code>
6928 var el = Roo.get("my-div");
6929
6930 // or with getEl
6931 var el = getEl("my-div");
6932
6933 // or with a DOM element
6934 var el = Roo.get(myDivElement);
6935 </code></pre>
6936  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6937  * each call instead of constructing a new one.<br><br>
6938  * <b>Animations</b><br />
6939  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6940  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6941 <pre>
6942 Option    Default   Description
6943 --------- --------  ---------------------------------------------
6944 duration  .35       The duration of the animation in seconds
6945 easing    easeOut   The YUI easing method
6946 callback  none      A function to execute when the anim completes
6947 scope     this      The scope (this) of the callback function
6948 </pre>
6949 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6950 * manipulate the animation. Here's an example:
6951 <pre><code>
6952 var el = Roo.get("my-div");
6953
6954 // no animation
6955 el.setWidth(100);
6956
6957 // default animation
6958 el.setWidth(100, true);
6959
6960 // animation with some options set
6961 el.setWidth(100, {
6962     duration: 1,
6963     callback: this.foo,
6964     scope: this
6965 });
6966
6967 // using the "anim" property to get the Anim object
6968 var opt = {
6969     duration: 1,
6970     callback: this.foo,
6971     scope: this
6972 };
6973 el.setWidth(100, opt);
6974 ...
6975 if(opt.anim.isAnimated()){
6976     opt.anim.stop();
6977 }
6978 </code></pre>
6979 * <b> Composite (Collections of) Elements</b><br />
6980  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6981  * @constructor Create a new Element directly.
6982  * @param {String/HTMLElement} element
6983  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6984  */
6985     Roo.Element = function(element, forceNew){
6986         var dom = typeof element == "string" ?
6987                 document.getElementById(element) : element;
6988         if(!dom){ // invalid id/element
6989             return null;
6990         }
6991         var id = dom.id;
6992         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6993             return Roo.Element.cache[id];
6994         }
6995
6996         /**
6997          * The DOM element
6998          * @type HTMLElement
6999          */
7000         this.dom = dom;
7001
7002         /**
7003          * The DOM element ID
7004          * @type String
7005          */
7006         this.id = id || Roo.id(dom);
7007     };
7008
7009     var El = Roo.Element;
7010
7011     El.prototype = {
7012         /**
7013          * The element's default display mode  (defaults to "")
7014          * @type String
7015          */
7016         originalDisplay : "",
7017
7018         visibilityMode : 1,
7019         /**
7020          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7021          * @type String
7022          */
7023         defaultUnit : "px",
7024         /**
7025          * Sets the element's visibility mode. When setVisible() is called it
7026          * will use this to determine whether to set the visibility or the display property.
7027          * @param visMode Element.VISIBILITY or Element.DISPLAY
7028          * @return {Roo.Element} this
7029          */
7030         setVisibilityMode : function(visMode){
7031             this.visibilityMode = visMode;
7032             return this;
7033         },
7034         /**
7035          * Convenience method for setVisibilityMode(Element.DISPLAY)
7036          * @param {String} display (optional) What to set display to when visible
7037          * @return {Roo.Element} this
7038          */
7039         enableDisplayMode : function(display){
7040             this.setVisibilityMode(El.DISPLAY);
7041             if(typeof display != "undefined") this.originalDisplay = display;
7042             return this;
7043         },
7044
7045         /**
7046          * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7047          * @param {String} selector The simple selector to test
7048          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049                 search as a number or element (defaults to 10 || document.body)
7050          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7051          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7052          */
7053         findParent : function(simpleSelector, maxDepth, returnEl){
7054             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7055             maxDepth = maxDepth || 50;
7056             if(typeof maxDepth != "number"){
7057                 stopEl = Roo.getDom(maxDepth);
7058                 maxDepth = 10;
7059             }
7060             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7061                 if(dq.is(p, simpleSelector)){
7062                     return returnEl ? Roo.get(p) : p;
7063                 }
7064                 depth++;
7065                 p = p.parentNode;
7066             }
7067             return null;
7068         },
7069
7070
7071         /**
7072          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7073          * @param {String} selector The simple selector to test
7074          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7075                 search as a number or element (defaults to 10 || document.body)
7076          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7077          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7078          */
7079         findParentNode : function(simpleSelector, maxDepth, returnEl){
7080             var p = Roo.fly(this.dom.parentNode, '_internal');
7081             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7082         },
7083
7084         /**
7085          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7086          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7087          * @param {String} selector The simple selector to test
7088          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7089                 search as a number or element (defaults to 10 || document.body)
7090          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7091          */
7092         up : function(simpleSelector, maxDepth){
7093             return this.findParentNode(simpleSelector, maxDepth, true);
7094         },
7095
7096
7097
7098         /**
7099          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7100          * @param {String} selector The simple selector to test
7101          * @return {Boolean} True if this element matches the selector, else false
7102          */
7103         is : function(simpleSelector){
7104             return Roo.DomQuery.is(this.dom, simpleSelector);
7105         },
7106
7107         /**
7108          * Perform animation on this element.
7109          * @param {Object} args The YUI animation control args
7110          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7111          * @param {Function} onComplete (optional) Function to call when animation completes
7112          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7113          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7114          * @return {Roo.Element} this
7115          */
7116         animate : function(args, duration, onComplete, easing, animType){
7117             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7118             return this;
7119         },
7120
7121         /*
7122          * @private Internal animation call
7123          */
7124         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7125             animType = animType || 'run';
7126             opt = opt || {};
7127             var anim = Roo.lib.Anim[animType](
7128                 this.dom, args,
7129                 (opt.duration || defaultDur) || .35,
7130                 (opt.easing || defaultEase) || 'easeOut',
7131                 function(){
7132                     Roo.callback(cb, this);
7133                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7134                 },
7135                 this
7136             );
7137             opt.anim = anim;
7138             return anim;
7139         },
7140
7141         // private legacy anim prep
7142         preanim : function(a, i){
7143             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7144         },
7145
7146         /**
7147          * Removes worthless text nodes
7148          * @param {Boolean} forceReclean (optional) By default the element
7149          * keeps track if it has been cleaned already so
7150          * you can call this over and over. However, if you update the element and
7151          * need to force a reclean, you can pass true.
7152          */
7153         clean : function(forceReclean){
7154             if(this.isCleaned && forceReclean !== true){
7155                 return this;
7156             }
7157             var ns = /\S/;
7158             var d = this.dom, n = d.firstChild, ni = -1;
7159             while(n){
7160                 var nx = n.nextSibling;
7161                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7162                     d.removeChild(n);
7163                 }else{
7164                     n.nodeIndex = ++ni;
7165                 }
7166                 n = nx;
7167             }
7168             this.isCleaned = true;
7169             return this;
7170         },
7171
7172         // private
7173         calcOffsetsTo : function(el){
7174             el = Roo.get(el);
7175             var d = el.dom;
7176             var restorePos = false;
7177             if(el.getStyle('position') == 'static'){
7178                 el.position('relative');
7179                 restorePos = true;
7180             }
7181             var x = 0, y =0;
7182             var op = this.dom;
7183             while(op && op != d && op.tagName != 'HTML'){
7184                 x+= op.offsetLeft;
7185                 y+= op.offsetTop;
7186                 op = op.offsetParent;
7187             }
7188             if(restorePos){
7189                 el.position('static');
7190             }
7191             return [x, y];
7192         },
7193
7194         /**
7195          * Scrolls this element into view within the passed container.
7196          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7197          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7198          * @return {Roo.Element} this
7199          */
7200         scrollIntoView : function(container, hscroll){
7201             var c = Roo.getDom(container) || document.body;
7202             var el = this.dom;
7203
7204             var o = this.calcOffsetsTo(c),
7205                 l = o[0],
7206                 t = o[1],
7207                 b = t+el.offsetHeight,
7208                 r = l+el.offsetWidth;
7209
7210             var ch = c.clientHeight;
7211             var ct = parseInt(c.scrollTop, 10);
7212             var cl = parseInt(c.scrollLeft, 10);
7213             var cb = ct + ch;
7214             var cr = cl + c.clientWidth;
7215
7216             if(t < ct){
7217                 c.scrollTop = t;
7218             }else if(b > cb){
7219                 c.scrollTop = b-ch;
7220             }
7221
7222             if(hscroll !== false){
7223                 if(l < cl){
7224                     c.scrollLeft = l;
7225                 }else if(r > cr){
7226                     c.scrollLeft = r-c.clientWidth;
7227                 }
7228             }
7229             return this;
7230         },
7231
7232         // private
7233         scrollChildIntoView : function(child, hscroll){
7234             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7235         },
7236
7237         /**
7238          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7239          * the new height may not be available immediately.
7240          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7241          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7242          * @param {Function} onComplete (optional) Function to call when animation completes
7243          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7244          * @return {Roo.Element} this
7245          */
7246         autoHeight : function(animate, duration, onComplete, easing){
7247             var oldHeight = this.getHeight();
7248             this.clip();
7249             this.setHeight(1); // force clipping
7250             setTimeout(function(){
7251                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7252                 if(!animate){
7253                     this.setHeight(height);
7254                     this.unclip();
7255                     if(typeof onComplete == "function"){
7256                         onComplete();
7257                     }
7258                 }else{
7259                     this.setHeight(oldHeight); // restore original height
7260                     this.setHeight(height, animate, duration, function(){
7261                         this.unclip();
7262                         if(typeof onComplete == "function") onComplete();
7263                     }.createDelegate(this), easing);
7264                 }
7265             }.createDelegate(this), 0);
7266             return this;
7267         },
7268
7269         /**
7270          * Returns true if this element is an ancestor of the passed element
7271          * @param {HTMLElement/String} el The element to check
7272          * @return {Boolean} True if this element is an ancestor of el, else false
7273          */
7274         contains : function(el){
7275             if(!el){return false;}
7276             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7277         },
7278
7279         /**
7280          * Checks whether the element is currently visible using both visibility and display properties.
7281          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7282          * @return {Boolean} True if the element is currently visible, else false
7283          */
7284         isVisible : function(deep) {
7285             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7286             if(deep !== true || !vis){
7287                 return vis;
7288             }
7289             var p = this.dom.parentNode;
7290             while(p && p.tagName.toLowerCase() != "body"){
7291                 if(!Roo.fly(p, '_isVisible').isVisible()){
7292                     return false;
7293                 }
7294                 p = p.parentNode;
7295             }
7296             return true;
7297         },
7298
7299         /**
7300          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7301          * @param {String} selector The CSS selector
7302          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7303          * @return {CompositeElement/CompositeElementLite} The composite element
7304          */
7305         select : function(selector, unique){
7306             return El.select(selector, unique, this.dom);
7307         },
7308
7309         /**
7310          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7311          * @param {String} selector The CSS selector
7312          * @return {Array} An array of the matched nodes
7313          */
7314         query : function(selector, unique){
7315             return Roo.DomQuery.select(selector, this.dom);
7316         },
7317
7318         /**
7319          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7320          * @param {String} selector The CSS selector
7321          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7322          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7323          */
7324         child : function(selector, returnDom){
7325             var n = Roo.DomQuery.selectNode(selector, this.dom);
7326             return returnDom ? n : Roo.get(n);
7327         },
7328
7329         /**
7330          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7331          * @param {String} selector The CSS selector
7332          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7333          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7334          */
7335         down : function(selector, returnDom){
7336             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7337             return returnDom ? n : Roo.get(n);
7338         },
7339
7340         /**
7341          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7342          * @param {String} group The group the DD object is member of
7343          * @param {Object} config The DD config object
7344          * @param {Object} overrides An object containing methods to override/implement on the DD object
7345          * @return {Roo.dd.DD} The DD object
7346          */
7347         initDD : function(group, config, overrides){
7348             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7349             return Roo.apply(dd, overrides);
7350         },
7351
7352         /**
7353          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7354          * @param {String} group The group the DDProxy object is member of
7355          * @param {Object} config The DDProxy config object
7356          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7357          * @return {Roo.dd.DDProxy} The DDProxy object
7358          */
7359         initDDProxy : function(group, config, overrides){
7360             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7361             return Roo.apply(dd, overrides);
7362         },
7363
7364         /**
7365          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7366          * @param {String} group The group the DDTarget object is member of
7367          * @param {Object} config The DDTarget config object
7368          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7369          * @return {Roo.dd.DDTarget} The DDTarget object
7370          */
7371         initDDTarget : function(group, config, overrides){
7372             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7373             return Roo.apply(dd, overrides);
7374         },
7375
7376         /**
7377          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7378          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7379          * @param {Boolean} visible Whether the element is visible
7380          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7381          * @return {Roo.Element} this
7382          */
7383          setVisible : function(visible, animate){
7384             if(!animate || !A){
7385                 if(this.visibilityMode == El.DISPLAY){
7386                     this.setDisplayed(visible);
7387                 }else{
7388                     this.fixDisplay();
7389                     this.dom.style.visibility = visible ? "visible" : "hidden";
7390                 }
7391             }else{
7392                 // closure for composites
7393                 var dom = this.dom;
7394                 var visMode = this.visibilityMode;
7395                 if(visible){
7396                     this.setOpacity(.01);
7397                     this.setVisible(true);
7398                 }
7399                 this.anim({opacity: { to: (visible?1:0) }},
7400                       this.preanim(arguments, 1),
7401                       null, .35, 'easeIn', function(){
7402                          if(!visible){
7403                              if(visMode == El.DISPLAY){
7404                                  dom.style.display = "none";
7405                              }else{
7406                                  dom.style.visibility = "hidden";
7407                              }
7408                              Roo.get(dom).setOpacity(1);
7409                          }
7410                      });
7411             }
7412             return this;
7413         },
7414
7415         /**
7416          * Returns true if display is not "none"
7417          * @return {Boolean}
7418          */
7419         isDisplayed : function() {
7420             return this.getStyle("display") != "none";
7421         },
7422
7423         /**
7424          * Toggles the element's visibility or display, depending on visibility mode.
7425          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7426          * @return {Roo.Element} this
7427          */
7428         toggle : function(animate){
7429             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7430             return this;
7431         },
7432
7433         /**
7434          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7435          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7436          * @return {Roo.Element} this
7437          */
7438         setDisplayed : function(value) {
7439             if(typeof value == "boolean"){
7440                value = value ? this.originalDisplay : "none";
7441             }
7442             this.setStyle("display", value);
7443             return this;
7444         },
7445
7446         /**
7447          * Tries to focus the element. Any exceptions are caught and ignored.
7448          * @return {Roo.Element} this
7449          */
7450         focus : function() {
7451             try{
7452                 this.dom.focus();
7453             }catch(e){}
7454             return this;
7455         },
7456
7457         /**
7458          * Tries to blur the element. Any exceptions are caught and ignored.
7459          * @return {Roo.Element} this
7460          */
7461         blur : function() {
7462             try{
7463                 this.dom.blur();
7464             }catch(e){}
7465             return this;
7466         },
7467
7468         /**
7469          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7470          * @param {String/Array} className The CSS class to add, or an array of classes
7471          * @return {Roo.Element} this
7472          */
7473         addClass : function(className){
7474             if(className instanceof Array){
7475                 for(var i = 0, len = className.length; i < len; i++) {
7476                     this.addClass(className[i]);
7477                 }
7478             }else{
7479                 if(className && !this.hasClass(className)){
7480                     this.dom.className = this.dom.className + " " + className;
7481                 }
7482             }
7483             return this;
7484         },
7485
7486         /**
7487          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7488          * @param {String/Array} className The CSS class to add, or an array of classes
7489          * @return {Roo.Element} this
7490          */
7491         radioClass : function(className){
7492             var siblings = this.dom.parentNode.childNodes;
7493             for(var i = 0; i < siblings.length; i++) {
7494                 var s = siblings[i];
7495                 if(s.nodeType == 1){
7496                     Roo.get(s).removeClass(className);
7497                 }
7498             }
7499             this.addClass(className);
7500             return this;
7501         },
7502
7503         /**
7504          * Removes one or more CSS classes from the element.
7505          * @param {String/Array} className The CSS class to remove, or an array of classes
7506          * @return {Roo.Element} this
7507          */
7508         removeClass : function(className){
7509             if(!className || !this.dom.className){
7510                 return this;
7511             }
7512             if(className instanceof Array){
7513                 for(var i = 0, len = className.length; i < len; i++) {
7514                     this.removeClass(className[i]);
7515                 }
7516             }else{
7517                 if(this.hasClass(className)){
7518                     var re = this.classReCache[className];
7519                     if (!re) {
7520                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7521                        this.classReCache[className] = re;
7522                     }
7523                     this.dom.className =
7524                         this.dom.className.replace(re, " ");
7525                 }
7526             }
7527             return this;
7528         },
7529
7530         // private
7531         classReCache: {},
7532
7533         /**
7534          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7535          * @param {String} className The CSS class to toggle
7536          * @return {Roo.Element} this
7537          */
7538         toggleClass : function(className){
7539             if(this.hasClass(className)){
7540                 this.removeClass(className);
7541             }else{
7542                 this.addClass(className);
7543             }
7544             return this;
7545         },
7546
7547         /**
7548          * Checks if the specified CSS class exists on this element's DOM node.
7549          * @param {String} className The CSS class to check for
7550          * @return {Boolean} True if the class exists, else false
7551          */
7552         hasClass : function(className){
7553             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7554         },
7555
7556         /**
7557          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7558          * @param {String} oldClassName The CSS class to replace
7559          * @param {String} newClassName The replacement CSS class
7560          * @return {Roo.Element} this
7561          */
7562         replaceClass : function(oldClassName, newClassName){
7563             this.removeClass(oldClassName);
7564             this.addClass(newClassName);
7565             return this;
7566         },
7567
7568         /**
7569          * Returns an object with properties matching the styles requested.
7570          * For example, el.getStyles('color', 'font-size', 'width') might return
7571          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7572          * @param {String} style1 A style name
7573          * @param {String} style2 A style name
7574          * @param {String} etc.
7575          * @return {Object} The style object
7576          */
7577         getStyles : function(){
7578             var a = arguments, len = a.length, r = {};
7579             for(var i = 0; i < len; i++){
7580                 r[a[i]] = this.getStyle(a[i]);
7581             }
7582             return r;
7583         },
7584
7585         /**
7586          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7587          * @param {String} property The style property whose value is returned.
7588          * @return {String} The current value of the style property for this element.
7589          */
7590         getStyle : function(){
7591             return view && view.getComputedStyle ?
7592                 function(prop){
7593                     var el = this.dom, v, cs, camel;
7594                     if(prop == 'float'){
7595                         prop = "cssFloat";
7596                     }
7597                     if(el.style && (v = el.style[prop])){
7598                         return v;
7599                     }
7600                     if(cs = view.getComputedStyle(el, "")){
7601                         if(!(camel = propCache[prop])){
7602                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7603                         }
7604                         return cs[camel];
7605                     }
7606                     return null;
7607                 } :
7608                 function(prop){
7609                     var el = this.dom, v, cs, camel;
7610                     if(prop == 'opacity'){
7611                         if(typeof el.style.filter == 'string'){
7612                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7613                             if(m){
7614                                 var fv = parseFloat(m[1]);
7615                                 if(!isNaN(fv)){
7616                                     return fv ? fv / 100 : 0;
7617                                 }
7618                             }
7619                         }
7620                         return 1;
7621                     }else if(prop == 'float'){
7622                         prop = "styleFloat";
7623                     }
7624                     if(!(camel = propCache[prop])){
7625                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7626                     }
7627                     if(v = el.style[camel]){
7628                         return v;
7629                     }
7630                     if(cs = el.currentStyle){
7631                         return cs[camel];
7632                     }
7633                     return null;
7634                 };
7635         }(),
7636
7637         /**
7638          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7639          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7640          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7641          * @return {Roo.Element} this
7642          */
7643         setStyle : function(prop, value){
7644             if(typeof prop == "string"){
7645                 
7646                 if (prop == 'float') {
7647                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7648                     return this;
7649                 }
7650                 
7651                 var camel;
7652                 if(!(camel = propCache[prop])){
7653                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7654                 }
7655                 
7656                 if(camel == 'opacity') {
7657                     this.setOpacity(value);
7658                 }else{
7659                     this.dom.style[camel] = value;
7660                 }
7661             }else{
7662                 for(var style in prop){
7663                     if(typeof prop[style] != "function"){
7664                        this.setStyle(style, prop[style]);
7665                     }
7666                 }
7667             }
7668             return this;
7669         },
7670
7671         /**
7672          * More flexible version of {@link #setStyle} for setting style properties.
7673          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7674          * a function which returns such a specification.
7675          * @return {Roo.Element} this
7676          */
7677         applyStyles : function(style){
7678             Roo.DomHelper.applyStyles(this.dom, style);
7679             return this;
7680         },
7681
7682         /**
7683           * Gets the current X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7684           * @return {Number} The X position of the element
7685           */
7686         getX : function(){
7687             return D.getX(this.dom);
7688         },
7689
7690         /**
7691           * Gets the current Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7692           * @return {Number} The Y position of the element
7693           */
7694         getY : function(){
7695             return D.getY(this.dom);
7696         },
7697
7698         /**
7699           * Gets the current position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7700           * @return {Array} The XY position of the element
7701           */
7702         getXY : function(){
7703             return D.getXY(this.dom);
7704         },
7705
7706         /**
7707          * Sets the X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7708          * @param {Number} The X position of the element
7709          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7710          * @return {Roo.Element} this
7711          */
7712         setX : function(x, animate){
7713             if(!animate || !A){
7714                 D.setX(this.dom, x);
7715             }else{
7716                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7717             }
7718             return this;
7719         },
7720
7721         /**
7722          * Sets the Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7723          * @param {Number} The Y position of the element
7724          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7725          * @return {Roo.Element} this
7726          */
7727         setY : function(y, animate){
7728             if(!animate || !A){
7729                 D.setY(this.dom, y);
7730             }else{
7731                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7732             }
7733             return this;
7734         },
7735
7736         /**
7737          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7738          * @param {String} left The left CSS property value
7739          * @return {Roo.Element} this
7740          */
7741         setLeft : function(left){
7742             this.setStyle("left", this.addUnits(left));
7743             return this;
7744         },
7745
7746         /**
7747          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7748          * @param {String} top The top CSS property value
7749          * @return {Roo.Element} this
7750          */
7751         setTop : function(top){
7752             this.setStyle("top", this.addUnits(top));
7753             return this;
7754         },
7755
7756         /**
7757          * Sets the element's CSS right style.
7758          * @param {String} right The right CSS property value
7759          * @return {Roo.Element} this
7760          */
7761         setRight : function(right){
7762             this.setStyle("right", this.addUnits(right));
7763             return this;
7764         },
7765
7766         /**
7767          * Sets the element's CSS bottom style.
7768          * @param {String} bottom The bottom CSS property value
7769          * @return {Roo.Element} this
7770          */
7771         setBottom : function(bottom){
7772             this.setStyle("bottom", this.addUnits(bottom));
7773             return this;
7774         },
7775
7776         /**
7777          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7778          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7779          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7780          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7781          * @return {Roo.Element} this
7782          */
7783         setXY : function(pos, animate){
7784             if(!animate || !A){
7785                 D.setXY(this.dom, pos);
7786             }else{
7787                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7788             }
7789             return this;
7790         },
7791
7792         /**
7793          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7794          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7795          * @param {Number} x X value for new position (coordinates are page-based)
7796          * @param {Number} y Y value for new position (coordinates are page-based)
7797          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7798          * @return {Roo.Element} this
7799          */
7800         setLocation : function(x, y, animate){
7801             this.setXY([x, y], this.preanim(arguments, 2));
7802             return this;
7803         },
7804
7805         /**
7806          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7807          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7808          * @param {Number} x X value for new position (coordinates are page-based)
7809          * @param {Number} y Y value for new position (coordinates are page-based)
7810          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7811          * @return {Roo.Element} this
7812          */
7813         moveTo : function(x, y, animate){
7814             this.setXY([x, y], this.preanim(arguments, 2));
7815             return this;
7816         },
7817
7818         /**
7819          * Returns the region of the given element.
7820          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7821          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7822          */
7823         getRegion : function(){
7824             return D.getRegion(this.dom);
7825         },
7826
7827         /**
7828          * Returns the offset height of the element
7829          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7830          * @return {Number} The element's height
7831          */
7832         getHeight : function(contentHeight){
7833             var h = this.dom.offsetHeight || 0;
7834             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7835         },
7836
7837         /**
7838          * Returns the offset width of the element
7839          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7840          * @return {Number} The element's width
7841          */
7842         getWidth : function(contentWidth){
7843             var w = this.dom.offsetWidth || 0;
7844             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7845         },
7846
7847         /**
7848          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7849          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7850          * if a height has not been set using CSS.
7851          * @return {Number}
7852          */
7853         getComputedHeight : function(){
7854             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7855             if(!h){
7856                 h = parseInt(this.getStyle('height'), 10) || 0;
7857                 if(!this.isBorderBox()){
7858                     h += this.getFrameWidth('tb');
7859                 }
7860             }
7861             return h;
7862         },
7863
7864         /**
7865          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7866          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7867          * if a width has not been set using CSS.
7868          * @return {Number}
7869          */
7870         getComputedWidth : function(){
7871             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7872             if(!w){
7873                 w = parseInt(this.getStyle('width'), 10) || 0;
7874                 if(!this.isBorderBox()){
7875                     w += this.getFrameWidth('lr');
7876                 }
7877             }
7878             return w;
7879         },
7880
7881         /**
7882          * Returns the size of the element.
7883          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7884          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7885          */
7886         getSize : function(contentSize){
7887             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7888         },
7889
7890         /**
7891          * Returns the width and height of the viewport.
7892          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7893          */
7894         getViewSize : function(){
7895             var d = this.dom, doc = document, aw = 0, ah = 0;
7896             if(d == doc || d == doc.body){
7897                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7898             }else{
7899                 return {
7900                     width : d.clientWidth,
7901                     height: d.clientHeight
7902                 };
7903             }
7904         },
7905
7906         /**
7907          * Returns the value of the "value" attribute
7908          * @param {Boolean} asNumber true to parse the value as a number
7909          * @return {String/Number}
7910          */
7911         getValue : function(asNumber){
7912             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7913         },
7914
7915         // private
7916         adjustWidth : function(width){
7917             if(typeof width == "number"){
7918                 if(this.autoBoxAdjust && !this.isBorderBox()){
7919                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7920                 }
7921                 if(width < 0){
7922                     width = 0;
7923                 }
7924             }
7925             return width;
7926         },
7927
7928         // private
7929         adjustHeight : function(height){
7930             if(typeof height == "number"){
7931                if(this.autoBoxAdjust && !this.isBorderBox()){
7932                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7933                }
7934                if(height < 0){
7935                    height = 0;
7936                }
7937             }
7938             return height;
7939         },
7940
7941         /**
7942          * Set the width of the element
7943          * @param {Number} width The new width
7944          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7945          * @return {Roo.Element} this
7946          */
7947         setWidth : function(width, animate){
7948             width = this.adjustWidth(width);
7949             if(!animate || !A){
7950                 this.dom.style.width = this.addUnits(width);
7951             }else{
7952                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7953             }
7954             return this;
7955         },
7956
7957         /**
7958          * Set the height of the element
7959          * @param {Number} height The new height
7960          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961          * @return {Roo.Element} this
7962          */
7963          setHeight : function(height, animate){
7964             height = this.adjustHeight(height);
7965             if(!animate || !A){
7966                 this.dom.style.height = this.addUnits(height);
7967             }else{
7968                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7969             }
7970             return this;
7971         },
7972
7973         /**
7974          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7975          * @param {Number} width The new width
7976          * @param {Number} height The new height
7977          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7978          * @return {Roo.Element} this
7979          */
7980          setSize : function(width, height, animate){
7981             if(typeof width == "object"){ // in case of object from getSize()
7982                 height = width.height; width = width.width;
7983             }
7984             width = this.adjustWidth(width); height = this.adjustHeight(height);
7985             if(!animate || !A){
7986                 this.dom.style.width = this.addUnits(width);
7987                 this.dom.style.height = this.addUnits(height);
7988             }else{
7989                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7990             }
7991             return this;
7992         },
7993
7994         /**
7995          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7996          * @param {Number} x X value for new position (coordinates are page-based)
7997          * @param {Number} y Y value for new position (coordinates are page-based)
7998          * @param {Number} width The new width
7999          * @param {Number} height The new height
8000          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8001          * @return {Roo.Element} this
8002          */
8003         setBounds : function(x, y, width, height, animate){
8004             if(!animate || !A){
8005                 this.setSize(width, height);
8006                 this.setLocation(x, y);
8007             }else{
8008                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8009                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8010                               this.preanim(arguments, 4), 'motion');
8011             }
8012             return this;
8013         },
8014
8015         /**
8016          * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8017          * @param {Roo.lib.Region} region The region to fill
8018          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8019          * @return {Roo.Element} this
8020          */
8021         setRegion : function(region, animate){
8022             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8023             return this;
8024         },
8025
8026         /**
8027          * Appends an event handler
8028          *
8029          * @param {String}   eventName     The type of event to append
8030          * @param {Function} fn        The method the event invokes
8031          * @param {Object} scope       (optional) The scope (this object) of the fn
8032          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8033          */
8034         addListener : function(eventName, fn, scope, options){
8035             if (this.dom) {
8036                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8037             }
8038         },
8039
8040         /**
8041          * Removes an event handler from this element
8042          * @param {String} eventName the type of event to remove
8043          * @param {Function} fn the method the event invokes
8044          * @return {Roo.Element} this
8045          */
8046         removeListener : function(eventName, fn){
8047             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8048             return this;
8049         },
8050
8051         /**
8052          * Removes all previous added listeners from this element
8053          * @return {Roo.Element} this
8054          */
8055         removeAllListeners : function(){
8056             E.purgeElement(this.dom);
8057             return this;
8058         },
8059
8060         relayEvent : function(eventName, observable){
8061             this.on(eventName, function(e){
8062                 observable.fireEvent(eventName, e);
8063             });
8064         },
8065
8066         /**
8067          * Set the opacity of the element
8068          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8069          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8070          * @return {Roo.Element} this
8071          */
8072          setOpacity : function(opacity, animate){
8073             if(!animate || !A){
8074                 var s = this.dom.style;
8075                 if(Roo.isIE){
8076                     s.zoom = 1;
8077                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8078                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8079                 }else{
8080                     s.opacity = opacity;
8081                 }
8082             }else{
8083                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8084             }
8085             return this;
8086         },
8087
8088         /**
8089          * Gets the left X coordinate
8090          * @param {Boolean} local True to get the local css position instead of page coordinate
8091          * @return {Number}
8092          */
8093         getLeft : function(local){
8094             if(!local){
8095                 return this.getX();
8096             }else{
8097                 return parseInt(this.getStyle("left"), 10) || 0;
8098             }
8099         },
8100
8101         /**
8102          * Gets the right X coordinate of the element (element X position + element width)
8103          * @param {Boolean} local True to get the local css position instead of page coordinate
8104          * @return {Number}
8105          */
8106         getRight : function(local){
8107             if(!local){
8108                 return this.getX() + this.getWidth();
8109             }else{
8110                 return (this.getLeft(true) + this.getWidth()) || 0;
8111             }
8112         },
8113
8114         /**
8115          * Gets the top Y coordinate
8116          * @param {Boolean} local True to get the local css position instead of page coordinate
8117          * @return {Number}
8118          */
8119         getTop : function(local) {
8120             if(!local){
8121                 return this.getY();
8122             }else{
8123                 return parseInt(this.getStyle("top"), 10) || 0;
8124             }
8125         },
8126
8127         /**
8128          * Gets the bottom Y coordinate of the element (element Y position + element height)
8129          * @param {Boolean} local True to get the local css position instead of page coordinate
8130          * @return {Number}
8131          */
8132         getBottom : function(local){
8133             if(!local){
8134                 return this.getY() + this.getHeight();
8135             }else{
8136                 return (this.getTop(true) + this.getHeight()) || 0;
8137             }
8138         },
8139
8140         /**
8141         * Initializes positioning on this element. If a desired position is not passed, it will make the
8142         * the element positioned relative IF it is not already positioned.
8143         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8144         * @param {Number} zIndex (optional) The zIndex to apply
8145         * @param {Number} x (optional) Set the page X position
8146         * @param {Number} y (optional) Set the page Y position
8147         */
8148         position : function(pos, zIndex, x, y){
8149             if(!pos){
8150                if(this.getStyle('position') == 'static'){
8151                    this.setStyle('position', 'relative');
8152                }
8153             }else{
8154                 this.setStyle("position", pos);
8155             }
8156             if(zIndex){
8157                 this.setStyle("z-index", zIndex);
8158             }
8159             if(x !== undefined && y !== undefined){
8160                 this.setXY([x, y]);
8161             }else if(x !== undefined){
8162                 this.setX(x);
8163             }else if(y !== undefined){
8164                 this.setY(y);
8165             }
8166         },
8167
8168         /**
8169         * Clear positioning back to the default when the document was loaded
8170         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8171         * @return {Roo.Element} this
8172          */
8173         clearPositioning : function(value){
8174             value = value ||'';
8175             this.setStyle({
8176                 "left": value,
8177                 "right": value,
8178                 "top": value,
8179                 "bottom": value,
8180                 "z-index": "",
8181                 "position" : "static"
8182             });
8183             return this;
8184         },
8185
8186         /**
8187         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8188         * snapshot before performing an update and then restoring the element.
8189         * @return {Object}
8190         */
8191         getPositioning : function(){
8192             var l = this.getStyle("left");
8193             var t = this.getStyle("top");
8194             return {
8195                 "position" : this.getStyle("position"),
8196                 "left" : l,
8197                 "right" : l ? "" : this.getStyle("right"),
8198                 "top" : t,
8199                 "bottom" : t ? "" : this.getStyle("bottom"),
8200                 "z-index" : this.getStyle("z-index")
8201             };
8202         },
8203
8204         /**
8205          * Gets the width of the border(s) for the specified side(s)
8206          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8207          * passing lr would get the border (l)eft width + the border (r)ight width.
8208          * @return {Number} The width of the sides passed added together
8209          */
8210         getBorderWidth : function(side){
8211             return this.addStyles(side, El.borders);
8212         },
8213
8214         /**
8215          * Gets the width of the padding(s) for the specified side(s)
8216          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8217          * passing lr would get the padding (l)eft + the padding (r)ight.
8218          * @return {Number} The padding of the sides passed added together
8219          */
8220         getPadding : function(side){
8221             return this.addStyles(side, El.paddings);
8222         },
8223
8224         /**
8225         * Set positioning with an object returned by getPositioning().
8226         * @param {Object} posCfg
8227         * @return {Roo.Element} this
8228          */
8229         setPositioning : function(pc){
8230             this.applyStyles(pc);
8231             if(pc.right == "auto"){
8232                 this.dom.style.right = "";
8233             }
8234             if(pc.bottom == "auto"){
8235                 this.dom.style.bottom = "";
8236             }
8237             return this;
8238         },
8239
8240         // private
8241         fixDisplay : function(){
8242             if(this.getStyle("display") == "none"){
8243                 this.setStyle("visibility", "hidden");
8244                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8245                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8246                     this.setStyle("display", "block");
8247                 }
8248             }
8249         },
8250
8251         /**
8252          * Quick set left and top adding default units
8253          * @param {String} left The left CSS property value
8254          * @param {String} top The top CSS property value
8255          * @return {Roo.Element} this
8256          */
8257          setLeftTop : function(left, top){
8258             this.dom.style.left = this.addUnits(left);
8259             this.dom.style.top = this.addUnits(top);
8260             return this;
8261         },
8262
8263         /**
8264          * Move this element relative to its current position.
8265          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8266          * @param {Number} distance How far to move the element in pixels
8267          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8268          * @return {Roo.Element} this
8269          */
8270          move : function(direction, distance, animate){
8271             var xy = this.getXY();
8272             direction = direction.toLowerCase();
8273             switch(direction){
8274                 case "l":
8275                 case "left":
8276                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8277                     break;
8278                case "r":
8279                case "right":
8280                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8281                     break;
8282                case "t":
8283                case "top":
8284                case "up":
8285                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8286                     break;
8287                case "b":
8288                case "bottom":
8289                case "down":
8290                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8291                     break;
8292             }
8293             return this;
8294         },
8295
8296         /**
8297          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8298          * @return {Roo.Element} this
8299          */
8300         clip : function(){
8301             if(!this.isClipped){
8302                this.isClipped = true;
8303                this.originalClip = {
8304                    "o": this.getStyle("overflow"),
8305                    "x": this.getStyle("overflow-x"),
8306                    "y": this.getStyle("overflow-y")
8307                };
8308                this.setStyle("overflow", "hidden");
8309                this.setStyle("overflow-x", "hidden");
8310                this.setStyle("overflow-y", "hidden");
8311             }
8312             return this;
8313         },
8314
8315         /**
8316          *  Return clipping (overflow) to original clipping before clip() was called
8317          * @return {Roo.Element} this
8318          */
8319         unclip : function(){
8320             if(this.isClipped){
8321                 this.isClipped = false;
8322                 var o = this.originalClip;
8323                 if(o.o){this.setStyle("overflow", o.o);}
8324                 if(o.x){this.setStyle("overflow-x", o.x);}
8325                 if(o.y){this.setStyle("overflow-y", o.y);}
8326             }
8327             return this;
8328         },
8329
8330
8331         /**
8332          * Gets the x,y coordinates specified by the anchor position on the element.
8333          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8334          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8335          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8336          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8337          * @return {Array} [x, y] An array containing the element's x and y coordinates
8338          */
8339         getAnchorXY : function(anchor, local, s){
8340             //Passing a different size is useful for pre-calculating anchors,
8341             //especially for anchored animations that change the el size.
8342
8343             var w, h, vp = false;
8344             if(!s){
8345                 var d = this.dom;
8346                 if(d == document.body || d == document){
8347                     vp = true;
8348                     w = D.getViewWidth(); h = D.getViewHeight();
8349                 }else{
8350                     w = this.getWidth(); h = this.getHeight();
8351                 }
8352             }else{
8353                 w = s.width;  h = s.height;
8354             }
8355             var x = 0, y = 0, r = Math.round;
8356             switch((anchor || "tl").toLowerCase()){
8357                 case "c":
8358                     x = r(w*.5);
8359                     y = r(h*.5);
8360                 break;
8361                 case "t":
8362                     x = r(w*.5);
8363                     y = 0;
8364                 break;
8365                 case "l":
8366                     x = 0;
8367                     y = r(h*.5);
8368                 break;
8369                 case "r":
8370                     x = w;
8371                     y = r(h*.5);
8372                 break;
8373                 case "b":
8374                     x = r(w*.5);
8375                     y = h;
8376                 break;
8377                 case "tl":
8378                     x = 0;
8379                     y = 0;
8380                 break;
8381                 case "bl":
8382                     x = 0;
8383                     y = h;
8384                 break;
8385                 case "br":
8386                     x = w;
8387                     y = h;
8388                 break;
8389                 case "tr":
8390                     x = w;
8391                     y = 0;
8392                 break;
8393             }
8394             if(local === true){
8395                 return [x, y];
8396             }
8397             if(vp){
8398                 var sc = this.getScroll();
8399                 return [x + sc.left, y + sc.top];
8400             }
8401             //Add the element's offset xy
8402             var o = this.getXY();
8403             return [x+o[0], y+o[1]];
8404         },
8405
8406         /**
8407          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8408          * supported position values.
8409          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8410          * @param {String} position The position to align to.
8411          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8412          * @return {Array} [x, y]
8413          */
8414         getAlignToXY : function(el, p, o){
8415             el = Roo.get(el);
8416             var d = this.dom;
8417             if(!el.dom){
8418                 throw "Element.alignTo with an element that doesn't exist";
8419             }
8420             var c = false; //constrain to viewport
8421             var p1 = "", p2 = "";
8422             o = o || [0,0];
8423
8424             if(!p){
8425                 p = "tl-bl";
8426             }else if(p == "?"){
8427                 p = "tl-bl?";
8428             }else if(p.indexOf("-") == -1){
8429                 p = "tl-" + p;
8430             }
8431             p = p.toLowerCase();
8432             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8433             if(!m){
8434                throw "Element.alignTo with an invalid alignment " + p;
8435             }
8436             p1 = m[1]; p2 = m[2]; c = !!m[3];
8437
8438             //Subtract the aligned el's internal xy from the target's offset xy
8439             //plus custom offset to get the aligned el's new offset xy
8440             var a1 = this.getAnchorXY(p1, true);
8441             var a2 = el.getAnchorXY(p2, false);
8442             var x = a2[0] - a1[0] + o[0];
8443             var y = a2[1] - a1[1] + o[1];
8444             if(c){
8445                 //constrain the aligned el to viewport if necessary
8446                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8447                 // 5px of margin for ie
8448                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8449
8450                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8451                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8452                 //otherwise swap the aligned el to the opposite border of the target.
8453                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8454                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8455                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8456                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8457
8458                var doc = document;
8459                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8460                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8461
8462                if((x+w) > dw + scrollX){
8463                     x = swapX ? r.left-w : dw+scrollX-w;
8464                 }
8465                if(x < scrollX){
8466                    x = swapX ? r.right : scrollX;
8467                }
8468                if((y+h) > dh + scrollY){
8469                     y = swapY ? r.top-h : dh+scrollY-h;
8470                 }
8471                if (y < scrollY){
8472                    y = swapY ? r.bottom : scrollY;
8473                }
8474             }
8475             return [x,y];
8476         },
8477
8478         // private
8479         getConstrainToXY : function(){
8480             var os = {top:0, left:0, bottom:0, right: 0};
8481
8482             return function(el, local, offsets, proposedXY){
8483                 el = Roo.get(el);
8484                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8485
8486                 var vw, vh, vx = 0, vy = 0;
8487                 if(el.dom == document.body || el.dom == document){
8488                     vw = Roo.lib.Dom.getViewWidth();
8489                     vh = Roo.lib.Dom.getViewHeight();
8490                 }else{
8491                     vw = el.dom.clientWidth;
8492                     vh = el.dom.clientHeight;
8493                     if(!local){
8494                         var vxy = el.getXY();
8495                         vx = vxy[0];
8496                         vy = vxy[1];
8497                     }
8498                 }
8499
8500                 var s = el.getScroll();
8501
8502                 vx += offsets.left + s.left;
8503                 vy += offsets.top + s.top;
8504
8505                 vw -= offsets.right;
8506                 vh -= offsets.bottom;
8507
8508                 var vr = vx+vw;
8509                 var vb = vy+vh;
8510
8511                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8512                 var x = xy[0], y = xy[1];
8513                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8514
8515                 // only move it if it needs it
8516                 var moved = false;
8517
8518                 // first validate right/bottom
8519                 if((x + w) > vr){
8520                     x = vr - w;
8521                     moved = true;
8522                 }
8523                 if((y + h) > vb){
8524                     y = vb - h;
8525                     moved = true;
8526                 }
8527                 // then make sure top/left isn't negative
8528                 if(x < vx){
8529                     x = vx;
8530                     moved = true;
8531                 }
8532                 if(y < vy){
8533                     y = vy;
8534                     moved = true;
8535                 }
8536                 return moved ? [x, y] : false;
8537             };
8538         }(),
8539
8540         // private
8541         adjustForConstraints : function(xy, parent, offsets){
8542             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8543         },
8544
8545         /**
8546          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8547          * document it aligns it to the viewport.
8548          * The position parameter is optional, and can be specified in any one of the following formats:
8549          * <ul>
8550          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8551          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8552          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8553          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8554          *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8555          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8556          * </ul>
8557          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8558          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8559          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8560          * that specified in order to enforce the viewport constraints.
8561          * Following are all of the supported anchor positions:
8562     <pre>
8563     Value  Description
8564     -----  -----------------------------
8565     tl     The top left corner (default)
8566     t      The center of the top edge
8567     tr     The top right corner
8568     l      The center of the left edge
8569     c      In the center of the element
8570     r      The center of the right edge
8571     bl     The bottom left corner
8572     b      The center of the bottom edge
8573     br     The bottom right corner
8574     </pre>
8575     Example Usage:
8576     <pre><code>
8577     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8578     el.alignTo("other-el");
8579
8580     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8581     el.alignTo("other-el", "tr?");
8582
8583     // align the bottom right corner of el with the center left edge of other-el
8584     el.alignTo("other-el", "br-l?");
8585
8586     // align the center of el with the bottom left corner of other-el and
8587     // adjust the x position by -6 pixels (and the y position by 0)
8588     el.alignTo("other-el", "c-bl", [-6, 0]);
8589     </code></pre>
8590          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8591          * @param {String} position The position to align to.
8592          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8593          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8594          * @return {Roo.Element} this
8595          */
8596         alignTo : function(element, position, offsets, animate){
8597             var xy = this.getAlignToXY(element, position, offsets);
8598             this.setXY(xy, this.preanim(arguments, 3));
8599             return this;
8600         },
8601
8602         /**
8603          * Anchors an element to another element and realigns it when the window is resized.
8604          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8605          * @param {String} position The position to align to.
8606          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8607          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8608          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8609          * is a number, it is used as the buffer delay (defaults to 50ms).
8610          * @param {Function} callback The function to call after the animation finishes
8611          * @return {Roo.Element} this
8612          */
8613         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8614             var action = function(){
8615                 this.alignTo(el, alignment, offsets, animate);
8616                 Roo.callback(callback, this);
8617             };
8618             Roo.EventManager.onWindowResize(action, this);
8619             var tm = typeof monitorScroll;
8620             if(tm != 'undefined'){
8621                 Roo.EventManager.on(window, 'scroll', action, this,
8622                     {buffer: tm == 'number' ? monitorScroll : 50});
8623             }
8624             action.call(this); // align immediately
8625             return this;
8626         },
8627         /**
8628          * Clears any opacity settings from this element. Required in some cases for IE.
8629          * @return {Roo.Element} this
8630          */
8631         clearOpacity : function(){
8632             if (window.ActiveXObject) {
8633                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8634                     this.dom.style.filter = "";
8635                 }
8636             } else {
8637                 this.dom.style.opacity = "";
8638                 this.dom.style["-moz-opacity"] = "";
8639                 this.dom.style["-khtml-opacity"] = "";
8640             }
8641             return this;
8642         },
8643
8644         /**
8645          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8646          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8647          * @return {Roo.Element} this
8648          */
8649         hide : function(animate){
8650             this.setVisible(false, this.preanim(arguments, 0));
8651             return this;
8652         },
8653
8654         /**
8655         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8656         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8657          * @return {Roo.Element} this
8658          */
8659         show : function(animate){
8660             this.setVisible(true, this.preanim(arguments, 0));
8661             return this;
8662         },
8663
8664         /**
8665          * @private Test if size has a unit, otherwise appends the default
8666          */
8667         addUnits : function(size){
8668             return Roo.Element.addUnits(size, this.defaultUnit);
8669         },
8670
8671         /**
8672          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8673          * @return {Roo.Element} this
8674          */
8675         beginMeasure : function(){
8676             var el = this.dom;
8677             if(el.offsetWidth || el.offsetHeight){
8678                 return this; // offsets work already
8679             }
8680             var changed = [];
8681             var p = this.dom, b = document.body; // start with this element
8682             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8683                 var pe = Roo.get(p);
8684                 if(pe.getStyle('display') == 'none'){
8685                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8686                     p.style.visibility = "hidden";
8687                     p.style.display = "block";
8688                 }
8689                 p = p.parentNode;
8690             }
8691             this._measureChanged = changed;
8692             return this;
8693
8694         },
8695
8696         /**
8697          * Restores displays to before beginMeasure was called
8698          * @return {Roo.Element} this
8699          */
8700         endMeasure : function(){
8701             var changed = this._measureChanged;
8702             if(changed){
8703                 for(var i = 0, len = changed.length; i < len; i++) {
8704                     var r = changed[i];
8705                     r.el.style.visibility = r.visibility;
8706                     r.el.style.display = "none";
8707                 }
8708                 this._measureChanged = null;
8709             }
8710             return this;
8711         },
8712
8713         /**
8714         * Update the innerHTML of this element, optionally searching for and processing scripts
8715         * @param {String} html The new HTML
8716         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8717         * @param {Function} callback For async script loading you can be noticed when the update completes
8718         * @return {Roo.Element} this
8719          */
8720         update : function(html, loadScripts, callback){
8721             if(typeof html == "undefined"){
8722                 html = "";
8723             }
8724             if(loadScripts !== true){
8725                 this.dom.innerHTML = html;
8726                 if(typeof callback == "function"){
8727                     callback();
8728                 }
8729                 return this;
8730             }
8731             var id = Roo.id();
8732             var dom = this.dom;
8733
8734             html += '<span id="' + id + '"></span>';
8735
8736             E.onAvailable(id, function(){
8737                 var hd = document.getElementsByTagName("head")[0];
8738                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8739                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8740                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8741
8742                 var match;
8743                 while(match = re.exec(html)){
8744                     var attrs = match[1];
8745                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8746                     if(srcMatch && srcMatch[2]){
8747                        var s = document.createElement("script");
8748                        s.src = srcMatch[2];
8749                        var typeMatch = attrs.match(typeRe);
8750                        if(typeMatch && typeMatch[2]){
8751                            s.type = typeMatch[2];
8752                        }
8753                        hd.appendChild(s);
8754                     }else if(match[2] && match[2].length > 0){
8755                         if(window.execScript) {
8756                            window.execScript(match[2]);
8757                         } else {
8758                             /**
8759                              * eval:var:id
8760                              * eval:var:dom
8761                              * eval:var:html
8762                              * 
8763                              */
8764                            window.eval(match[2]);
8765                         }
8766                     }
8767                 }
8768                 var el = document.getElementById(id);
8769                 if(el){el.parentNode.removeChild(el);}
8770                 if(typeof callback == "function"){
8771                     callback();
8772                 }
8773             });
8774             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8775             return this;
8776         },
8777
8778         /**
8779          * Direct access to the UpdateManager update() method (takes the same parameters).
8780          * @param {String/Function} url The url for this request or a function to call to get the url
8781          * @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}
8782          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8783          * @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.
8784          * @return {Roo.Element} this
8785          */
8786         load : function(){
8787             var um = this.getUpdateManager();
8788             um.update.apply(um, arguments);
8789             return this;
8790         },
8791
8792         /**
8793         * Gets this element's UpdateManager
8794         * @return {Roo.UpdateManager} The UpdateManager
8795         */
8796         getUpdateManager : function(){
8797             if(!this.updateManager){
8798                 this.updateManager = new Roo.UpdateManager(this);
8799             }
8800             return this.updateManager;
8801         },
8802
8803         /**
8804          * Disables text selection for this element (normalized across browsers)
8805          * @return {Roo.Element} this
8806          */
8807         unselectable : function(){
8808             this.dom.unselectable = "on";
8809             this.swallowEvent("selectstart", true);
8810             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8811             this.addClass("x-unselectable");
8812             return this;
8813         },
8814
8815         /**
8816         * Calculates the x, y to center this element on the screen
8817         * @return {Array} The x, y values [x, y]
8818         */
8819         getCenterXY : function(){
8820             return this.getAlignToXY(document, 'c-c');
8821         },
8822
8823         /**
8824         * Centers the Element in either the viewport, or another Element.
8825         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8826         */
8827         center : function(centerIn){
8828             this.alignTo(centerIn || document, 'c-c');
8829             return this;
8830         },
8831
8832         /**
8833          * Tests various css rules/browsers to determine if this element uses a border box
8834          * @return {Boolean}
8835          */
8836         isBorderBox : function(){
8837             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8838         },
8839
8840         /**
8841          * Return a box {x, y, width, height} that can be used to set another elements
8842          * size/location to match this element.
8843          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8844          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8845          * @return {Object} box An object in the format {x, y, width, height}
8846          */
8847         getBox : function(contentBox, local){
8848             var xy;
8849             if(!local){
8850                 xy = this.getXY();
8851             }else{
8852                 var left = parseInt(this.getStyle("left"), 10) || 0;
8853                 var top = parseInt(this.getStyle("top"), 10) || 0;
8854                 xy = [left, top];
8855             }
8856             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8857             if(!contentBox){
8858                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8859             }else{
8860                 var l = this.getBorderWidth("l")+this.getPadding("l");
8861                 var r = this.getBorderWidth("r")+this.getPadding("r");
8862                 var t = this.getBorderWidth("t")+this.getPadding("t");
8863                 var b = this.getBorderWidth("b")+this.getPadding("b");
8864                 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8865             }
8866             bx.right = bx.x + bx.width;
8867             bx.bottom = bx.y + bx.height;
8868             return bx;
8869         },
8870
8871         /**
8872          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8873          for more information about the sides.
8874          * @param {String} sides
8875          * @return {Number}
8876          */
8877         getFrameWidth : function(sides, onlyContentBox){
8878             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8879         },
8880
8881         /**
8882          * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8883          * @param {Object} box The box to fill {x, y, width, height}
8884          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8885          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8886          * @return {Roo.Element} this
8887          */
8888         setBox : function(box, adjust, animate){
8889             var w = box.width, h = box.height;
8890             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8891                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8892                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8893             }
8894             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8895             return this;
8896         },
8897
8898         /**
8899          * Forces the browser to repaint this element
8900          * @return {Roo.Element} this
8901          */
8902          repaint : function(){
8903             var dom = this.dom;
8904             this.addClass("x-repaint");
8905             setTimeout(function(){
8906                 Roo.get(dom).removeClass("x-repaint");
8907             }, 1);
8908             return this;
8909         },
8910
8911         /**
8912          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8913          * then it returns the calculated width of the sides (see getPadding)
8914          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8915          * @return {Object/Number}
8916          */
8917         getMargins : function(side){
8918             if(!side){
8919                 return {
8920                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8921                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8922                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8923                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8924                 };
8925             }else{
8926                 return this.addStyles(side, El.margins);
8927              }
8928         },
8929
8930         // private
8931         addStyles : function(sides, styles){
8932             var val = 0, v, w;
8933             for(var i = 0, len = sides.length; i < len; i++){
8934                 v = this.getStyle(styles[sides.charAt(i)]);
8935                 if(v){
8936                      w = parseInt(v, 10);
8937                      if(w){ val += w; }
8938                 }
8939             }
8940             return val;
8941         },
8942
8943         /**
8944          * Creates a proxy element of this element
8945          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8946          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8947          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8948          * @return {Roo.Element} The new proxy element
8949          */
8950         createProxy : function(config, renderTo, matchBox){
8951             if(renderTo){
8952                 renderTo = Roo.getDom(renderTo);
8953             }else{
8954                 renderTo = document.body;
8955             }
8956             config = typeof config == "object" ?
8957                 config : {tag : "div", cls: config};
8958             var proxy = Roo.DomHelper.append(renderTo, config, true);
8959             if(matchBox){
8960                proxy.setBox(this.getBox());
8961             }
8962             return proxy;
8963         },
8964
8965         /**
8966          * Puts a mask over this element to disable user interaction. Requires core.css.
8967          * This method can only be applied to elements which accept child nodes.
8968          * @param {String} msg (optional) A message to display in the mask
8969          * @param {String} msgCls (optional) A css class to apply to the msg element
8970          * @return {Element} The mask  element
8971          */
8972         mask : function(msg, msgCls)
8973         {
8974             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8975                 this.setStyle("position", "relative");
8976             }
8977             if(!this._mask){
8978                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8979             }
8980             this.addClass("x-masked");
8981             this._mask.setDisplayed(true);
8982             
8983             // we wander
8984             var z = 0;
8985             var dom = this.dom
8986             while (dom && dom.style) {
8987                 if (!isNaN(parseInt(dom.style.zIndex))) {
8988                     z = Math.max(z, parseInt(dom.style.zIndex));
8989                 }
8990                 dom = dom.parentNode;
8991             }
8992             // if we are masking the body - then it hides everything..
8993             if (this.dom == document.body) {
8994                 z = 1000000;
8995                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8996                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8997             }
8998            
8999             if(typeof msg == 'string'){
9000                 if(!this._maskMsg){
9001                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9002                 }
9003                 var mm = this._maskMsg;
9004                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9005                 mm.dom.firstChild.innerHTML = msg;
9006                 mm.setDisplayed(true);
9007                 mm.center(this);
9008                 mm.setStyle('z-index', z + 102);
9009             }
9010             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9011                 this._mask.setHeight(this.getHeight());
9012             }
9013             this._mask.setStyle('z-index', z + 100);
9014             
9015             return this._mask;
9016         },
9017
9018         /**
9019          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9020          * it is cached for reuse.
9021          */
9022         unmask : function(removeEl){
9023             if(this._mask){
9024                 if(removeEl === true){
9025                     this._mask.remove();
9026                     delete this._mask;
9027                     if(this._maskMsg){
9028                         this._maskMsg.remove();
9029                         delete this._maskMsg;
9030                     }
9031                 }else{
9032                     this._mask.setDisplayed(false);
9033                     if(this._maskMsg){
9034                         this._maskMsg.setDisplayed(false);
9035                     }
9036                 }
9037             }
9038             this.removeClass("x-masked");
9039         },
9040
9041         /**
9042          * Returns true if this element is masked
9043          * @return {Boolean}
9044          */
9045         isMasked : function(){
9046             return this._mask && this._mask.isVisible();
9047         },
9048
9049         /**
9050          * Creates an iframe shim for this element to keep selects and other windowed objects from
9051          * showing through.
9052          * @return {Roo.Element} The new shim element
9053          */
9054         createShim : function(){
9055             var el = document.createElement('iframe');
9056             el.frameBorder = 'no';
9057             el.className = 'roo-shim';
9058             if(Roo.isIE && Roo.isSecure){
9059                 el.src = Roo.SSL_SECURE_URL;
9060             }
9061             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9062             shim.autoBoxAdjust = false;
9063             return shim;
9064         },
9065
9066         /**
9067          * Removes this element from the DOM and deletes it from the cache
9068          */
9069         remove : function(){
9070             if(this.dom.parentNode){
9071                 this.dom.parentNode.removeChild(this.dom);
9072             }
9073             delete El.cache[this.dom.id];
9074         },
9075
9076         /**
9077          * Sets up event handlers to add and remove a css class when the mouse is over this element
9078          * @param {String} className
9079          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9080          * mouseout events for children elements
9081          * @return {Roo.Element} this
9082          */
9083         addClassOnOver : function(className, preventFlicker){
9084             this.on("mouseover", function(){
9085                 Roo.fly(this, '_internal').addClass(className);
9086             }, this.dom);
9087             var removeFn = function(e){
9088                 if(preventFlicker !== true || !e.within(this, true)){
9089                     Roo.fly(this, '_internal').removeClass(className);
9090                 }
9091             };
9092             this.on("mouseout", removeFn, this.dom);
9093             return this;
9094         },
9095
9096         /**
9097          * Sets up event handlers to add and remove a css class when this element has the focus
9098          * @param {String} className
9099          * @return {Roo.Element} this
9100          */
9101         addClassOnFocus : function(className){
9102             this.on("focus", function(){
9103                 Roo.fly(this, '_internal').addClass(className);
9104             }, this.dom);
9105             this.on("blur", function(){
9106                 Roo.fly(this, '_internal').removeClass(className);
9107             }, this.dom);
9108             return this;
9109         },
9110         /**
9111          * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9112          * @param {String} className
9113          * @return {Roo.Element} this
9114          */
9115         addClassOnClick : function(className){
9116             var dom = this.dom;
9117             this.on("mousedown", function(){
9118                 Roo.fly(dom, '_internal').addClass(className);
9119                 var d = Roo.get(document);
9120                 var fn = function(){
9121                     Roo.fly(dom, '_internal').removeClass(className);
9122                     d.removeListener("mouseup", fn);
9123                 };
9124                 d.on("mouseup", fn);
9125             });
9126             return this;
9127         },
9128
9129         /**
9130          * Stops the specified event from bubbling and optionally prevents the default action
9131          * @param {String} eventName
9132          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9133          * @return {Roo.Element} this
9134          */
9135         swallowEvent : function(eventName, preventDefault){
9136             var fn = function(e){
9137                 e.stopPropagation();
9138                 if(preventDefault){
9139                     e.preventDefault();
9140                 }
9141             };
9142             if(eventName instanceof Array){
9143                 for(var i = 0, len = eventName.length; i < len; i++){
9144                      this.on(eventName[i], fn);
9145                 }
9146                 return this;
9147             }
9148             this.on(eventName, fn);
9149             return this;
9150         },
9151
9152         /**
9153          * @private
9154          */
9155       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9156
9157         /**
9158          * Sizes this element to its parent element's dimensions performing
9159          * neccessary box adjustments.
9160          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9161          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9162          * @return {Roo.Element} this
9163          */
9164         fitToParent : function(monitorResize, targetParent) {
9165           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9166           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9167           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9168             return;
9169           }
9170           var p = Roo.get(targetParent || this.dom.parentNode);
9171           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9172           if (monitorResize === true) {
9173             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9174             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9175           }
9176           return this;
9177         },
9178
9179         /**
9180          * Gets the next sibling, skipping text nodes
9181          * @return {HTMLElement} The next sibling or null
9182          */
9183         getNextSibling : function(){
9184             var n = this.dom.nextSibling;
9185             while(n && n.nodeType != 1){
9186                 n = n.nextSibling;
9187             }
9188             return n;
9189         },
9190
9191         /**
9192          * Gets the previous sibling, skipping text nodes
9193          * @return {HTMLElement} The previous sibling or null
9194          */
9195         getPrevSibling : function(){
9196             var n = this.dom.previousSibling;
9197             while(n && n.nodeType != 1){
9198                 n = n.previousSibling;
9199             }
9200             return n;
9201         },
9202
9203
9204         /**
9205          * Appends the passed element(s) to this element
9206          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9207          * @return {Roo.Element} this
9208          */
9209         appendChild: function(el){
9210             el = Roo.get(el);
9211             el.appendTo(this);
9212             return this;
9213         },
9214
9215         /**
9216          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9217          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9218          * automatically generated with the specified attributes.
9219          * @param {HTMLElement} insertBefore (optional) a child element of this element
9220          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9221          * @return {Roo.Element} The new child element
9222          */
9223         createChild: function(config, insertBefore, returnDom){
9224             config = config || {tag:'div'};
9225             if(insertBefore){
9226                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9227             }
9228             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9229         },
9230
9231         /**
9232          * Appends this element to the passed element
9233          * @param {String/HTMLElement/Element} el The new parent element
9234          * @return {Roo.Element} this
9235          */
9236         appendTo: function(el){
9237             el = Roo.getDom(el);
9238             el.appendChild(this.dom);
9239             return this;
9240         },
9241
9242         /**
9243          * Inserts this element before the passed element in the DOM
9244          * @param {String/HTMLElement/Element} el The element to insert before
9245          * @return {Roo.Element} this
9246          */
9247         insertBefore: function(el){
9248             el = Roo.getDom(el);
9249             el.parentNode.insertBefore(this.dom, el);
9250             return this;
9251         },
9252
9253         /**
9254          * Inserts this element after the passed element in the DOM
9255          * @param {String/HTMLElement/Element} el The element to insert after
9256          * @return {Roo.Element} this
9257          */
9258         insertAfter: function(el){
9259             el = Roo.getDom(el);
9260             el.parentNode.insertBefore(this.dom, el.nextSibling);
9261             return this;
9262         },
9263
9264         /**
9265          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9266          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9267          * @return {Roo.Element} The new child
9268          */
9269         insertFirst: function(el, returnDom){
9270             el = el || {};
9271             if(typeof el == 'object' && !el.nodeType){ // dh config
9272                 return this.createChild(el, this.dom.firstChild, returnDom);
9273             }else{
9274                 el = Roo.getDom(el);
9275                 this.dom.insertBefore(el, this.dom.firstChild);
9276                 return !returnDom ? Roo.get(el) : el;
9277             }
9278         },
9279
9280         /**
9281          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9282          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9283          * @param {String} where (optional) 'before' or 'after' defaults to before
9284          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9285          * @return {Roo.Element} the inserted Element
9286          */
9287         insertSibling: function(el, where, returnDom){
9288             where = where ? where.toLowerCase() : 'before';
9289             el = el || {};
9290             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9291
9292             if(typeof el == 'object' && !el.nodeType){ // dh config
9293                 if(where == 'after' && !this.dom.nextSibling){
9294                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9295                 }else{
9296                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9297                 }
9298
9299             }else{
9300                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9301                             where == 'before' ? this.dom : this.dom.nextSibling);
9302                 if(!returnDom){
9303                     rt = Roo.get(rt);
9304                 }
9305             }
9306             return rt;
9307         },
9308
9309         /**
9310          * Creates and wraps this element with another element
9311          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9312          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9313          * @return {HTMLElement/Element} The newly created wrapper element
9314          */
9315         wrap: function(config, returnDom){
9316             if(!config){
9317                 config = {tag: "div"};
9318             }
9319             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9320             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9321             return newEl;
9322         },
9323
9324         /**
9325          * Replaces the passed element with this element
9326          * @param {String/HTMLElement/Element} el The element to replace
9327          * @return {Roo.Element} this
9328          */
9329         replace: function(el){
9330             el = Roo.get(el);
9331             this.insertBefore(el);
9332             el.remove();
9333             return this;
9334         },
9335
9336         /**
9337          * Inserts an html fragment into this element
9338          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9339          * @param {String} html The HTML fragment
9340          * @param {Boolean} returnEl True to return an Roo.Element
9341          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9342          */
9343         insertHtml : function(where, html, returnEl){
9344             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9345             return returnEl ? Roo.get(el) : el;
9346         },
9347
9348         /**
9349          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9350          * @param {Object} o The object with the attributes
9351          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9352          * @return {Roo.Element} this
9353          */
9354         set : function(o, useSet){
9355             var el = this.dom;
9356             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9357             for(var attr in o){
9358                 if(attr == "style" || typeof o[attr] == "function") continue;
9359                 if(attr=="cls"){
9360                     el.className = o["cls"];
9361                 }else{
9362                     if(useSet) el.setAttribute(attr, o[attr]);
9363                     else el[attr] = o[attr];
9364                 }
9365             }
9366             if(o.style){
9367                 Roo.DomHelper.applyStyles(el, o.style);
9368             }
9369             return this;
9370         },
9371
9372         /**
9373          * Convenience method for constructing a KeyMap
9374          * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9375          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9376          * @param {Function} fn The function to call
9377          * @param {Object} scope (optional) The scope of the function
9378          * @return {Roo.KeyMap} The KeyMap created
9379          */
9380         addKeyListener : function(key, fn, scope){
9381             var config;
9382             if(typeof key != "object" || key instanceof Array){
9383                 config = {
9384                     key: key,
9385                     fn: fn,
9386                     scope: scope
9387                 };
9388             }else{
9389                 config = {
9390                     key : key.key,
9391                     shift : key.shift,
9392                     ctrl : key.ctrl,
9393                     alt : key.alt,
9394                     fn: fn,
9395                     scope: scope
9396                 };
9397             }
9398             return new Roo.KeyMap(this, config);
9399         },
9400
9401         /**
9402          * Creates a KeyMap for this element
9403          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9404          * @return {Roo.KeyMap} The KeyMap created
9405          */
9406         addKeyMap : function(config){
9407             return new Roo.KeyMap(this, config);
9408         },
9409
9410         /**
9411          * Returns true if this element is scrollable.
9412          * @return {Boolean}
9413          */
9414          isScrollable : function(){
9415             var dom = this.dom;
9416             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9417         },
9418
9419         /**
9420          * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9421          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9422          * @param {Number} value The new scroll value
9423          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9424          * @return {Element} this
9425          */
9426
9427         scrollTo : function(side, value, animate){
9428             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9429             if(!animate || !A){
9430                 this.dom[prop] = value;
9431             }else{
9432                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9433                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9434             }
9435             return this;
9436         },
9437
9438         /**
9439          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9440          * within this element's scrollable range.
9441          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9442          * @param {Number} distance How far to scroll the element in pixels
9443          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9444          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9445          * was scrolled as far as it could go.
9446          */
9447          scroll : function(direction, distance, animate){
9448              if(!this.isScrollable()){
9449                  return;
9450              }
9451              var el = this.dom;
9452              var l = el.scrollLeft, t = el.scrollTop;
9453              var w = el.scrollWidth, h = el.scrollHeight;
9454              var cw = el.clientWidth, ch = el.clientHeight;
9455              direction = direction.toLowerCase();
9456              var scrolled = false;
9457              var a = this.preanim(arguments, 2);
9458              switch(direction){
9459                  case "l":
9460                  case "left":
9461                      if(w - l > cw){
9462                          var v = Math.min(l + distance, w-cw);
9463                          this.scrollTo("left", v, a);
9464                          scrolled = true;
9465                      }
9466                      break;
9467                 case "r":
9468                 case "right":
9469                      if(l > 0){
9470                          var v = Math.max(l - distance, 0);
9471                          this.scrollTo("left", v, a);
9472                          scrolled = true;
9473                      }
9474                      break;
9475                 case "t":
9476                 case "top":
9477                 case "up":
9478                      if(t > 0){
9479                          var v = Math.max(t - distance, 0);
9480                          this.scrollTo("top", v, a);
9481                          scrolled = true;
9482                      }
9483                      break;
9484                 case "b":
9485                 case "bottom":
9486                 case "down":
9487                      if(h - t > ch){
9488                          var v = Math.min(t + distance, h-ch);
9489                          this.scrollTo("top", v, a);
9490                          scrolled = true;
9491                      }
9492                      break;
9493              }
9494              return scrolled;
9495         },
9496
9497         /**
9498          * Translates the passed page coordinates into left/top css values for this element
9499          * @param {Number/Array} x The page x or an array containing [x, y]
9500          * @param {Number} y The page y
9501          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9502          */
9503         translatePoints : function(x, y){
9504             if(typeof x == 'object' || x instanceof Array){
9505                 y = x[1]; x = x[0];
9506             }
9507             var p = this.getStyle('position');
9508             var o = this.getXY();
9509
9510             var l = parseInt(this.getStyle('left'), 10);
9511             var t = parseInt(this.getStyle('top'), 10);
9512
9513             if(isNaN(l)){
9514                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9515             }
9516             if(isNaN(t)){
9517                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9518             }
9519
9520             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9521         },
9522
9523         /**
9524          * Returns the current scroll position of the element.
9525          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9526          */
9527         getScroll : function(){
9528             var d = this.dom, doc = document;
9529             if(d == doc || d == doc.body){
9530                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9531                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9532                 return {left: l, top: t};
9533             }else{
9534                 return {left: d.scrollLeft, top: d.scrollTop};
9535             }
9536         },
9537
9538         /**
9539          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9540          * are convert to standard 6 digit hex color.
9541          * @param {String} attr The css attribute
9542          * @param {String} defaultValue The default value to use when a valid color isn't found
9543          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9544          * YUI color anims.
9545          */
9546         getColor : function(attr, defaultValue, prefix){
9547             var v = this.getStyle(attr);
9548             if(!v || v == "transparent" || v == "inherit") {
9549                 return defaultValue;
9550             }
9551             var color = typeof prefix == "undefined" ? "#" : prefix;
9552             if(v.substr(0, 4) == "rgb("){
9553                 var rvs = v.slice(4, v.length -1).split(",");
9554                 for(var i = 0; i < 3; i++){
9555                     var h = parseInt(rvs[i]).toString(16);
9556                     if(h < 16){
9557                         h = "0" + h;
9558                     }
9559                     color += h;
9560                 }
9561             } else {
9562                 if(v.substr(0, 1) == "#"){
9563                     if(v.length == 4) {
9564                         for(var i = 1; i < 4; i++){
9565                             var c = v.charAt(i);
9566                             color +=  c + c;
9567                         }
9568                     }else if(v.length == 7){
9569                         color += v.substr(1);
9570                     }
9571                 }
9572             }
9573             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9574         },
9575
9576         /**
9577          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9578          * gradient background, rounded corners and a 4-way shadow.
9579          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9580          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9581          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9582          * @return {Roo.Element} this
9583          */
9584         boxWrap : function(cls){
9585             cls = cls || 'x-box';
9586             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9587             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9588             return el;
9589         },
9590
9591         /**
9592          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9593          * @param {String} namespace The namespace in which to look for the attribute
9594          * @param {String} name The attribute name
9595          * @return {String} The attribute value
9596          */
9597         getAttributeNS : Roo.isIE ? function(ns, name){
9598             var d = this.dom;
9599             var type = typeof d[ns+":"+name];
9600             if(type != 'undefined' && type != 'unknown'){
9601                 return d[ns+":"+name];
9602             }
9603             return d[name];
9604         } : function(ns, name){
9605             var d = this.dom;
9606             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9607         },
9608         
9609         
9610         /**
9611          * Sets or Returns the value the dom attribute value
9612          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9613          * @param {String} value (optional) The value to set the attribute to
9614          * @return {String} The attribute value
9615          */
9616         attr : function(name){
9617             if (arguments.length > 1) {
9618                 this.dom.setAttribute(name, arguments[1]);
9619                 return arguments[1];
9620             }
9621             if (typeof(name) == 'object') {
9622                 for(var i in name) {
9623                     this.attr(i, name[i]);
9624                 }
9625                 return name;
9626             }
9627             
9628             
9629             if (!this.dom.hasAttribute(name)) {
9630                 return undefined;
9631             }
9632             return this.dom.getAttribute(name);
9633         }
9634         
9635         
9636         
9637     };
9638
9639     var ep = El.prototype;
9640
9641     /**
9642      * Appends an event handler (Shorthand for addListener)
9643      * @param {String}   eventName     The type of event to append
9644      * @param {Function} fn        The method the event invokes
9645      * @param {Object} scope       (optional) The scope (this object) of the fn
9646      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9647      * @method
9648      */
9649     ep.on = ep.addListener;
9650         // backwards compat
9651     ep.mon = ep.addListener;
9652
9653     /**
9654      * Removes an event handler from this element (shorthand for removeListener)
9655      * @param {String} eventName the type of event to remove
9656      * @param {Function} fn the method the event invokes
9657      * @return {Roo.Element} this
9658      * @method
9659      */
9660     ep.un = ep.removeListener;
9661
9662     /**
9663      * true to automatically adjust width and height settings for box-model issues (default to true)
9664      */
9665     ep.autoBoxAdjust = true;
9666
9667     // private
9668     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9669
9670     // private
9671     El.addUnits = function(v, defaultUnit){
9672         if(v === "" || v == "auto"){
9673             return v;
9674         }
9675         if(v === undefined){
9676             return '';
9677         }
9678         if(typeof v == "number" || !El.unitPattern.test(v)){
9679             return v + (defaultUnit || 'px');
9680         }
9681         return v;
9682     };
9683
9684     // special markup used throughout Roo when box wrapping elements
9685     El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9686     /**
9687      * Visibility mode constant - Use visibility to hide element
9688      * @static
9689      * @type Number
9690      */
9691     El.VISIBILITY = 1;
9692     /**
9693      * Visibility mode constant - Use display to hide element
9694      * @static
9695      * @type Number
9696      */
9697     El.DISPLAY = 2;
9698
9699     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9700     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9701     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9702
9703
9704
9705     /**
9706      * @private
9707      */
9708     El.cache = {};
9709
9710     var docEl;
9711
9712     /**
9713      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9714      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9715      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9716      * @return {Element} The Element object
9717      * @static
9718      */
9719     El.get = function(el){
9720         var ex, elm, id;
9721         if(!el){ return null; }
9722         if(typeof el == "string"){ // element id
9723             if(!(elm = document.getElementById(el))){
9724                 return null;
9725             }
9726             if(ex = El.cache[el]){
9727                 ex.dom = elm;
9728             }else{
9729                 ex = El.cache[el] = new El(elm);
9730             }
9731             return ex;
9732         }else if(el.tagName){ // dom element
9733             if(!(id = el.id)){
9734                 id = Roo.id(el);
9735             }
9736             if(ex = El.cache[id]){
9737                 ex.dom = el;
9738             }else{
9739                 ex = El.cache[id] = new El(el);
9740             }
9741             return ex;
9742         }else if(el instanceof El){
9743             if(el != docEl){
9744                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9745                                                               // catch case where it hasn't been appended
9746                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9747             }
9748             return el;
9749         }else if(el.isComposite){
9750             return el;
9751         }else if(el instanceof Array){
9752             return El.select(el);
9753         }else if(el == document){
9754             // create a bogus element object representing the document object
9755             if(!docEl){
9756                 var f = function(){};
9757                 f.prototype = El.prototype;
9758                 docEl = new f();
9759                 docEl.dom = document;
9760             }
9761             return docEl;
9762         }
9763         return null;
9764     };
9765
9766     // private
9767     El.uncache = function(el){
9768         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9769             if(a[i]){
9770                 delete El.cache[a[i].id || a[i]];
9771             }
9772         }
9773     };
9774
9775     // private
9776     // Garbage collection - uncache elements/purge listeners on orphaned elements
9777     // so we don't hold a reference and cause the browser to retain them
9778     El.garbageCollect = function(){
9779         if(!Roo.enableGarbageCollector){
9780             clearInterval(El.collectorThread);
9781             return;
9782         }
9783         for(var eid in El.cache){
9784             var el = El.cache[eid], d = el.dom;
9785             // -------------------------------------------------------
9786             // Determining what is garbage:
9787             // -------------------------------------------------------
9788             // !d
9789             // dom node is null, definitely garbage
9790             // -------------------------------------------------------
9791             // !d.parentNode
9792             // no parentNode == direct orphan, definitely garbage
9793             // -------------------------------------------------------
9794             // !d.offsetParent && !document.getElementById(eid)
9795             // display none elements have no offsetParent so we will
9796             // also try to look it up by it's id. However, check
9797             // offsetParent first so we don't do unneeded lookups.
9798             // This enables collection of elements that are not orphans
9799             // directly, but somewhere up the line they have an orphan
9800             // parent.
9801             // -------------------------------------------------------
9802             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9803                 delete El.cache[eid];
9804                 if(d && Roo.enableListenerCollection){
9805                     E.purgeElement(d);
9806                 }
9807             }
9808         }
9809     }
9810     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9811
9812
9813     // dom is optional
9814     El.Flyweight = function(dom){
9815         this.dom = dom;
9816     };
9817     El.Flyweight.prototype = El.prototype;
9818
9819     El._flyweights = {};
9820     /**
9821      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9822      * the dom node can be overwritten by other code.
9823      * @param {String/HTMLElement} el The dom node or id
9824      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9825      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9826      * @static
9827      * @return {Element} The shared Element object
9828      */
9829     El.fly = function(el, named){
9830         named = named || '_global';
9831         el = Roo.getDom(el);
9832         if(!el){
9833             return null;
9834         }
9835         if(!El._flyweights[named]){
9836             El._flyweights[named] = new El.Flyweight();
9837         }
9838         El._flyweights[named].dom = el;
9839         return El._flyweights[named];
9840     };
9841
9842     /**
9843      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9844      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9845      * Shorthand of {@link Roo.Element#get}
9846      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9847      * @return {Element} The Element object
9848      * @member Roo
9849      * @method get
9850      */
9851     Roo.get = El.get;
9852     /**
9853      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9854      * the dom node can be overwritten by other code.
9855      * Shorthand of {@link Roo.Element#fly}
9856      * @param {String/HTMLElement} el The dom node or id
9857      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9858      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9859      * @static
9860      * @return {Element} The shared Element object
9861      * @member Roo
9862      * @method fly
9863      */
9864     Roo.fly = El.fly;
9865
9866     // speedy lookup for elements never to box adjust
9867     var noBoxAdjust = Roo.isStrict ? {
9868         select:1
9869     } : {
9870         input:1, select:1, textarea:1
9871     };
9872     if(Roo.isIE || Roo.isGecko){
9873         noBoxAdjust['button'] = 1;
9874     }
9875
9876
9877     Roo.EventManager.on(window, 'unload', function(){
9878         delete El.cache;
9879         delete El._flyweights;
9880     });
9881 })();
9882
9883
9884
9885
9886 if(Roo.DomQuery){
9887     Roo.Element.selectorFunction = Roo.DomQuery.select;
9888 }
9889
9890 Roo.Element.select = function(selector, unique, root){
9891     var els;
9892     if(typeof selector == "string"){
9893         els = Roo.Element.selectorFunction(selector, root);
9894     }else if(selector.length !== undefined){
9895         els = selector;
9896     }else{
9897         throw "Invalid selector";
9898     }
9899     if(unique === true){
9900         return new Roo.CompositeElement(els);
9901     }else{
9902         return new Roo.CompositeElementLite(els);
9903     }
9904 };
9905 /**
9906  * Selects elements based on the passed CSS selector to enable working on them as 1.
9907  * @param {String/Array} selector The CSS selector or an array of elements
9908  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9909  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9910  * @return {CompositeElementLite/CompositeElement}
9911  * @member Roo
9912  * @method select
9913  */
9914 Roo.select = Roo.Element.select;
9915
9916
9917
9918
9919
9920
9921
9922
9923
9924
9925
9926
9927
9928
9929 /*
9930  * Based on:
9931  * Ext JS Library 1.1.1
9932  * Copyright(c) 2006-2007, Ext JS, LLC.
9933  *
9934  * Originally Released Under LGPL - original licence link has changed is not relivant.
9935  *
9936  * Fork - LGPL
9937  * <script type="text/javascript">
9938  */
9939
9940
9941
9942 //Notifies Element that fx methods are available
9943 Roo.enableFx = true;
9944
9945 /**
9946  * @class Roo.Fx
9947  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9948  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9949  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9950  * Element effects to work.</p><br/>
9951  *
9952  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9953  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9954  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9955  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9956  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9957  * expected results and should be done with care.</p><br/>
9958  *
9959  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9960  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9961 <pre>
9962 Value  Description
9963 -----  -----------------------------
9964 tl     The top left corner
9965 t      The center of the top edge
9966 tr     The top right corner
9967 l      The center of the left edge
9968 r      The center of the right edge
9969 bl     The bottom left corner
9970 b      The center of the bottom edge
9971 br     The bottom right corner
9972 </pre>
9973  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9974  * below are common options that can be passed to any Fx method.</b>
9975  * @cfg {Function} callback A function called when the effect is finished
9976  * @cfg {Object} scope The scope of the effect function
9977  * @cfg {String} easing A valid Easing value for the effect
9978  * @cfg {String} afterCls A css class to apply after the effect
9979  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9980  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9981  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9982  * effects that end with the element being visually hidden, ignored otherwise)
9983  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9984  * a function which returns such a specification that will be applied to the Element after the effect finishes
9985  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9986  * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9987  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9988  */
9989 Roo.Fx = {
9990         /**
9991          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9992          * origin for the slide effect.  This function automatically handles wrapping the element with
9993          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9994          * Usage:
9995          *<pre><code>
9996 // default: slide the element in from the top
9997 el.slideIn();
9998
9999 // custom: slide the element in from the right with a 2-second duration
10000 el.slideIn('r', { duration: 2 });
10001
10002 // common config options shown with default values
10003 el.slideIn('t', {
10004     easing: 'easeOut',
10005     duration: .5
10006 });
10007 </code></pre>
10008          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10009          * @param {Object} options (optional) Object literal with any of the Fx config options
10010          * @return {Roo.Element} The Element
10011          */
10012     slideIn : function(anchor, o){
10013         var el = this.getFxEl();
10014         o = o || {};
10015
10016         el.queueFx(o, function(){
10017
10018             anchor = anchor || "t";
10019
10020             // fix display to visibility
10021             this.fixDisplay();
10022
10023             // restore values after effect
10024             var r = this.getFxRestore();
10025             var b = this.getBox();
10026             // fixed size for slide
10027             this.setSize(b);
10028
10029             // wrap if needed
10030             var wrap = this.fxWrap(r.pos, o, "hidden");
10031
10032             var st = this.dom.style;
10033             st.visibility = "visible";
10034             st.position = "absolute";
10035
10036             // clear out temp styles after slide and unwrap
10037             var after = function(){
10038                 el.fxUnwrap(wrap, r.pos, o);
10039                 st.width = r.width;
10040                 st.height = r.height;
10041                 el.afterFx(o);
10042             };
10043             // time to calc the positions
10044             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10045
10046             switch(anchor.toLowerCase()){
10047                 case "t":
10048                     wrap.setSize(b.width, 0);
10049                     st.left = st.bottom = "0";
10050                     a = {height: bh};
10051                 break;
10052                 case "l":
10053                     wrap.setSize(0, b.height);
10054                     st.right = st.top = "0";
10055                     a = {width: bw};
10056                 break;
10057                 case "r":
10058                     wrap.setSize(0, b.height);
10059                     wrap.setX(b.right);
10060                     st.left = st.top = "0";
10061                     a = {width: bw, points: pt};
10062                 break;
10063                 case "b":
10064                     wrap.setSize(b.width, 0);
10065                     wrap.setY(b.bottom);
10066                     st.left = st.top = "0";
10067                     a = {height: bh, points: pt};
10068                 break;
10069                 case "tl":
10070                     wrap.setSize(0, 0);
10071                     st.right = st.bottom = "0";
10072                     a = {width: bw, height: bh};
10073                 break;
10074                 case "bl":
10075                     wrap.setSize(0, 0);
10076                     wrap.setY(b.y+b.height);
10077                     st.right = st.top = "0";
10078                     a = {width: bw, height: bh, points: pt};
10079                 break;
10080                 case "br":
10081                     wrap.setSize(0, 0);
10082                     wrap.setXY([b.right, b.bottom]);
10083                     st.left = st.top = "0";
10084                     a = {width: bw, height: bh, points: pt};
10085                 break;
10086                 case "tr":
10087                     wrap.setSize(0, 0);
10088                     wrap.setX(b.x+b.width);
10089                     st.left = st.bottom = "0";
10090                     a = {width: bw, height: bh, points: pt};
10091                 break;
10092             }
10093             this.dom.style.visibility = "visible";
10094             wrap.show();
10095
10096             arguments.callee.anim = wrap.fxanim(a,
10097                 o,
10098                 'motion',
10099                 .5,
10100                 'easeOut', after);
10101         });
10102         return this;
10103     },
10104     
10105         /**
10106          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10107          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10108          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10109          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10110          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10111          * Usage:
10112          *<pre><code>
10113 // default: slide the element out to the top
10114 el.slideOut();
10115
10116 // custom: slide the element out to the right with a 2-second duration
10117 el.slideOut('r', { duration: 2 });
10118
10119 // common config options shown with default values
10120 el.slideOut('t', {
10121     easing: 'easeOut',
10122     duration: .5,
10123     remove: false,
10124     useDisplay: false
10125 });
10126 </code></pre>
10127          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10128          * @param {Object} options (optional) Object literal with any of the Fx config options
10129          * @return {Roo.Element} The Element
10130          */
10131     slideOut : function(anchor, o){
10132         var el = this.getFxEl();
10133         o = o || {};
10134
10135         el.queueFx(o, function(){
10136
10137             anchor = anchor || "t";
10138
10139             // restore values after effect
10140             var r = this.getFxRestore();
10141             
10142             var b = this.getBox();
10143             // fixed size for slide
10144             this.setSize(b);
10145
10146             // wrap if needed
10147             var wrap = this.fxWrap(r.pos, o, "visible");
10148
10149             var st = this.dom.style;
10150             st.visibility = "visible";
10151             st.position = "absolute";
10152
10153             wrap.setSize(b);
10154
10155             var after = function(){
10156                 if(o.useDisplay){
10157                     el.setDisplayed(false);
10158                 }else{
10159                     el.hide();
10160                 }
10161
10162                 el.fxUnwrap(wrap, r.pos, o);
10163
10164                 st.width = r.width;
10165                 st.height = r.height;
10166
10167                 el.afterFx(o);
10168             };
10169
10170             var a, zero = {to: 0};
10171             switch(anchor.toLowerCase()){
10172                 case "t":
10173                     st.left = st.bottom = "0";
10174                     a = {height: zero};
10175                 break;
10176                 case "l":
10177                     st.right = st.top = "0";
10178                     a = {width: zero};
10179                 break;
10180                 case "r":
10181                     st.left = st.top = "0";
10182                     a = {width: zero, points: {to:[b.right, b.y]}};
10183                 break;
10184                 case "b":
10185                     st.left = st.top = "0";
10186                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10187                 break;
10188                 case "tl":
10189                     st.right = st.bottom = "0";
10190                     a = {width: zero, height: zero};
10191                 break;
10192                 case "bl":
10193                     st.right = st.top = "0";
10194                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10195                 break;
10196                 case "br":
10197                     st.left = st.top = "0";
10198                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10199                 break;
10200                 case "tr":
10201                     st.left = st.bottom = "0";
10202                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10203                 break;
10204             }
10205
10206             arguments.callee.anim = wrap.fxanim(a,
10207                 o,
10208                 'motion',
10209                 .5,
10210                 "easeOut", after);
10211         });
10212         return this;
10213     },
10214
10215         /**
10216          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10217          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10218          * The element must be removed from the DOM using the 'remove' config option if desired.
10219          * Usage:
10220          *<pre><code>
10221 // default
10222 el.puff();
10223
10224 // common config options shown with default values
10225 el.puff({
10226     easing: 'easeOut',
10227     duration: .5,
10228     remove: false,
10229     useDisplay: false
10230 });
10231 </code></pre>
10232          * @param {Object} options (optional) Object literal with any of the Fx config options
10233          * @return {Roo.Element} The Element
10234          */
10235     puff : function(o){
10236         var el = this.getFxEl();
10237         o = o || {};
10238
10239         el.queueFx(o, function(){
10240             this.clearOpacity();
10241             this.show();
10242
10243             // restore values after effect
10244             var r = this.getFxRestore();
10245             var st = this.dom.style;
10246
10247             var after = function(){
10248                 if(o.useDisplay){
10249                     el.setDisplayed(false);
10250                 }else{
10251                     el.hide();
10252                 }
10253
10254                 el.clearOpacity();
10255
10256                 el.setPositioning(r.pos);
10257                 st.width = r.width;
10258                 st.height = r.height;
10259                 st.fontSize = '';
10260                 el.afterFx(o);
10261             };
10262
10263             var width = this.getWidth();
10264             var height = this.getHeight();
10265
10266             arguments.callee.anim = this.fxanim({
10267                     width : {to: this.adjustWidth(width * 2)},
10268                     height : {to: this.adjustHeight(height * 2)},
10269                     points : {by: [-(width * .5), -(height * .5)]},
10270                     opacity : {to: 0},
10271                     fontSize: {to:200, unit: "%"}
10272                 },
10273                 o,
10274                 'motion',
10275                 .5,
10276                 "easeOut", after);
10277         });
10278         return this;
10279     },
10280
10281         /**
10282          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10283          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10284          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10285          * Usage:
10286          *<pre><code>
10287 // default
10288 el.switchOff();
10289
10290 // all config options shown with default values
10291 el.switchOff({
10292     easing: 'easeIn',
10293     duration: .3,
10294     remove: false,
10295     useDisplay: false
10296 });
10297 </code></pre>
10298          * @param {Object} options (optional) Object literal with any of the Fx config options
10299          * @return {Roo.Element} The Element
10300          */
10301     switchOff : function(o){
10302         var el = this.getFxEl();
10303         o = o || {};
10304
10305         el.queueFx(o, function(){
10306             this.clearOpacity();
10307             this.clip();
10308
10309             // restore values after effect
10310             var r = this.getFxRestore();
10311             var st = this.dom.style;
10312
10313             var after = function(){
10314                 if(o.useDisplay){
10315                     el.setDisplayed(false);
10316                 }else{
10317                     el.hide();
10318                 }
10319
10320                 el.clearOpacity();
10321                 el.setPositioning(r.pos);
10322                 st.width = r.width;
10323                 st.height = r.height;
10324
10325                 el.afterFx(o);
10326             };
10327
10328             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10329                 this.clearOpacity();
10330                 (function(){
10331                     this.fxanim({
10332                         height:{to:1},
10333                         points:{by:[0, this.getHeight() * .5]}
10334                     }, o, 'motion', 0.3, 'easeIn', after);
10335                 }).defer(100, this);
10336             });
10337         });
10338         return this;
10339     },
10340
10341     /**
10342      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10343      * changed using the "attr" config option) and then fading back to the original color. If no original
10344      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10345      * Usage:
10346 <pre><code>
10347 // default: highlight background to yellow
10348 el.highlight();
10349
10350 // custom: highlight foreground text to blue for 2 seconds
10351 el.highlight("0000ff", { attr: 'color', duration: 2 });
10352
10353 // common config options shown with default values
10354 el.highlight("ffff9c", {
10355     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10356     endColor: (current color) or "ffffff",
10357     easing: 'easeIn',
10358     duration: 1
10359 });
10360 </code></pre>
10361      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10362      * @param {Object} options (optional) Object literal with any of the Fx config options
10363      * @return {Roo.Element} The Element
10364      */ 
10365     highlight : function(color, o){
10366         var el = this.getFxEl();
10367         o = o || {};
10368
10369         el.queueFx(o, function(){
10370             color = color || "ffff9c";
10371             attr = o.attr || "backgroundColor";
10372
10373             this.clearOpacity();
10374             this.show();
10375
10376             var origColor = this.getColor(attr);
10377             var restoreColor = this.dom.style[attr];
10378             endColor = (o.endColor || origColor) || "ffffff";
10379
10380             var after = function(){
10381                 el.dom.style[attr] = restoreColor;
10382                 el.afterFx(o);
10383             };
10384
10385             var a = {};
10386             a[attr] = {from: color, to: endColor};
10387             arguments.callee.anim = this.fxanim(a,
10388                 o,
10389                 'color',
10390                 1,
10391                 'easeIn', after);
10392         });
10393         return this;
10394     },
10395
10396    /**
10397     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10398     * Usage:
10399 <pre><code>
10400 // default: a single light blue ripple
10401 el.frame();
10402
10403 // custom: 3 red ripples lasting 3 seconds total
10404 el.frame("ff0000", 3, { duration: 3 });
10405
10406 // common config options shown with default values
10407 el.frame("C3DAF9", 1, {
10408     duration: 1 //duration of entire animation (not each individual ripple)
10409     // Note: Easing is not configurable and will be ignored if included
10410 });
10411 </code></pre>
10412     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10413     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10414     * @param {Object} options (optional) Object literal with any of the Fx config options
10415     * @return {Roo.Element} The Element
10416     */
10417     frame : function(color, count, o){
10418         var el = this.getFxEl();
10419         o = o || {};
10420
10421         el.queueFx(o, function(){
10422             color = color || "#C3DAF9";
10423             if(color.length == 6){
10424                 color = "#" + color;
10425             }
10426             count = count || 1;
10427             duration = o.duration || 1;
10428             this.show();
10429
10430             var b = this.getBox();
10431             var animFn = function(){
10432                 var proxy = this.createProxy({
10433
10434                      style:{
10435                         visbility:"hidden",
10436                         position:"absolute",
10437                         "z-index":"35000", // yee haw
10438                         border:"0px solid " + color
10439                      }
10440                   });
10441                 var scale = Roo.isBorderBox ? 2 : 1;
10442                 proxy.animate({
10443                     top:{from:b.y, to:b.y - 20},
10444                     left:{from:b.x, to:b.x - 20},
10445                     borderWidth:{from:0, to:10},
10446                     opacity:{from:1, to:0},
10447                     height:{from:b.height, to:(b.height + (20*scale))},
10448                     width:{from:b.width, to:(b.width + (20*scale))}
10449                 }, duration, function(){
10450                     proxy.remove();
10451                 });
10452                 if(--count > 0){
10453                      animFn.defer((duration/2)*1000, this);
10454                 }else{
10455                     el.afterFx(o);
10456                 }
10457             };
10458             animFn.call(this);
10459         });
10460         return this;
10461     },
10462
10463    /**
10464     * Creates a pause before any subsequent queued effects begin.  If there are
10465     * no effects queued after the pause it will have no effect.
10466     * Usage:
10467 <pre><code>
10468 el.pause(1);
10469 </code></pre>
10470     * @param {Number} seconds The length of time to pause (in seconds)
10471     * @return {Roo.Element} The Element
10472     */
10473     pause : function(seconds){
10474         var el = this.getFxEl();
10475         var o = {};
10476
10477         el.queueFx(o, function(){
10478             setTimeout(function(){
10479                 el.afterFx(o);
10480             }, seconds * 1000);
10481         });
10482         return this;
10483     },
10484
10485    /**
10486     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10487     * using the "endOpacity" config option.
10488     * Usage:
10489 <pre><code>
10490 // default: fade in from opacity 0 to 100%
10491 el.fadeIn();
10492
10493 // custom: fade in from opacity 0 to 75% over 2 seconds
10494 el.fadeIn({ endOpacity: .75, duration: 2});
10495
10496 // common config options shown with default values
10497 el.fadeIn({
10498     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10499     easing: 'easeOut',
10500     duration: .5
10501 });
10502 </code></pre>
10503     * @param {Object} options (optional) Object literal with any of the Fx config options
10504     * @return {Roo.Element} The Element
10505     */
10506     fadeIn : function(o){
10507         var el = this.getFxEl();
10508         o = o || {};
10509         el.queueFx(o, function(){
10510             this.setOpacity(0);
10511             this.fixDisplay();
10512             this.dom.style.visibility = 'visible';
10513             var to = o.endOpacity || 1;
10514             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10515                 o, null, .5, "easeOut", function(){
10516                 if(to == 1){
10517                     this.clearOpacity();
10518                 }
10519                 el.afterFx(o);
10520             });
10521         });
10522         return this;
10523     },
10524
10525    /**
10526     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10527     * using the "endOpacity" config option.
10528     * Usage:
10529 <pre><code>
10530 // default: fade out from the element's current opacity to 0
10531 el.fadeOut();
10532
10533 // custom: fade out from the element's current opacity to 25% over 2 seconds
10534 el.fadeOut({ endOpacity: .25, duration: 2});
10535
10536 // common config options shown with default values
10537 el.fadeOut({
10538     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10539     easing: 'easeOut',
10540     duration: .5
10541     remove: false,
10542     useDisplay: false
10543 });
10544 </code></pre>
10545     * @param {Object} options (optional) Object literal with any of the Fx config options
10546     * @return {Roo.Element} The Element
10547     */
10548     fadeOut : function(o){
10549         var el = this.getFxEl();
10550         o = o || {};
10551         el.queueFx(o, function(){
10552             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10553                 o, null, .5, "easeOut", function(){
10554                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10555                      this.dom.style.display = "none";
10556                 }else{
10557                      this.dom.style.visibility = "hidden";
10558                 }
10559                 this.clearOpacity();
10560                 el.afterFx(o);
10561             });
10562         });
10563         return this;
10564     },
10565
10566    /**
10567     * Animates the transition of an element's dimensions from a starting height/width
10568     * to an ending height/width.
10569     * Usage:
10570 <pre><code>
10571 // change height and width to 100x100 pixels
10572 el.scale(100, 100);
10573
10574 // common config options shown with default values.  The height and width will default to
10575 // the element's existing values if passed as null.
10576 el.scale(
10577     [element's width],
10578     [element's height], {
10579     easing: 'easeOut',
10580     duration: .35
10581 });
10582 </code></pre>
10583     * @param {Number} width  The new width (pass undefined to keep the original width)
10584     * @param {Number} height  The new height (pass undefined to keep the original height)
10585     * @param {Object} options (optional) Object literal with any of the Fx config options
10586     * @return {Roo.Element} The Element
10587     */
10588     scale : function(w, h, o){
10589         this.shift(Roo.apply({}, o, {
10590             width: w,
10591             height: h
10592         }));
10593         return this;
10594     },
10595
10596    /**
10597     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10598     * Any of these properties not specified in the config object will not be changed.  This effect 
10599     * requires that at least one new dimension, position or opacity setting must be passed in on
10600     * the config object in order for the function to have any effect.
10601     * Usage:
10602 <pre><code>
10603 // slide the element horizontally to x position 200 while changing the height and opacity
10604 el.shift({ x: 200, height: 50, opacity: .8 });
10605
10606 // common config options shown with default values.
10607 el.shift({
10608     width: [element's width],
10609     height: [element's height],
10610     x: [element's x position],
10611     y: [element's y position],
10612     opacity: [element's opacity],
10613     easing: 'easeOut',
10614     duration: .35
10615 });
10616 </code></pre>
10617     * @param {Object} options  Object literal with any of the Fx config options
10618     * @return {Roo.Element} The Element
10619     */
10620     shift : function(o){
10621         var el = this.getFxEl();
10622         o = o || {};
10623         el.queueFx(o, function(){
10624             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10625             if(w !== undefined){
10626                 a.width = {to: this.adjustWidth(w)};
10627             }
10628             if(h !== undefined){
10629                 a.height = {to: this.adjustHeight(h)};
10630             }
10631             if(x !== undefined || y !== undefined){
10632                 a.points = {to: [
10633                     x !== undefined ? x : this.getX(),
10634                     y !== undefined ? y : this.getY()
10635                 ]};
10636             }
10637             if(op !== undefined){
10638                 a.opacity = {to: op};
10639             }
10640             if(o.xy !== undefined){
10641                 a.points = {to: o.xy};
10642             }
10643             arguments.callee.anim = this.fxanim(a,
10644                 o, 'motion', .35, "easeOut", function(){
10645                 el.afterFx(o);
10646             });
10647         });
10648         return this;
10649     },
10650
10651         /**
10652          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10653          * ending point of the effect.
10654          * Usage:
10655          *<pre><code>
10656 // default: slide the element downward while fading out
10657 el.ghost();
10658
10659 // custom: slide the element out to the right with a 2-second duration
10660 el.ghost('r', { duration: 2 });
10661
10662 // common config options shown with default values
10663 el.ghost('b', {
10664     easing: 'easeOut',
10665     duration: .5
10666     remove: false,
10667     useDisplay: false
10668 });
10669 </code></pre>
10670          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10671          * @param {Object} options (optional) Object literal with any of the Fx config options
10672          * @return {Roo.Element} The Element
10673          */
10674     ghost : function(anchor, o){
10675         var el = this.getFxEl();
10676         o = o || {};
10677
10678         el.queueFx(o, function(){
10679             anchor = anchor || "b";
10680
10681             // restore values after effect
10682             var r = this.getFxRestore();
10683             var w = this.getWidth(),
10684                 h = this.getHeight();
10685
10686             var st = this.dom.style;
10687
10688             var after = function(){
10689                 if(o.useDisplay){
10690                     el.setDisplayed(false);
10691                 }else{
10692                     el.hide();
10693                 }
10694
10695                 el.clearOpacity();
10696                 el.setPositioning(r.pos);
10697                 st.width = r.width;
10698                 st.height = r.height;
10699
10700                 el.afterFx(o);
10701             };
10702
10703             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10704             switch(anchor.toLowerCase()){
10705                 case "t":
10706                     pt.by = [0, -h];
10707                 break;
10708                 case "l":
10709                     pt.by = [-w, 0];
10710                 break;
10711                 case "r":
10712                     pt.by = [w, 0];
10713                 break;
10714                 case "b":
10715                     pt.by = [0, h];
10716                 break;
10717                 case "tl":
10718                     pt.by = [-w, -h];
10719                 break;
10720                 case "bl":
10721                     pt.by = [-w, h];
10722                 break;
10723                 case "br":
10724                     pt.by = [w, h];
10725                 break;
10726                 case "tr":
10727                     pt.by = [w, -h];
10728                 break;
10729             }
10730
10731             arguments.callee.anim = this.fxanim(a,
10732                 o,
10733                 'motion',
10734                 .5,
10735                 "easeOut", after);
10736         });
10737         return this;
10738     },
10739
10740         /**
10741          * Ensures that all effects queued after syncFx is called on the element are
10742          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10743          * @return {Roo.Element} The Element
10744          */
10745     syncFx : function(){
10746         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10747             block : false,
10748             concurrent : true,
10749             stopFx : false
10750         });
10751         return this;
10752     },
10753
10754         /**
10755          * Ensures that all effects queued after sequenceFx is called on the element are
10756          * run in sequence.  This is the opposite of {@link #syncFx}.
10757          * @return {Roo.Element} The Element
10758          */
10759     sequenceFx : function(){
10760         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10761             block : false,
10762             concurrent : false,
10763             stopFx : false
10764         });
10765         return this;
10766     },
10767
10768         /* @private */
10769     nextFx : function(){
10770         var ef = this.fxQueue[0];
10771         if(ef){
10772             ef.call(this);
10773         }
10774     },
10775
10776         /**
10777          * Returns true if the element has any effects actively running or queued, else returns false.
10778          * @return {Boolean} True if element has active effects, else false
10779          */
10780     hasActiveFx : function(){
10781         return this.fxQueue && this.fxQueue[0];
10782     },
10783
10784         /**
10785          * Stops any running effects and clears the element's internal effects queue if it contains
10786          * any additional effects that haven't started yet.
10787          * @return {Roo.Element} The Element
10788          */
10789     stopFx : function(){
10790         if(this.hasActiveFx()){
10791             var cur = this.fxQueue[0];
10792             if(cur && cur.anim && cur.anim.isAnimated()){
10793                 this.fxQueue = [cur]; // clear out others
10794                 cur.anim.stop(true);
10795             }
10796         }
10797         return this;
10798     },
10799
10800         /* @private */
10801     beforeFx : function(o){
10802         if(this.hasActiveFx() && !o.concurrent){
10803            if(o.stopFx){
10804                this.stopFx();
10805                return true;
10806            }
10807            return false;
10808         }
10809         return true;
10810     },
10811
10812         /**
10813          * Returns true if the element is currently blocking so that no other effect can be queued
10814          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10815          * used to ensure that an effect initiated by a user action runs to completion prior to the
10816          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10817          * @return {Boolean} True if blocking, else false
10818          */
10819     hasFxBlock : function(){
10820         var q = this.fxQueue;
10821         return q && q[0] && q[0].block;
10822     },
10823
10824         /* @private */
10825     queueFx : function(o, fn){
10826         if(!this.fxQueue){
10827             this.fxQueue = [];
10828         }
10829         if(!this.hasFxBlock()){
10830             Roo.applyIf(o, this.fxDefaults);
10831             if(!o.concurrent){
10832                 var run = this.beforeFx(o);
10833                 fn.block = o.block;
10834                 this.fxQueue.push(fn);
10835                 if(run){
10836                     this.nextFx();
10837                 }
10838             }else{
10839                 fn.call(this);
10840             }
10841         }
10842         return this;
10843     },
10844
10845         /* @private */
10846     fxWrap : function(pos, o, vis){
10847         var wrap;
10848         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10849             var wrapXY;
10850             if(o.fixPosition){
10851                 wrapXY = this.getXY();
10852             }
10853             var div = document.createElement("div");
10854             div.style.visibility = vis;
10855             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10856             wrap.setPositioning(pos);
10857             if(wrap.getStyle("position") == "static"){
10858                 wrap.position("relative");
10859             }
10860             this.clearPositioning('auto');
10861             wrap.clip();
10862             wrap.dom.appendChild(this.dom);
10863             if(wrapXY){
10864                 wrap.setXY(wrapXY);
10865             }
10866         }
10867         return wrap;
10868     },
10869
10870         /* @private */
10871     fxUnwrap : function(wrap, pos, o){
10872         this.clearPositioning();
10873         this.setPositioning(pos);
10874         if(!o.wrap){
10875             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10876             wrap.remove();
10877         }
10878     },
10879
10880         /* @private */
10881     getFxRestore : function(){
10882         var st = this.dom.style;
10883         return {pos: this.getPositioning(), width: st.width, height : st.height};
10884     },
10885
10886         /* @private */
10887     afterFx : function(o){
10888         if(o.afterStyle){
10889             this.applyStyles(o.afterStyle);
10890         }
10891         if(o.afterCls){
10892             this.addClass(o.afterCls);
10893         }
10894         if(o.remove === true){
10895             this.remove();
10896         }
10897         Roo.callback(o.callback, o.scope, [this]);
10898         if(!o.concurrent){
10899             this.fxQueue.shift();
10900             this.nextFx();
10901         }
10902     },
10903
10904         /* @private */
10905     getFxEl : function(){ // support for composite element fx
10906         return Roo.get(this.dom);
10907     },
10908
10909         /* @private */
10910     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10911         animType = animType || 'run';
10912         opt = opt || {};
10913         var anim = Roo.lib.Anim[animType](
10914             this.dom, args,
10915             (opt.duration || defaultDur) || .35,
10916             (opt.easing || defaultEase) || 'easeOut',
10917             function(){
10918                 Roo.callback(cb, this);
10919             },
10920             this
10921         );
10922         opt.anim = anim;
10923         return anim;
10924     }
10925 };
10926
10927 // backwords compat
10928 Roo.Fx.resize = Roo.Fx.scale;
10929
10930 //When included, Roo.Fx is automatically applied to Element so that all basic
10931 //effects are available directly via the Element API
10932 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10933  * Based on:
10934  * Ext JS Library 1.1.1
10935  * Copyright(c) 2006-2007, Ext JS, LLC.
10936  *
10937  * Originally Released Under LGPL - original licence link has changed is not relivant.
10938  *
10939  * Fork - LGPL
10940  * <script type="text/javascript">
10941  */
10942
10943
10944 /**
10945  * @class Roo.CompositeElement
10946  * Standard composite class. Creates a Roo.Element for every element in the collection.
10947  * <br><br>
10948  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10949  * actions will be performed on all the elements in this collection.</b>
10950  * <br><br>
10951  * All methods return <i>this</i> and can be chained.
10952  <pre><code>
10953  var els = Roo.select("#some-el div.some-class", true);
10954  // or select directly from an existing element
10955  var el = Roo.get('some-el');
10956  el.select('div.some-class', true);
10957
10958  els.setWidth(100); // all elements become 100 width
10959  els.hide(true); // all elements fade out and hide
10960  // or
10961  els.setWidth(100).hide(true);
10962  </code></pre>
10963  */
10964 Roo.CompositeElement = function(els){
10965     this.elements = [];
10966     this.addElements(els);
10967 };
10968 Roo.CompositeElement.prototype = {
10969     isComposite: true,
10970     addElements : function(els){
10971         if(!els) return this;
10972         if(typeof els == "string"){
10973             els = Roo.Element.selectorFunction(els);
10974         }
10975         var yels = this.elements;
10976         var index = yels.length-1;
10977         for(var i = 0, len = els.length; i < len; i++) {
10978                 yels[++index] = Roo.get(els[i]);
10979         }
10980         return this;
10981     },
10982
10983     /**
10984     * Clears this composite and adds the elements returned by the passed selector.
10985     * @param {String/Array} els A string CSS selector, an array of elements or an element
10986     * @return {CompositeElement} this
10987     */
10988     fill : function(els){
10989         this.elements = [];
10990         this.add(els);
10991         return this;
10992     },
10993
10994     /**
10995     * Filters this composite to only elements that match the passed selector.
10996     * @param {String} selector A string CSS selector
10997     * @param {Boolean} inverse return inverse filter (not matches)
10998     * @return {CompositeElement} this
10999     */
11000     filter : function(selector, inverse){
11001         var els = [];
11002         inverse = inverse || false;
11003         this.each(function(el){
11004             var match = inverse ? !el.is(selector) : el.is(selector);
11005             if(match){
11006                 els[els.length] = el.dom;
11007             }
11008         });
11009         this.fill(els);
11010         return this;
11011     },
11012
11013     invoke : function(fn, args){
11014         var els = this.elements;
11015         for(var i = 0, len = els.length; i < len; i++) {
11016                 Roo.Element.prototype[fn].apply(els[i], args);
11017         }
11018         return this;
11019     },
11020     /**
11021     * Adds elements to this composite.
11022     * @param {String/Array} els A string CSS selector, an array of elements or an element
11023     * @return {CompositeElement} this
11024     */
11025     add : function(els){
11026         if(typeof els == "string"){
11027             this.addElements(Roo.Element.selectorFunction(els));
11028         }else if(els.length !== undefined){
11029             this.addElements(els);
11030         }else{
11031             this.addElements([els]);
11032         }
11033         return this;
11034     },
11035     /**
11036     * Calls the passed function passing (el, this, index) for each element in this composite.
11037     * @param {Function} fn The function to call
11038     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11039     * @return {CompositeElement} this
11040     */
11041     each : function(fn, scope){
11042         var els = this.elements;
11043         for(var i = 0, len = els.length; i < len; i++){
11044             if(fn.call(scope || els[i], els[i], this, i) === false) {
11045                 break;
11046             }
11047         }
11048         return this;
11049     },
11050
11051     /**
11052      * Returns the Element object at the specified index
11053      * @param {Number} index
11054      * @return {Roo.Element}
11055      */
11056     item : function(index){
11057         return this.elements[index] || null;
11058     },
11059
11060     /**
11061      * Returns the first Element
11062      * @return {Roo.Element}
11063      */
11064     first : function(){
11065         return this.item(0);
11066     },
11067
11068     /**
11069      * Returns the last Element
11070      * @return {Roo.Element}
11071      */
11072     last : function(){
11073         return this.item(this.elements.length-1);
11074     },
11075
11076     /**
11077      * Returns the number of elements in this composite
11078      * @return Number
11079      */
11080     getCount : function(){
11081         return this.elements.length;
11082     },
11083
11084     /**
11085      * Returns true if this composite contains the passed element
11086      * @return Boolean
11087      */
11088     contains : function(el){
11089         return this.indexOf(el) !== -1;
11090     },
11091
11092     /**
11093      * Returns true if this composite contains the passed element
11094      * @return Boolean
11095      */
11096     indexOf : function(el){
11097         return this.elements.indexOf(Roo.get(el));
11098     },
11099
11100
11101     /**
11102     * Removes the specified element(s).
11103     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11104     * or an array of any of those.
11105     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11106     * @return {CompositeElement} this
11107     */
11108     removeElement : function(el, removeDom){
11109         if(el instanceof Array){
11110             for(var i = 0, len = el.length; i < len; i++){
11111                 this.removeElement(el[i]);
11112             }
11113             return this;
11114         }
11115         var index = typeof el == 'number' ? el : this.indexOf(el);
11116         if(index !== -1){
11117             if(removeDom){
11118                 var d = this.elements[index];
11119                 if(d.dom){
11120                     d.remove();
11121                 }else{
11122                     d.parentNode.removeChild(d);
11123                 }
11124             }
11125             this.elements.splice(index, 1);
11126         }
11127         return this;
11128     },
11129
11130     /**
11131     * Replaces the specified element with the passed element.
11132     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11133     * to replace.
11134     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11135     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11136     * @return {CompositeElement} this
11137     */
11138     replaceElement : function(el, replacement, domReplace){
11139         var index = typeof el == 'number' ? el : this.indexOf(el);
11140         if(index !== -1){
11141             if(domReplace){
11142                 this.elements[index].replaceWith(replacement);
11143             }else{
11144                 this.elements.splice(index, 1, Roo.get(replacement))
11145             }
11146         }
11147         return this;
11148     },
11149
11150     /**
11151      * Removes all elements.
11152      */
11153     clear : function(){
11154         this.elements = [];
11155     }
11156 };
11157 (function(){
11158     Roo.CompositeElement.createCall = function(proto, fnName){
11159         if(!proto[fnName]){
11160             proto[fnName] = function(){
11161                 return this.invoke(fnName, arguments);
11162             };
11163         }
11164     };
11165     for(var fnName in Roo.Element.prototype){
11166         if(typeof Roo.Element.prototype[fnName] == "function"){
11167             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11168         }
11169     };
11170 })();
11171 /*
11172  * Based on:
11173  * Ext JS Library 1.1.1
11174  * Copyright(c) 2006-2007, Ext JS, LLC.
11175  *
11176  * Originally Released Under LGPL - original licence link has changed is not relivant.
11177  *
11178  * Fork - LGPL
11179  * <script type="text/javascript">
11180  */
11181
11182 /**
11183  * @class Roo.CompositeElementLite
11184  * @extends Roo.CompositeElement
11185  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11186  <pre><code>
11187  var els = Roo.select("#some-el div.some-class");
11188  // or select directly from an existing element
11189  var el = Roo.get('some-el');
11190  el.select('div.some-class');
11191
11192  els.setWidth(100); // all elements become 100 width
11193  els.hide(true); // all elements fade out and hide
11194  // or
11195  els.setWidth(100).hide(true);
11196  </code></pre><br><br>
11197  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11198  * actions will be performed on all the elements in this collection.</b>
11199  */
11200 Roo.CompositeElementLite = function(els){
11201     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11202     this.el = new Roo.Element.Flyweight();
11203 };
11204 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11205     addElements : function(els){
11206         if(els){
11207             if(els instanceof Array){
11208                 this.elements = this.elements.concat(els);
11209             }else{
11210                 var yels = this.elements;
11211                 var index = yels.length-1;
11212                 for(var i = 0, len = els.length; i < len; i++) {
11213                     yels[++index] = els[i];
11214                 }
11215             }
11216         }
11217         return this;
11218     },
11219     invoke : function(fn, args){
11220         var els = this.elements;
11221         var el = this.el;
11222         for(var i = 0, len = els.length; i < len; i++) {
11223             el.dom = els[i];
11224                 Roo.Element.prototype[fn].apply(el, args);
11225         }
11226         return this;
11227     },
11228     /**
11229      * Returns a flyweight Element of the dom element object at the specified index
11230      * @param {Number} index
11231      * @return {Roo.Element}
11232      */
11233     item : function(index){
11234         if(!this.elements[index]){
11235             return null;
11236         }
11237         this.el.dom = this.elements[index];
11238         return this.el;
11239     },
11240
11241     // fixes scope with flyweight
11242     addListener : function(eventName, handler, scope, opt){
11243         var els = this.elements;
11244         for(var i = 0, len = els.length; i < len; i++) {
11245             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11246         }
11247         return this;
11248     },
11249
11250     /**
11251     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11252     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11253     * a reference to the dom node, use el.dom.</b>
11254     * @param {Function} fn The function to call
11255     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11256     * @return {CompositeElement} this
11257     */
11258     each : function(fn, scope){
11259         var els = this.elements;
11260         var el = this.el;
11261         for(var i = 0, len = els.length; i < len; i++){
11262             el.dom = els[i];
11263                 if(fn.call(scope || el, el, this, i) === false){
11264                 break;
11265             }
11266         }
11267         return this;
11268     },
11269
11270     indexOf : function(el){
11271         return this.elements.indexOf(Roo.getDom(el));
11272     },
11273
11274     replaceElement : function(el, replacement, domReplace){
11275         var index = typeof el == 'number' ? el : this.indexOf(el);
11276         if(index !== -1){
11277             replacement = Roo.getDom(replacement);
11278             if(domReplace){
11279                 var d = this.elements[index];
11280                 d.parentNode.insertBefore(replacement, d);
11281                 d.parentNode.removeChild(d);
11282             }
11283             this.elements.splice(index, 1, replacement);
11284         }
11285         return this;
11286     }
11287 });
11288 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11289
11290 /*
11291  * Based on:
11292  * Ext JS Library 1.1.1
11293  * Copyright(c) 2006-2007, Ext JS, LLC.
11294  *
11295  * Originally Released Under LGPL - original licence link has changed is not relivant.
11296  *
11297  * Fork - LGPL
11298  * <script type="text/javascript">
11299  */
11300
11301  
11302
11303 /**
11304  * @class Roo.data.Connection
11305  * @extends Roo.util.Observable
11306  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11307  * either to a configured URL, or to a URL specified at request time.<br><br>
11308  * <p>
11309  * Requests made by this class are asynchronous, and will return immediately. No data from
11310  * the server will be available to the statement immediately following the {@link #request} call.
11311  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11312  * <p>
11313  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11314  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11315  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11316  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11317  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11318  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11319  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11320  * standard DOM methods.
11321  * @constructor
11322  * @param {Object} config a configuration object.
11323  */
11324 Roo.data.Connection = function(config){
11325     Roo.apply(this, config);
11326     this.addEvents({
11327         /**
11328          * @event beforerequest
11329          * Fires before a network request is made to retrieve a data object.
11330          * @param {Connection} conn This Connection object.
11331          * @param {Object} options The options config object passed to the {@link #request} method.
11332          */
11333         "beforerequest" : true,
11334         /**
11335          * @event requestcomplete
11336          * Fires if the request was successfully completed.
11337          * @param {Connection} conn This Connection object.
11338          * @param {Object} response The XHR object containing the response data.
11339          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11340          * @param {Object} options The options config object passed to the {@link #request} method.
11341          */
11342         "requestcomplete" : true,
11343         /**
11344          * @event requestexception
11345          * Fires if an error HTTP status was returned from the server.
11346          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11347          * @param {Connection} conn This Connection object.
11348          * @param {Object} response The XHR object containing the response data.
11349          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11350          * @param {Object} options The options config object passed to the {@link #request} method.
11351          */
11352         "requestexception" : true
11353     });
11354     Roo.data.Connection.superclass.constructor.call(this);
11355 };
11356
11357 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11358     /**
11359      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11360      */
11361     /**
11362      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11363      * extra parameters to each request made by this object. (defaults to undefined)
11364      */
11365     /**
11366      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11367      *  to each request made by this object. (defaults to undefined)
11368      */
11369     /**
11370      * @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)
11371      */
11372     /**
11373      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11374      */
11375     timeout : 30000,
11376     /**
11377      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11378      * @type Boolean
11379      */
11380     autoAbort:false,
11381
11382     /**
11383      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11384      * @type Boolean
11385      */
11386     disableCaching: true,
11387
11388     /**
11389      * Sends an HTTP request to a remote server.
11390      * @param {Object} options An object which may contain the following properties:<ul>
11391      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11392      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11393      * request, a url encoded string or a function to call to get either.</li>
11394      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11395      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11396      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11397      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11398      * <li>options {Object} The parameter to the request call.</li>
11399      * <li>success {Boolean} True if the request succeeded.</li>
11400      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11401      * </ul></li>
11402      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11403      * The callback is passed the following parameters:<ul>
11404      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11405      * <li>options {Object} The parameter to the request call.</li>
11406      * </ul></li>
11407      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11408      * The callback is passed the following parameters:<ul>
11409      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11410      * <li>options {Object} The parameter to the request call.</li>
11411      * </ul></li>
11412      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11413      * for the callback function. Defaults to the browser window.</li>
11414      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11415      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11416      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11417      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11418      * params for the post data. Any params will be appended to the URL.</li>
11419      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11420      * </ul>
11421      * @return {Number} transactionId
11422      */
11423     request : function(o){
11424         if(this.fireEvent("beforerequest", this, o) !== false){
11425             var p = o.params;
11426
11427             if(typeof p == "function"){
11428                 p = p.call(o.scope||window, o);
11429             }
11430             if(typeof p == "object"){
11431                 p = Roo.urlEncode(o.params);
11432             }
11433             if(this.extraParams){
11434                 var extras = Roo.urlEncode(this.extraParams);
11435                 p = p ? (p + '&' + extras) : extras;
11436             }
11437
11438             var url = o.url || this.url;
11439             if(typeof url == 'function'){
11440                 url = url.call(o.scope||window, o);
11441             }
11442
11443             if(o.form){
11444                 var form = Roo.getDom(o.form);
11445                 url = url || form.action;
11446
11447                 var enctype = form.getAttribute("enctype");
11448                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11449                     return this.doFormUpload(o, p, url);
11450                 }
11451                 var f = Roo.lib.Ajax.serializeForm(form);
11452                 p = p ? (p + '&' + f) : f;
11453             }
11454
11455             var hs = o.headers;
11456             if(this.defaultHeaders){
11457                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11458                 if(!o.headers){
11459                     o.headers = hs;
11460                 }
11461             }
11462
11463             var cb = {
11464                 success: this.handleResponse,
11465                 failure: this.handleFailure,
11466                 scope: this,
11467                 argument: {options: o},
11468                 timeout : o.timeout || this.timeout
11469             };
11470
11471             var method = o.method||this.method||(p ? "POST" : "GET");
11472
11473             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11474                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11475             }
11476
11477             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11478                 if(o.autoAbort){
11479                     this.abort();
11480                 }
11481             }else if(this.autoAbort !== false){
11482                 this.abort();
11483             }
11484
11485             if((method == 'GET' && p) || o.xmlData){
11486                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11487                 p = '';
11488             }
11489             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11490             return this.transId;
11491         }else{
11492             Roo.callback(o.callback, o.scope, [o, null, null]);
11493             return null;
11494         }
11495     },
11496
11497     /**
11498      * Determine whether this object has a request outstanding.
11499      * @param {Number} transactionId (Optional) defaults to the last transaction
11500      * @return {Boolean} True if there is an outstanding request.
11501      */
11502     isLoading : function(transId){
11503         if(transId){
11504             return Roo.lib.Ajax.isCallInProgress(transId);
11505         }else{
11506             return this.transId ? true : false;
11507         }
11508     },
11509
11510     /**
11511      * Aborts any outstanding request.
11512      * @param {Number} transactionId (Optional) defaults to the last transaction
11513      */
11514     abort : function(transId){
11515         if(transId || this.isLoading()){
11516             Roo.lib.Ajax.abort(transId || this.transId);
11517         }
11518     },
11519
11520     // private
11521     handleResponse : function(response){
11522         this.transId = false;
11523         var options = response.argument.options;
11524         response.argument = options ? options.argument : null;
11525         this.fireEvent("requestcomplete", this, response, options);
11526         Roo.callback(options.success, options.scope, [response, options]);
11527         Roo.callback(options.callback, options.scope, [options, true, response]);
11528     },
11529
11530     // private
11531     handleFailure : function(response, e){
11532         this.transId = false;
11533         var options = response.argument.options;
11534         response.argument = options ? options.argument : null;
11535         this.fireEvent("requestexception", this, response, options, e);
11536         Roo.callback(options.failure, options.scope, [response, options]);
11537         Roo.callback(options.callback, options.scope, [options, false, response]);
11538     },
11539
11540     // private
11541     doFormUpload : function(o, ps, url){
11542         var id = Roo.id();
11543         var frame = document.createElement('iframe');
11544         frame.id = id;
11545         frame.name = id;
11546         frame.className = 'x-hidden';
11547         if(Roo.isIE){
11548             frame.src = Roo.SSL_SECURE_URL;
11549         }
11550         document.body.appendChild(frame);
11551
11552         if(Roo.isIE){
11553            document.frames[id].name = id;
11554         }
11555
11556         var form = Roo.getDom(o.form);
11557         form.target = id;
11558         form.method = 'POST';
11559         form.enctype = form.encoding = 'multipart/form-data';
11560         if(url){
11561             form.action = url;
11562         }
11563
11564         var hiddens, hd;
11565         if(ps){ // add dynamic params
11566             hiddens = [];
11567             ps = Roo.urlDecode(ps, false);
11568             for(var k in ps){
11569                 if(ps.hasOwnProperty(k)){
11570                     hd = document.createElement('input');
11571                     hd.type = 'hidden';
11572                     hd.name = k;
11573                     hd.value = ps[k];
11574                     form.appendChild(hd);
11575                     hiddens.push(hd);
11576                 }
11577             }
11578         }
11579
11580         function cb(){
11581             var r = {  // bogus response object
11582                 responseText : '',
11583                 responseXML : null
11584             };
11585
11586             r.argument = o ? o.argument : null;
11587
11588             try { //
11589                 var doc;
11590                 if(Roo.isIE){
11591                     doc = frame.contentWindow.document;
11592                 }else {
11593                     doc = (frame.contentDocument || window.frames[id].document);
11594                 }
11595                 if(doc && doc.body){
11596                     r.responseText = doc.body.innerHTML;
11597                 }
11598                 if(doc && doc.XMLDocument){
11599                     r.responseXML = doc.XMLDocument;
11600                 }else {
11601                     r.responseXML = doc;
11602                 }
11603             }
11604             catch(e) {
11605                 // ignore
11606             }
11607
11608             Roo.EventManager.removeListener(frame, 'load', cb, this);
11609
11610             this.fireEvent("requestcomplete", this, r, o);
11611             Roo.callback(o.success, o.scope, [r, o]);
11612             Roo.callback(o.callback, o.scope, [o, true, r]);
11613
11614             setTimeout(function(){document.body.removeChild(frame);}, 100);
11615         }
11616
11617         Roo.EventManager.on(frame, 'load', cb, this);
11618         form.submit();
11619
11620         if(hiddens){ // remove dynamic params
11621             for(var i = 0, len = hiddens.length; i < len; i++){
11622                 form.removeChild(hiddens[i]);
11623             }
11624         }
11625     }
11626 });
11627 /*
11628  * Based on:
11629  * Ext JS Library 1.1.1
11630  * Copyright(c) 2006-2007, Ext JS, LLC.
11631  *
11632  * Originally Released Under LGPL - original licence link has changed is not relivant.
11633  *
11634  * Fork - LGPL
11635  * <script type="text/javascript">
11636  */
11637  
11638 /**
11639  * Global Ajax request class.
11640  * 
11641  * @class Roo.Ajax
11642  * @extends Roo.data.Connection
11643  * @static
11644  * 
11645  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11646  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11647  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11648  * @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)
11649  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11650  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11651  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11652  */
11653 Roo.Ajax = new Roo.data.Connection({
11654     // fix up the docs
11655     /**
11656      * @scope Roo.Ajax
11657      * @type {Boolear} 
11658      */
11659     autoAbort : false,
11660
11661     /**
11662      * Serialize the passed form into a url encoded string
11663      * @scope Roo.Ajax
11664      * @param {String/HTMLElement} form
11665      * @return {String}
11666      */
11667     serializeForm : function(form){
11668         return Roo.lib.Ajax.serializeForm(form);
11669     }
11670 });/*
11671  * Based on:
11672  * Ext JS Library 1.1.1
11673  * Copyright(c) 2006-2007, Ext JS, LLC.
11674  *
11675  * Originally Released Under LGPL - original licence link has changed is not relivant.
11676  *
11677  * Fork - LGPL
11678  * <script type="text/javascript">
11679  */
11680
11681  
11682 /**
11683  * @class Roo.UpdateManager
11684  * @extends Roo.util.Observable
11685  * Provides AJAX-style update for Element object.<br><br>
11686  * Usage:<br>
11687  * <pre><code>
11688  * // Get it from a Roo.Element object
11689  * var el = Roo.get("foo");
11690  * var mgr = el.getUpdateManager();
11691  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11692  * ...
11693  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11694  * <br>
11695  * // or directly (returns the same UpdateManager instance)
11696  * var mgr = new Roo.UpdateManager("myElementId");
11697  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11698  * mgr.on("update", myFcnNeedsToKnow);
11699  * <br>
11700    // short handed call directly from the element object
11701    Roo.get("foo").load({
11702         url: "bar.php",
11703         scripts:true,
11704         params: "for=bar",
11705         text: "Loading Foo..."
11706    });
11707  * </code></pre>
11708  * @constructor
11709  * Create new UpdateManager directly.
11710  * @param {String/HTMLElement/Roo.Element} el The element to update
11711  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11712  */
11713 Roo.UpdateManager = function(el, forceNew){
11714     el = Roo.get(el);
11715     if(!forceNew && el.updateManager){
11716         return el.updateManager;
11717     }
11718     /**
11719      * The Element object
11720      * @type Roo.Element
11721      */
11722     this.el = el;
11723     /**
11724      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11725      * @type String
11726      */
11727     this.defaultUrl = null;
11728
11729     this.addEvents({
11730         /**
11731          * @event beforeupdate
11732          * Fired before an update is made, return false from your handler and the update is cancelled.
11733          * @param {Roo.Element} el
11734          * @param {String/Object/Function} url
11735          * @param {String/Object} params
11736          */
11737         "beforeupdate": true,
11738         /**
11739          * @event update
11740          * Fired after successful update is made.
11741          * @param {Roo.Element} el
11742          * @param {Object} oResponseObject The response Object
11743          */
11744         "update": true,
11745         /**
11746          * @event failure
11747          * Fired on update failure.
11748          * @param {Roo.Element} el
11749          * @param {Object} oResponseObject The response Object
11750          */
11751         "failure": true
11752     });
11753     var d = Roo.UpdateManager.defaults;
11754     /**
11755      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11756      * @type String
11757      */
11758     this.sslBlankUrl = d.sslBlankUrl;
11759     /**
11760      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11761      * @type Boolean
11762      */
11763     this.disableCaching = d.disableCaching;
11764     /**
11765      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11766      * @type String
11767      */
11768     this.indicatorText = d.indicatorText;
11769     /**
11770      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11771      * @type String
11772      */
11773     this.showLoadIndicator = d.showLoadIndicator;
11774     /**
11775      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11776      * @type Number
11777      */
11778     this.timeout = d.timeout;
11779
11780     /**
11781      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11782      * @type Boolean
11783      */
11784     this.loadScripts = d.loadScripts;
11785
11786     /**
11787      * Transaction object of current executing transaction
11788      */
11789     this.transaction = null;
11790
11791     /**
11792      * @private
11793      */
11794     this.autoRefreshProcId = null;
11795     /**
11796      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11797      * @type Function
11798      */
11799     this.refreshDelegate = this.refresh.createDelegate(this);
11800     /**
11801      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11802      * @type Function
11803      */
11804     this.updateDelegate = this.update.createDelegate(this);
11805     /**
11806      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11807      * @type Function
11808      */
11809     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11810     /**
11811      * @private
11812      */
11813     this.successDelegate = this.processSuccess.createDelegate(this);
11814     /**
11815      * @private
11816      */
11817     this.failureDelegate = this.processFailure.createDelegate(this);
11818
11819     if(!this.renderer){
11820      /**
11821       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11822       */
11823     this.renderer = new Roo.UpdateManager.BasicRenderer();
11824     }
11825     
11826     Roo.UpdateManager.superclass.constructor.call(this);
11827 };
11828
11829 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11830     /**
11831      * Get the Element this UpdateManager is bound to
11832      * @return {Roo.Element} The element
11833      */
11834     getEl : function(){
11835         return this.el;
11836     },
11837     /**
11838      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11839      * @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:
11840 <pre><code>
11841 um.update({<br/>
11842     url: "your-url.php",<br/>
11843     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11844     callback: yourFunction,<br/>
11845     scope: yourObject, //(optional scope)  <br/>
11846     discardUrl: false, <br/>
11847     nocache: false,<br/>
11848     text: "Loading...",<br/>
11849     timeout: 30,<br/>
11850     scripts: false<br/>
11851 });
11852 </code></pre>
11853      * The only required property is url. The optional properties nocache, text and scripts
11854      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11855      * @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}
11856      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11857      * @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.
11858      */
11859     update : function(url, params, callback, discardUrl){
11860         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11861             var method = this.method,
11862                 cfg;
11863             if(typeof url == "object"){ // must be config object
11864                 cfg = url;
11865                 url = cfg.url;
11866                 params = params || cfg.params;
11867                 callback = callback || cfg.callback;
11868                 discardUrl = discardUrl || cfg.discardUrl;
11869                 if(callback && cfg.scope){
11870                     callback = callback.createDelegate(cfg.scope);
11871                 }
11872                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11873                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11874                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11875                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11876                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11877             }
11878             this.showLoading();
11879             if(!discardUrl){
11880                 this.defaultUrl = url;
11881             }
11882             if(typeof url == "function"){
11883                 url = url.call(this);
11884             }
11885
11886             method = method || (params ? "POST" : "GET");
11887             if(method == "GET"){
11888                 url = this.prepareUrl(url);
11889             }
11890
11891             var o = Roo.apply(cfg ||{}, {
11892                 url : url,
11893                 params: params,
11894                 success: this.successDelegate,
11895                 failure: this.failureDelegate,
11896                 callback: undefined,
11897                 timeout: (this.timeout*1000),
11898                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11899             });
11900             Roo.log("updated manager called with timeout of " + o.timeout);
11901             this.transaction = Roo.Ajax.request(o);
11902         }
11903     },
11904
11905     /**
11906      * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11907      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11908      * @param {String/HTMLElement} form The form Id or form element
11909      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11910      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11911      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11912      */
11913     formUpdate : function(form, url, reset, callback){
11914         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11915             if(typeof url == "function"){
11916                 url = url.call(this);
11917             }
11918             form = Roo.getDom(form);
11919             this.transaction = Roo.Ajax.request({
11920                 form: form,
11921                 url:url,
11922                 success: this.successDelegate,
11923                 failure: this.failureDelegate,
11924                 timeout: (this.timeout*1000),
11925                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11926             });
11927             this.showLoading.defer(1, this);
11928         }
11929     },
11930
11931     /**
11932      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11933      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11934      */
11935     refresh : function(callback){
11936         if(this.defaultUrl == null){
11937             return;
11938         }
11939         this.update(this.defaultUrl, null, callback, true);
11940     },
11941
11942     /**
11943      * Set this element to auto refresh.
11944      * @param {Number} interval How often to update (in seconds).
11945      * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11946      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
11947      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11948      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11949      */
11950     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11951         if(refreshNow){
11952             this.update(url || this.defaultUrl, params, callback, true);
11953         }
11954         if(this.autoRefreshProcId){
11955             clearInterval(this.autoRefreshProcId);
11956         }
11957         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11958     },
11959
11960     /**
11961      * Stop auto refresh on this element.
11962      */
11963      stopAutoRefresh : function(){
11964         if(this.autoRefreshProcId){
11965             clearInterval(this.autoRefreshProcId);
11966             delete this.autoRefreshProcId;
11967         }
11968     },
11969
11970     isAutoRefreshing : function(){
11971        return this.autoRefreshProcId ? true : false;
11972     },
11973     /**
11974      * Called to update the element to "Loading" state. Override to perform custom action.
11975      */
11976     showLoading : function(){
11977         if(this.showLoadIndicator){
11978             this.el.update(this.indicatorText);
11979         }
11980     },
11981
11982     /**
11983      * Adds unique parameter to query string if disableCaching = true
11984      * @private
11985      */
11986     prepareUrl : function(url){
11987         if(this.disableCaching){
11988             var append = "_dc=" + (new Date().getTime());
11989             if(url.indexOf("?") !== -1){
11990                 url += "&" + append;
11991             }else{
11992                 url += "?" + append;
11993             }
11994         }
11995         return url;
11996     },
11997
11998     /**
11999      * @private
12000      */
12001     processSuccess : function(response){
12002         this.transaction = null;
12003         if(response.argument.form && response.argument.reset){
12004             try{ // put in try/catch since some older FF releases had problems with this
12005                 response.argument.form.reset();
12006             }catch(e){}
12007         }
12008         if(this.loadScripts){
12009             this.renderer.render(this.el, response, this,
12010                 this.updateComplete.createDelegate(this, [response]));
12011         }else{
12012             this.renderer.render(this.el, response, this);
12013             this.updateComplete(response);
12014         }
12015     },
12016
12017     updateComplete : function(response){
12018         this.fireEvent("update", this.el, response);
12019         if(typeof response.argument.callback == "function"){
12020             response.argument.callback(this.el, true, response);
12021         }
12022     },
12023
12024     /**
12025      * @private
12026      */
12027     processFailure : function(response){
12028         this.transaction = null;
12029         this.fireEvent("failure", this.el, response);
12030         if(typeof response.argument.callback == "function"){
12031             response.argument.callback(this.el, false, response);
12032         }
12033     },
12034
12035     /**
12036      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12037      * @param {Object} renderer The object implementing the render() method
12038      */
12039     setRenderer : function(renderer){
12040         this.renderer = renderer;
12041     },
12042
12043     getRenderer : function(){
12044        return this.renderer;
12045     },
12046
12047     /**
12048      * Set the defaultUrl used for updates
12049      * @param {String/Function} defaultUrl The url or a function to call to get the url
12050      */
12051     setDefaultUrl : function(defaultUrl){
12052         this.defaultUrl = defaultUrl;
12053     },
12054
12055     /**
12056      * Aborts the executing transaction
12057      */
12058     abort : function(){
12059         if(this.transaction){
12060             Roo.Ajax.abort(this.transaction);
12061         }
12062     },
12063
12064     /**
12065      * Returns true if an update is in progress
12066      * @return {Boolean}
12067      */
12068     isUpdating : function(){
12069         if(this.transaction){
12070             return Roo.Ajax.isLoading(this.transaction);
12071         }
12072         return false;
12073     }
12074 });
12075
12076 /**
12077  * @class Roo.UpdateManager.defaults
12078  * @static (not really - but it helps the doc tool)
12079  * The defaults collection enables customizing the default properties of UpdateManager
12080  */
12081    Roo.UpdateManager.defaults = {
12082        /**
12083          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12084          * @type Number
12085          */
12086          timeout : 30,
12087
12088          /**
12089          * True to process scripts by default (Defaults to false).
12090          * @type Boolean
12091          */
12092         loadScripts : false,
12093
12094         /**
12095         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12096         * @type String
12097         */
12098         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12099         /**
12100          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12101          * @type Boolean
12102          */
12103         disableCaching : false,
12104         /**
12105          * Whether to show indicatorText when loading (Defaults to true).
12106          * @type Boolean
12107          */
12108         showLoadIndicator : true,
12109         /**
12110          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12111          * @type String
12112          */
12113         indicatorText : '<div class="loading-indicator">Loading...</div>'
12114    };
12115
12116 /**
12117  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12118  *Usage:
12119  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12120  * @param {String/HTMLElement/Roo.Element} el The element to update
12121  * @param {String} url The url
12122  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12123  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12124  * @static
12125  * @deprecated
12126  * @member Roo.UpdateManager
12127  */
12128 Roo.UpdateManager.updateElement = function(el, url, params, options){
12129     var um = Roo.get(el, true).getUpdateManager();
12130     Roo.apply(um, options);
12131     um.update(url, params, options ? options.callback : null);
12132 };
12133 // alias for backwards compat
12134 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12135 /**
12136  * @class Roo.UpdateManager.BasicRenderer
12137  * Default Content renderer. Updates the elements innerHTML with the responseText.
12138  */
12139 Roo.UpdateManager.BasicRenderer = function(){};
12140
12141 Roo.UpdateManager.BasicRenderer.prototype = {
12142     /**
12143      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12144      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12145      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12146      * @param {Roo.Element} el The element being rendered
12147      * @param {Object} response The YUI Connect response object
12148      * @param {UpdateManager} updateManager The calling update manager
12149      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12150      */
12151      render : function(el, response, updateManager, callback){
12152         el.update(response.responseText, updateManager.loadScripts, callback);
12153     }
12154 };
12155 /*
12156  * Based on:
12157  * Roo JS
12158  * (c)) Alan Knowles
12159  * Licence : LGPL
12160  */
12161
12162
12163 /**
12164  * @class Roo.DomTemplate
12165  * @extends Roo.Template
12166  * An effort at a dom based template engine..
12167  *
12168  * Similar to XTemplate, except it uses dom parsing to create the template..
12169  *
12170  * Supported features:
12171  *
12172  *  Tags:
12173
12174 <pre><code>
12175       {a_variable} - output encoded.
12176       {a_variable.format:("Y-m-d")} - call a method on the variable
12177       {a_variable:raw} - unencoded output
12178       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12179       {a_variable:this.method_on_template(...)} - call a method on the template object.
12180  
12181 </code></pre>
12182  *  The tpl tag:
12183 <pre><code>
12184         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12185         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12186         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12187         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12188   
12189 </code></pre>
12190  *      
12191  */
12192 Roo.DomTemplate = function()
12193 {
12194      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12195      if (this.html) {
12196         this.compile();
12197      }
12198 };
12199
12200
12201 Roo.extend(Roo.DomTemplate, Roo.Template, {
12202     /**
12203      * id counter for sub templates.
12204      */
12205     id : 0,
12206     /**
12207      * flag to indicate if dom parser is inside a pre,
12208      * it will strip whitespace if not.
12209      */
12210     inPre : false,
12211     
12212     /**
12213      * The various sub templates
12214      */
12215     tpls : false,
12216     
12217     
12218     
12219     /**
12220      *
12221      * basic tag replacing syntax
12222      * WORD:WORD()
12223      *
12224      * // you can fake an object call by doing this
12225      *  x.t:(test,tesT) 
12226      * 
12227      */
12228     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12229     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12230     
12231     iterChild : function (node, method) {
12232         
12233         var oldPre = this.inPre;
12234         if (node.tagName == 'PRE') {
12235             this.inPre = true;
12236         }
12237         for( var i = 0; i < node.childNodes.length; i++) {
12238             method.call(this, node.childNodes[i]);
12239         }
12240         this.inPre = oldPre;
12241     },
12242     
12243     
12244     
12245     /**
12246      * compile the template
12247      *
12248      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12249      *
12250      */
12251     compile: function()
12252     {
12253         var s = this.html;
12254         
12255         // covert the html into DOM...
12256         var doc = false;
12257         var div =false;
12258         try {
12259             doc = document.implementation.createHTMLDocument("");
12260             doc.documentElement.innerHTML =   this.html  ;
12261             div = doc.documentElement;
12262         } catch (e) {
12263             // old IE... - nasty -- it causes all sorts of issues.. with
12264             // images getting pulled from server..
12265             div = document.createElement('div');
12266             div.innerHTML = this.html;
12267         }
12268         //doc.documentElement.innerHTML = htmlBody
12269          
12270         
12271         
12272         this.tpls = [];
12273         var _t = this;
12274         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12275         
12276         var tpls = this.tpls;
12277         
12278         // create a top level template from the snippet..
12279         
12280         //Roo.log(div.innerHTML);
12281         
12282         var tpl = {
12283             uid : 'master',
12284             id : this.id++,
12285             attr : false,
12286             value : false,
12287             body : div.innerHTML,
12288             
12289             forCall : false,
12290             execCall : false,
12291             dom : div,
12292             isTop : true
12293             
12294         };
12295         tpls.unshift(tpl);
12296         
12297         
12298         // compile them...
12299         this.tpls = [];
12300         Roo.each(tpls, function(tp){
12301             this.compileTpl(tp);
12302             this.tpls[tp.id] = tp;
12303         }, this);
12304         
12305         this.master = tpls[0];
12306         return this;
12307         
12308         
12309     },
12310     
12311     compileNode : function(node, istop) {
12312         // test for
12313         //Roo.log(node);
12314         
12315         
12316         // skip anything not a tag..
12317         if (node.nodeType != 1) {
12318             if (node.nodeType == 3 && !this.inPre) {
12319                 // reduce white space..
12320                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12321                 
12322             }
12323             return;
12324         }
12325         
12326         var tpl = {
12327             uid : false,
12328             id : false,
12329             attr : false,
12330             value : false,
12331             body : '',
12332             
12333             forCall : false,
12334             execCall : false,
12335             dom : false,
12336             isTop : istop
12337             
12338             
12339         };
12340         
12341         
12342         switch(true) {
12343             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12344             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12345             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12346             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12347             // no default..
12348         }
12349         
12350         
12351         if (!tpl.attr) {
12352             // just itterate children..
12353             this.iterChild(node,this.compileNode);
12354             return;
12355         }
12356         tpl.uid = this.id++;
12357         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12358         node.removeAttribute('roo-'+ tpl.attr);
12359         if (tpl.attr != 'name') {
12360             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12361             node.parentNode.replaceChild(placeholder,  node);
12362         } else {
12363             
12364             var placeholder =  document.createElement('span');
12365             placeholder.className = 'roo-tpl-' + tpl.value;
12366             node.parentNode.replaceChild(placeholder,  node);
12367         }
12368         
12369         // parent now sees '{domtplXXXX}
12370         this.iterChild(node,this.compileNode);
12371         
12372         // we should now have node body...
12373         var div = document.createElement('div');
12374         div.appendChild(node);
12375         tpl.dom = node;
12376         // this has the unfortunate side effect of converting tagged attributes
12377         // eg. href="{...}" into %7C...%7D
12378         // this has been fixed by searching for those combo's although it's a bit hacky..
12379         
12380         
12381         tpl.body = div.innerHTML;
12382         
12383         
12384          
12385         tpl.id = tpl.uid;
12386         switch(tpl.attr) {
12387             case 'for' :
12388                 switch (tpl.value) {
12389                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12390                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12391                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12392                 }
12393                 break;
12394             
12395             case 'exec':
12396                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12397                 break;
12398             
12399             case 'if':     
12400                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12401                 break;
12402             
12403             case 'name':
12404                 tpl.id  = tpl.value; // replace non characters???
12405                 break;
12406             
12407         }
12408         
12409         
12410         this.tpls.push(tpl);
12411         
12412         
12413         
12414     },
12415     
12416     
12417     
12418     
12419     /**
12420      * Compile a segment of the template into a 'sub-template'
12421      *
12422      * 
12423      * 
12424      *
12425      */
12426     compileTpl : function(tpl)
12427     {
12428         var fm = Roo.util.Format;
12429         var useF = this.disableFormats !== true;
12430         
12431         var sep = Roo.isGecko ? "+\n" : ",\n";
12432         
12433         var undef = function(str) {
12434             Roo.debug && Roo.log("Property not found :"  + str);
12435             return '';
12436         };
12437           
12438         //Roo.log(tpl.body);
12439         
12440         
12441         
12442         var fn = function(m, lbrace, name, format, args)
12443         {
12444             //Roo.log("ARGS");
12445             //Roo.log(arguments);
12446             args = args ? args.replace(/\\'/g,"'") : args;
12447             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12448             if (typeof(format) == 'undefined') {
12449                 format =  'htmlEncode'; 
12450             }
12451             if (format == 'raw' ) {
12452                 format = false;
12453             }
12454             
12455             if(name.substr(0, 6) == 'domtpl'){
12456                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12457             }
12458             
12459             // build an array of options to determine if value is undefined..
12460             
12461             // basically get 'xxxx.yyyy' then do
12462             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12463             //    (function () { Roo.log("Property not found"); return ''; })() :
12464             //    ......
12465             
12466             var udef_ar = [];
12467             var lookfor = '';
12468             Roo.each(name.split('.'), function(st) {
12469                 lookfor += (lookfor.length ? '.': '') + st;
12470                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12471             });
12472             
12473             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12474             
12475             
12476             if(format && useF){
12477                 
12478                 args = args ? ',' + args : "";
12479                  
12480                 if(format.substr(0, 5) != "this."){
12481                     format = "fm." + format + '(';
12482                 }else{
12483                     format = 'this.call("'+ format.substr(5) + '", ';
12484                     args = ", values";
12485                 }
12486                 
12487                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12488             }
12489              
12490             if (args && args.length) {
12491                 // called with xxyx.yuu:(test,test)
12492                 // change to ()
12493                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12494             }
12495             // raw.. - :raw modifier..
12496             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12497             
12498         };
12499         var body;
12500         // branched to use + in gecko and [].join() in others
12501         if(Roo.isGecko){
12502             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12503                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12504                     "';};};";
12505         }else{
12506             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12507             body.push(tpl.body.replace(/(\r\n|\n)/g,
12508                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12509             body.push("'].join('');};};");
12510             body = body.join('');
12511         }
12512         
12513         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12514        
12515         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12516         eval(body);
12517         
12518         return this;
12519     },
12520      
12521     /**
12522      * same as applyTemplate, except it's done to one of the subTemplates
12523      * when using named templates, you can do:
12524      *
12525      * var str = pl.applySubTemplate('your-name', values);
12526      *
12527      * 
12528      * @param {Number} id of the template
12529      * @param {Object} values to apply to template
12530      * @param {Object} parent (normaly the instance of this object)
12531      */
12532     applySubTemplate : function(id, values, parent)
12533     {
12534         
12535         
12536         var t = this.tpls[id];
12537         
12538         
12539         try { 
12540             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12541                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12542                 return '';
12543             }
12544         } catch(e) {
12545             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12546             Roo.log(values);
12547           
12548             return '';
12549         }
12550         try { 
12551             
12552             if(t.execCall && t.execCall.call(this, values, parent)){
12553                 return '';
12554             }
12555         } catch(e) {
12556             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12557             Roo.log(values);
12558             return '';
12559         }
12560         
12561         try {
12562             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12563             parent = t.target ? values : parent;
12564             if(t.forCall && vs instanceof Array){
12565                 var buf = [];
12566                 for(var i = 0, len = vs.length; i < len; i++){
12567                     try {
12568                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12569                     } catch (e) {
12570                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12571                         Roo.log(e.body);
12572                         //Roo.log(t.compiled);
12573                         Roo.log(vs[i]);
12574                     }   
12575                 }
12576                 return buf.join('');
12577             }
12578         } catch (e) {
12579             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12580             Roo.log(values);
12581             return '';
12582         }
12583         try {
12584             return t.compiled.call(this, vs, parent);
12585         } catch (e) {
12586             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12587             Roo.log(e.body);
12588             //Roo.log(t.compiled);
12589             Roo.log(values);
12590             return '';
12591         }
12592     },
12593
12594    
12595
12596     applyTemplate : function(values){
12597         return this.master.compiled.call(this, values, {});
12598         //var s = this.subs;
12599     },
12600
12601     apply : function(){
12602         return this.applyTemplate.apply(this, arguments);
12603     }
12604
12605  });
12606
12607 Roo.DomTemplate.from = function(el){
12608     el = Roo.getDom(el);
12609     return new Roo.Domtemplate(el.value || el.innerHTML);
12610 };/*
12611  * Based on:
12612  * Ext JS Library 1.1.1
12613  * Copyright(c) 2006-2007, Ext JS, LLC.
12614  *
12615  * Originally Released Under LGPL - original licence link has changed is not relivant.
12616  *
12617  * Fork - LGPL
12618  * <script type="text/javascript">
12619  */
12620
12621 /**
12622  * @class Roo.util.DelayedTask
12623  * Provides a convenient method of performing setTimeout where a new
12624  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12625  * You can use this class to buffer
12626  * the keypress events for a certain number of milliseconds, and perform only if they stop
12627  * for that amount of time.
12628  * @constructor The parameters to this constructor serve as defaults and are not required.
12629  * @param {Function} fn (optional) The default function to timeout
12630  * @param {Object} scope (optional) The default scope of that timeout
12631  * @param {Array} args (optional) The default Array of arguments
12632  */
12633 Roo.util.DelayedTask = function(fn, scope, args){
12634     var id = null, d, t;
12635
12636     var call = function(){
12637         var now = new Date().getTime();
12638         if(now - t >= d){
12639             clearInterval(id);
12640             id = null;
12641             fn.apply(scope, args || []);
12642         }
12643     };
12644     /**
12645      * Cancels any pending timeout and queues a new one
12646      * @param {Number} delay The milliseconds to delay
12647      * @param {Function} newFn (optional) Overrides function passed to constructor
12648      * @param {Object} newScope (optional) Overrides scope passed to constructor
12649      * @param {Array} newArgs (optional) Overrides args passed to constructor
12650      */
12651     this.delay = function(delay, newFn, newScope, newArgs){
12652         if(id && delay != d){
12653             this.cancel();
12654         }
12655         d = delay;
12656         t = new Date().getTime();
12657         fn = newFn || fn;
12658         scope = newScope || scope;
12659         args = newArgs || args;
12660         if(!id){
12661             id = setInterval(call, d);
12662         }
12663     };
12664
12665     /**
12666      * Cancel the last queued timeout
12667      */
12668     this.cancel = function(){
12669         if(id){
12670             clearInterval(id);
12671             id = null;
12672         }
12673     };
12674 };/*
12675  * Based on:
12676  * Ext JS Library 1.1.1
12677  * Copyright(c) 2006-2007, Ext JS, LLC.
12678  *
12679  * Originally Released Under LGPL - original licence link has changed is not relivant.
12680  *
12681  * Fork - LGPL
12682  * <script type="text/javascript">
12683  */
12684  
12685  
12686 Roo.util.TaskRunner = function(interval){
12687     interval = interval || 10;
12688     var tasks = [], removeQueue = [];
12689     var id = 0;
12690     var running = false;
12691
12692     var stopThread = function(){
12693         running = false;
12694         clearInterval(id);
12695         id = 0;
12696     };
12697
12698     var startThread = function(){
12699         if(!running){
12700             running = true;
12701             id = setInterval(runTasks, interval);
12702         }
12703     };
12704
12705     var removeTask = function(task){
12706         removeQueue.push(task);
12707         if(task.onStop){
12708             task.onStop();
12709         }
12710     };
12711
12712     var runTasks = function(){
12713         if(removeQueue.length > 0){
12714             for(var i = 0, len = removeQueue.length; i < len; i++){
12715                 tasks.remove(removeQueue[i]);
12716             }
12717             removeQueue = [];
12718             if(tasks.length < 1){
12719                 stopThread();
12720                 return;
12721             }
12722         }
12723         var now = new Date().getTime();
12724         for(var i = 0, len = tasks.length; i < len; ++i){
12725             var t = tasks[i];
12726             var itime = now - t.taskRunTime;
12727             if(t.interval <= itime){
12728                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12729                 t.taskRunTime = now;
12730                 if(rt === false || t.taskRunCount === t.repeat){
12731                     removeTask(t);
12732                     return;
12733                 }
12734             }
12735             if(t.duration && t.duration <= (now - t.taskStartTime)){
12736                 removeTask(t);
12737             }
12738         }
12739     };
12740
12741     /**
12742      * Queues a new task.
12743      * @param {Object} task
12744      */
12745     this.start = function(task){
12746         tasks.push(task);
12747         task.taskStartTime = new Date().getTime();
12748         task.taskRunTime = 0;
12749         task.taskRunCount = 0;
12750         startThread();
12751         return task;
12752     };
12753
12754     this.stop = function(task){
12755         removeTask(task);
12756         return task;
12757     };
12758
12759     this.stopAll = function(){
12760         stopThread();
12761         for(var i = 0, len = tasks.length; i < len; i++){
12762             if(tasks[i].onStop){
12763                 tasks[i].onStop();
12764             }
12765         }
12766         tasks = [];
12767         removeQueue = [];
12768     };
12769 };
12770
12771 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12772  * Based on:
12773  * Ext JS Library 1.1.1
12774  * Copyright(c) 2006-2007, Ext JS, LLC.
12775  *
12776  * Originally Released Under LGPL - original licence link has changed is not relivant.
12777  *
12778  * Fork - LGPL
12779  * <script type="text/javascript">
12780  */
12781
12782  
12783 /**
12784  * @class Roo.util.MixedCollection
12785  * @extends Roo.util.Observable
12786  * A Collection class that maintains both numeric indexes and keys and exposes events.
12787  * @constructor
12788  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12789  * collection (defaults to false)
12790  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12791  * and return the key value for that item.  This is used when available to look up the key on items that
12792  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12793  * equivalent to providing an implementation for the {@link #getKey} method.
12794  */
12795 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12796     this.items = [];
12797     this.map = {};
12798     this.keys = [];
12799     this.length = 0;
12800     this.addEvents({
12801         /**
12802          * @event clear
12803          * Fires when the collection is cleared.
12804          */
12805         "clear" : true,
12806         /**
12807          * @event add
12808          * Fires when an item is added to the collection.
12809          * @param {Number} index The index at which the item was added.
12810          * @param {Object} o The item added.
12811          * @param {String} key The key associated with the added item.
12812          */
12813         "add" : true,
12814         /**
12815          * @event replace
12816          * Fires when an item is replaced in the collection.
12817          * @param {String} key he key associated with the new added.
12818          * @param {Object} old The item being replaced.
12819          * @param {Object} new The new item.
12820          */
12821         "replace" : true,
12822         /**
12823          * @event remove
12824          * Fires when an item is removed from the collection.
12825          * @param {Object} o The item being removed.
12826          * @param {String} key (optional) The key associated with the removed item.
12827          */
12828         "remove" : true,
12829         "sort" : true
12830     });
12831     this.allowFunctions = allowFunctions === true;
12832     if(keyFn){
12833         this.getKey = keyFn;
12834     }
12835     Roo.util.MixedCollection.superclass.constructor.call(this);
12836 };
12837
12838 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12839     allowFunctions : false,
12840     
12841 /**
12842  * Adds an item to the collection.
12843  * @param {String} key The key to associate with the item
12844  * @param {Object} o The item to add.
12845  * @return {Object} The item added.
12846  */
12847     add : function(key, o){
12848         if(arguments.length == 1){
12849             o = arguments[0];
12850             key = this.getKey(o);
12851         }
12852         if(typeof key == "undefined" || key === null){
12853             this.length++;
12854             this.items.push(o);
12855             this.keys.push(null);
12856         }else{
12857             var old = this.map[key];
12858             if(old){
12859                 return this.replace(key, o);
12860             }
12861             this.length++;
12862             this.items.push(o);
12863             this.map[key] = o;
12864             this.keys.push(key);
12865         }
12866         this.fireEvent("add", this.length-1, o, key);
12867         return o;
12868     },
12869        
12870 /**
12871   * MixedCollection has a generic way to fetch keys if you implement getKey.
12872 <pre><code>
12873 // normal way
12874 var mc = new Roo.util.MixedCollection();
12875 mc.add(someEl.dom.id, someEl);
12876 mc.add(otherEl.dom.id, otherEl);
12877 //and so on
12878
12879 // using getKey
12880 var mc = new Roo.util.MixedCollection();
12881 mc.getKey = function(el){
12882    return el.dom.id;
12883 };
12884 mc.add(someEl);
12885 mc.add(otherEl);
12886
12887 // or via the constructor
12888 var mc = new Roo.util.MixedCollection(false, function(el){
12889    return el.dom.id;
12890 });
12891 mc.add(someEl);
12892 mc.add(otherEl);
12893 </code></pre>
12894  * @param o {Object} The item for which to find the key.
12895  * @return {Object} The key for the passed item.
12896  */
12897     getKey : function(o){
12898          return o.id; 
12899     },
12900    
12901 /**
12902  * Replaces an item in the collection.
12903  * @param {String} key The key associated with the item to replace, or the item to replace.
12904  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12905  * @return {Object}  The new item.
12906  */
12907     replace : function(key, o){
12908         if(arguments.length == 1){
12909             o = arguments[0];
12910             key = this.getKey(o);
12911         }
12912         var old = this.item(key);
12913         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12914              return this.add(key, o);
12915         }
12916         var index = this.indexOfKey(key);
12917         this.items[index] = o;
12918         this.map[key] = o;
12919         this.fireEvent("replace", key, old, o);
12920         return o;
12921     },
12922    
12923 /**
12924  * Adds all elements of an Array or an Object to the collection.
12925  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12926  * an Array of values, each of which are added to the collection.
12927  */
12928     addAll : function(objs){
12929         if(arguments.length > 1 || objs instanceof Array){
12930             var args = arguments.length > 1 ? arguments : objs;
12931             for(var i = 0, len = args.length; i < len; i++){
12932                 this.add(args[i]);
12933             }
12934         }else{
12935             for(var key in objs){
12936                 if(this.allowFunctions || typeof objs[key] != "function"){
12937                     this.add(key, objs[key]);
12938                 }
12939             }
12940         }
12941     },
12942    
12943 /**
12944  * Executes the specified function once for every item in the collection, passing each
12945  * item as the first and only parameter. returning false from the function will stop the iteration.
12946  * @param {Function} fn The function to execute for each item.
12947  * @param {Object} scope (optional) The scope in which to execute the function.
12948  */
12949     each : function(fn, scope){
12950         var items = [].concat(this.items); // each safe for removal
12951         for(var i = 0, len = items.length; i < len; i++){
12952             if(fn.call(scope || items[i], items[i], i, len) === false){
12953                 break;
12954             }
12955         }
12956     },
12957    
12958 /**
12959  * Executes the specified function once for every key in the collection, passing each
12960  * key, and its associated item as the first two parameters.
12961  * @param {Function} fn The function to execute for each item.
12962  * @param {Object} scope (optional) The scope in which to execute the function.
12963  */
12964     eachKey : function(fn, scope){
12965         for(var i = 0, len = this.keys.length; i < len; i++){
12966             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12967         }
12968     },
12969    
12970 /**
12971  * Returns the first item in the collection which elicits a true return value from the
12972  * passed selection function.
12973  * @param {Function} fn The selection function to execute for each item.
12974  * @param {Object} scope (optional) The scope in which to execute the function.
12975  * @return {Object} The first item in the collection which returned true from the selection function.
12976  */
12977     find : function(fn, scope){
12978         for(var i = 0, len = this.items.length; i < len; i++){
12979             if(fn.call(scope || window, this.items[i], this.keys[i])){
12980                 return this.items[i];
12981             }
12982         }
12983         return null;
12984     },
12985    
12986 /**
12987  * Inserts an item at the specified index in the collection.
12988  * @param {Number} index The index to insert the item at.
12989  * @param {String} key The key to associate with the new item, or the item itself.
12990  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12991  * @return {Object} The item inserted.
12992  */
12993     insert : function(index, key, o){
12994         if(arguments.length == 2){
12995             o = arguments[1];
12996             key = this.getKey(o);
12997         }
12998         if(index >= this.length){
12999             return this.add(key, o);
13000         }
13001         this.length++;
13002         this.items.splice(index, 0, o);
13003         if(typeof key != "undefined" && key != null){
13004             this.map[key] = o;
13005         }
13006         this.keys.splice(index, 0, key);
13007         this.fireEvent("add", index, o, key);
13008         return o;
13009     },
13010    
13011 /**
13012  * Removed an item from the collection.
13013  * @param {Object} o The item to remove.
13014  * @return {Object} The item removed.
13015  */
13016     remove : function(o){
13017         return this.removeAt(this.indexOf(o));
13018     },
13019    
13020 /**
13021  * Remove an item from a specified index in the collection.
13022  * @param {Number} index The index within the collection of the item to remove.
13023  */
13024     removeAt : function(index){
13025         if(index < this.length && index >= 0){
13026             this.length--;
13027             var o = this.items[index];
13028             this.items.splice(index, 1);
13029             var key = this.keys[index];
13030             if(typeof key != "undefined"){
13031                 delete this.map[key];
13032             }
13033             this.keys.splice(index, 1);
13034             this.fireEvent("remove", o, key);
13035         }
13036     },
13037    
13038 /**
13039  * Removed an item associated with the passed key fom the collection.
13040  * @param {String} key The key of the item to remove.
13041  */
13042     removeKey : function(key){
13043         return this.removeAt(this.indexOfKey(key));
13044     },
13045    
13046 /**
13047  * Returns the number of items in the collection.
13048  * @return {Number} the number of items in the collection.
13049  */
13050     getCount : function(){
13051         return this.length; 
13052     },
13053    
13054 /**
13055  * Returns index within the collection of the passed Object.
13056  * @param {Object} o The item to find the index of.
13057  * @return {Number} index of the item.
13058  */
13059     indexOf : function(o){
13060         if(!this.items.indexOf){
13061             for(var i = 0, len = this.items.length; i < len; i++){
13062                 if(this.items[i] == o) return i;
13063             }
13064             return -1;
13065         }else{
13066             return this.items.indexOf(o);
13067         }
13068     },
13069    
13070 /**
13071  * Returns index within the collection of the passed key.
13072  * @param {String} key The key to find the index of.
13073  * @return {Number} index of the key.
13074  */
13075     indexOfKey : function(key){
13076         if(!this.keys.indexOf){
13077             for(var i = 0, len = this.keys.length; i < len; i++){
13078                 if(this.keys[i] == key) return i;
13079             }
13080             return -1;
13081         }else{
13082             return this.keys.indexOf(key);
13083         }
13084     },
13085    
13086 /**
13087  * Returns the item associated with the passed key OR index. Key has priority over index.
13088  * @param {String/Number} key The key or index of the item.
13089  * @return {Object} The item associated with the passed key.
13090  */
13091     item : function(key){
13092         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13093         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13094     },
13095     
13096 /**
13097  * Returns the item at the specified index.
13098  * @param {Number} index The index of the item.
13099  * @return {Object}
13100  */
13101     itemAt : function(index){
13102         return this.items[index];
13103     },
13104     
13105 /**
13106  * Returns the item associated with the passed key.
13107  * @param {String/Number} key The key of the item.
13108  * @return {Object} The item associated with the passed key.
13109  */
13110     key : function(key){
13111         return this.map[key];
13112     },
13113    
13114 /**
13115  * Returns true if the collection contains the passed Object as an item.
13116  * @param {Object} o  The Object to look for in the collection.
13117  * @return {Boolean} True if the collection contains the Object as an item.
13118  */
13119     contains : function(o){
13120         return this.indexOf(o) != -1;
13121     },
13122    
13123 /**
13124  * Returns true if the collection contains the passed Object as a key.
13125  * @param {String} key The key to look for in the collection.
13126  * @return {Boolean} True if the collection contains the Object as a key.
13127  */
13128     containsKey : function(key){
13129         return typeof this.map[key] != "undefined";
13130     },
13131    
13132 /**
13133  * Removes all items from the collection.
13134  */
13135     clear : function(){
13136         this.length = 0;
13137         this.items = [];
13138         this.keys = [];
13139         this.map = {};
13140         this.fireEvent("clear");
13141     },
13142    
13143 /**
13144  * Returns the first item in the collection.
13145  * @return {Object} the first item in the collection..
13146  */
13147     first : function(){
13148         return this.items[0]; 
13149     },
13150    
13151 /**
13152  * Returns the last item in the collection.
13153  * @return {Object} the last item in the collection..
13154  */
13155     last : function(){
13156         return this.items[this.length-1];   
13157     },
13158     
13159     _sort : function(property, dir, fn){
13160         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13161         fn = fn || function(a, b){
13162             return a-b;
13163         };
13164         var c = [], k = this.keys, items = this.items;
13165         for(var i = 0, len = items.length; i < len; i++){
13166             c[c.length] = {key: k[i], value: items[i], index: i};
13167         }
13168         c.sort(function(a, b){
13169             var v = fn(a[property], b[property]) * dsc;
13170             if(v == 0){
13171                 v = (a.index < b.index ? -1 : 1);
13172             }
13173             return v;
13174         });
13175         for(var i = 0, len = c.length; i < len; i++){
13176             items[i] = c[i].value;
13177             k[i] = c[i].key;
13178         }
13179         this.fireEvent("sort", this);
13180     },
13181     
13182     /**
13183      * Sorts this collection with the passed comparison function
13184      * @param {String} direction (optional) "ASC" or "DESC"
13185      * @param {Function} fn (optional) comparison function
13186      */
13187     sort : function(dir, fn){
13188         this._sort("value", dir, fn);
13189     },
13190     
13191     /**
13192      * Sorts this collection by keys
13193      * @param {String} direction (optional) "ASC" or "DESC"
13194      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13195      */
13196     keySort : function(dir, fn){
13197         this._sort("key", dir, fn || function(a, b){
13198             return String(a).toUpperCase()-String(b).toUpperCase();
13199         });
13200     },
13201     
13202     /**
13203      * Returns a range of items in this collection
13204      * @param {Number} startIndex (optional) defaults to 0
13205      * @param {Number} endIndex (optional) default to the last item
13206      * @return {Array} An array of items
13207      */
13208     getRange : function(start, end){
13209         var items = this.items;
13210         if(items.length < 1){
13211             return [];
13212         }
13213         start = start || 0;
13214         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13215         var r = [];
13216         if(start <= end){
13217             for(var i = start; i <= end; i++) {
13218                     r[r.length] = items[i];
13219             }
13220         }else{
13221             for(var i = start; i >= end; i--) {
13222                     r[r.length] = items[i];
13223             }
13224         }
13225         return r;
13226     },
13227         
13228     /**
13229      * Filter the <i>objects</i> in this collection by a specific property. 
13230      * Returns a new collection that has been filtered.
13231      * @param {String} property A property on your objects
13232      * @param {String/RegExp} value Either string that the property values 
13233      * should start with or a RegExp to test against the property
13234      * @return {MixedCollection} The new filtered collection
13235      */
13236     filter : function(property, value){
13237         if(!value.exec){ // not a regex
13238             value = String(value);
13239             if(value.length == 0){
13240                 return this.clone();
13241             }
13242             value = new RegExp("^" + Roo.escapeRe(value), "i");
13243         }
13244         return this.filterBy(function(o){
13245             return o && value.test(o[property]);
13246         });
13247         },
13248     
13249     /**
13250      * Filter by a function. * Returns a new collection that has been filtered.
13251      * The passed function will be called with each 
13252      * object in the collection. If the function returns true, the value is included 
13253      * otherwise it is filtered.
13254      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13255      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13256      * @return {MixedCollection} The new filtered collection
13257      */
13258     filterBy : function(fn, scope){
13259         var r = new Roo.util.MixedCollection();
13260         r.getKey = this.getKey;
13261         var k = this.keys, it = this.items;
13262         for(var i = 0, len = it.length; i < len; i++){
13263             if(fn.call(scope||this, it[i], k[i])){
13264                                 r.add(k[i], it[i]);
13265                         }
13266         }
13267         return r;
13268     },
13269     
13270     /**
13271      * Creates a duplicate of this collection
13272      * @return {MixedCollection}
13273      */
13274     clone : function(){
13275         var r = new Roo.util.MixedCollection();
13276         var k = this.keys, it = this.items;
13277         for(var i = 0, len = it.length; i < len; i++){
13278             r.add(k[i], it[i]);
13279         }
13280         r.getKey = this.getKey;
13281         return r;
13282     }
13283 });
13284 /**
13285  * Returns the item associated with the passed key or index.
13286  * @method
13287  * @param {String/Number} key The key or index of the item.
13288  * @return {Object} The item associated with the passed key.
13289  */
13290 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13291  * Based on:
13292  * Ext JS Library 1.1.1
13293  * Copyright(c) 2006-2007, Ext JS, LLC.
13294  *
13295  * Originally Released Under LGPL - original licence link has changed is not relivant.
13296  *
13297  * Fork - LGPL
13298  * <script type="text/javascript">
13299  */
13300 /**
13301  * @class Roo.util.JSON
13302  * Modified version of Douglas Crockford"s json.js that doesn"t
13303  * mess with the Object prototype 
13304  * http://www.json.org/js.html
13305  * @singleton
13306  */
13307 Roo.util.JSON = new (function(){
13308     var useHasOwn = {}.hasOwnProperty ? true : false;
13309     
13310     // crashes Safari in some instances
13311     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13312     
13313     var pad = function(n) {
13314         return n < 10 ? "0" + n : n;
13315     };
13316     
13317     var m = {
13318         "\b": '\\b',
13319         "\t": '\\t',
13320         "\n": '\\n',
13321         "\f": '\\f',
13322         "\r": '\\r',
13323         '"' : '\\"',
13324         "\\": '\\\\'
13325     };
13326
13327     var encodeString = function(s){
13328         if (/["\\\x00-\x1f]/.test(s)) {
13329             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13330                 var c = m[b];
13331                 if(c){
13332                     return c;
13333                 }
13334                 c = b.charCodeAt();
13335                 return "\\u00" +
13336                     Math.floor(c / 16).toString(16) +
13337                     (c % 16).toString(16);
13338             }) + '"';
13339         }
13340         return '"' + s + '"';
13341     };
13342     
13343     var encodeArray = function(o){
13344         var a = ["["], b, i, l = o.length, v;
13345             for (i = 0; i < l; i += 1) {
13346                 v = o[i];
13347                 switch (typeof v) {
13348                     case "undefined":
13349                     case "function":
13350                     case "unknown":
13351                         break;
13352                     default:
13353                         if (b) {
13354                             a.push(',');
13355                         }
13356                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13357                         b = true;
13358                 }
13359             }
13360             a.push("]");
13361             return a.join("");
13362     };
13363     
13364     var encodeDate = function(o){
13365         return '"' + o.getFullYear() + "-" +
13366                 pad(o.getMonth() + 1) + "-" +
13367                 pad(o.getDate()) + "T" +
13368                 pad(o.getHours()) + ":" +
13369                 pad(o.getMinutes()) + ":" +
13370                 pad(o.getSeconds()) + '"';
13371     };
13372     
13373     /**
13374      * Encodes an Object, Array or other value
13375      * @param {Mixed} o The variable to encode
13376      * @return {String} The JSON string
13377      */
13378     this.encode = function(o)
13379     {
13380         // should this be extended to fully wrap stringify..
13381         
13382         if(typeof o == "undefined" || o === null){
13383             return "null";
13384         }else if(o instanceof Array){
13385             return encodeArray(o);
13386         }else if(o instanceof Date){
13387             return encodeDate(o);
13388         }else if(typeof o == "string"){
13389             return encodeString(o);
13390         }else if(typeof o == "number"){
13391             return isFinite(o) ? String(o) : "null";
13392         }else if(typeof o == "boolean"){
13393             return String(o);
13394         }else {
13395             var a = ["{"], b, i, v;
13396             for (i in o) {
13397                 if(!useHasOwn || o.hasOwnProperty(i)) {
13398                     v = o[i];
13399                     switch (typeof v) {
13400                     case "undefined":
13401                     case "function":
13402                     case "unknown":
13403                         break;
13404                     default:
13405                         if(b){
13406                             a.push(',');
13407                         }
13408                         a.push(this.encode(i), ":",
13409                                 v === null ? "null" : this.encode(v));
13410                         b = true;
13411                     }
13412                 }
13413             }
13414             a.push("}");
13415             return a.join("");
13416         }
13417     };
13418     
13419     /**
13420      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13421      * @param {String} json The JSON string
13422      * @return {Object} The resulting object
13423      */
13424     this.decode = function(json){
13425         
13426         return  /** eval:var:json */ eval("(" + json + ')');
13427     };
13428 })();
13429 /** 
13430  * Shorthand for {@link Roo.util.JSON#encode}
13431  * @member Roo encode 
13432  * @method */
13433 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13434 /** 
13435  * Shorthand for {@link Roo.util.JSON#decode}
13436  * @member Roo decode 
13437  * @method */
13438 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13439 /*
13440  * Based on:
13441  * Ext JS Library 1.1.1
13442  * Copyright(c) 2006-2007, Ext JS, LLC.
13443  *
13444  * Originally Released Under LGPL - original licence link has changed is not relivant.
13445  *
13446  * Fork - LGPL
13447  * <script type="text/javascript">
13448  */
13449  
13450 /**
13451  * @class Roo.util.Format
13452  * Reusable data formatting functions
13453  * @singleton
13454  */
13455 Roo.util.Format = function(){
13456     var trimRe = /^\s+|\s+$/g;
13457     return {
13458         /**
13459          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13460          * @param {String} value The string to truncate
13461          * @param {Number} length The maximum length to allow before truncating
13462          * @return {String} The converted text
13463          */
13464         ellipsis : function(value, len){
13465             if(value && value.length > len){
13466                 return value.substr(0, len-3)+"...";
13467             }
13468             return value;
13469         },
13470
13471         /**
13472          * Checks a reference and converts it to empty string if it is undefined
13473          * @param {Mixed} value Reference to check
13474          * @return {Mixed} Empty string if converted, otherwise the original value
13475          */
13476         undef : function(value){
13477             return typeof value != "undefined" ? value : "";
13478         },
13479
13480         /**
13481          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13482          * @param {String} value The string to encode
13483          * @return {String} The encoded text
13484          */
13485         htmlEncode : function(value){
13486             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13487         },
13488
13489         /**
13490          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13491          * @param {String} value The string to decode
13492          * @return {String} The decoded text
13493          */
13494         htmlDecode : function(value){
13495             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13496         },
13497
13498         /**
13499          * Trims any whitespace from either side of a string
13500          * @param {String} value The text to trim
13501          * @return {String} The trimmed text
13502          */
13503         trim : function(value){
13504             return String(value).replace(trimRe, "");
13505         },
13506
13507         /**
13508          * Returns a substring from within an original string
13509          * @param {String} value The original text
13510          * @param {Number} start The start index of the substring
13511          * @param {Number} length The length of the substring
13512          * @return {String} The substring
13513          */
13514         substr : function(value, start, length){
13515             return String(value).substr(start, length);
13516         },
13517
13518         /**
13519          * Converts a string to all lower case letters
13520          * @param {String} value The text to convert
13521          * @return {String} The converted text
13522          */
13523         lowercase : function(value){
13524             return String(value).toLowerCase();
13525         },
13526
13527         /**
13528          * Converts a string to all upper case letters
13529          * @param {String} value The text to convert
13530          * @return {String} The converted text
13531          */
13532         uppercase : function(value){
13533             return String(value).toUpperCase();
13534         },
13535
13536         /**
13537          * Converts the first character only of a string to upper case
13538          * @param {String} value The text to convert
13539          * @return {String} The converted text
13540          */
13541         capitalize : function(value){
13542             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13543         },
13544
13545         // private
13546         call : function(value, fn){
13547             if(arguments.length > 2){
13548                 var args = Array.prototype.slice.call(arguments, 2);
13549                 args.unshift(value);
13550                  
13551                 return /** eval:var:value */  eval(fn).apply(window, args);
13552             }else{
13553                 /** eval:var:value */
13554                 return /** eval:var:value */ eval(fn).call(window, value);
13555             }
13556         },
13557
13558        
13559         /**
13560          * safer version of Math.toFixed..??/
13561          * @param {Number/String} value The numeric value to format
13562          * @param {Number/String} value Decimal places 
13563          * @return {String} The formatted currency string
13564          */
13565         toFixed : function(v, n)
13566         {
13567             // why not use to fixed - precision is buggered???
13568             if (!n) {
13569                 return Math.round(v-0);
13570             }
13571             var fact = Math.pow(10,n+1);
13572             v = (Math.round((v-0)*fact))/fact;
13573             var z = (''+fact).substring(2);
13574             if (v == Math.floor(v)) {
13575                 return Math.floor(v) + '.' + z;
13576             }
13577             
13578             // now just padd decimals..
13579             var ps = String(v).split('.');
13580             var fd = (ps[1] + z);
13581             var r = fd.substring(0,n); 
13582             var rm = fd.substring(n); 
13583             if (rm < 5) {
13584                 return ps[0] + '.' + r;
13585             }
13586             r*=1; // turn it into a number;
13587             r++;
13588             if (String(r).length != n) {
13589                 ps[0]*=1;
13590                 ps[0]++;
13591                 r = String(r).substring(1); // chop the end off.
13592             }
13593             
13594             return ps[0] + '.' + r;
13595              
13596         },
13597         
13598         /**
13599          * Format a number as US currency
13600          * @param {Number/String} value The numeric value to format
13601          * @return {String} The formatted currency string
13602          */
13603         usMoney : function(v){
13604             return '$' + Roo.util.Format.number(v);
13605         },
13606         
13607         /**
13608          * Format a number
13609          * eventually this should probably emulate php's number_format
13610          * @param {Number/String} value The numeric value to format
13611          * @param {Number} decimals number of decimal places
13612          * @return {String} The formatted currency string
13613          */
13614         number : function(v,decimals)
13615         {
13616             // multiply and round.
13617             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13618             var mul = Math.pow(10, decimals);
13619             var zero = String(mul).substring(1);
13620             v = (Math.round((v-0)*mul))/mul;
13621             
13622             // if it's '0' number.. then
13623             
13624             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13625             v = String(v);
13626             var ps = v.split('.');
13627             var whole = ps[0];
13628             
13629             
13630             var r = /(\d+)(\d{3})/;
13631             // add comma's
13632             while (r.test(whole)) {
13633                 whole = whole.replace(r, '$1' + ',' + '$2');
13634             }
13635             
13636             
13637             var sub = ps[1] ?
13638                     // has decimals..
13639                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13640                     // does not have decimals
13641                     (decimals ? ('.' + zero) : '');
13642             
13643             
13644             return whole + sub ;
13645         },
13646         
13647         /**
13648          * Parse a value into a formatted date using the specified format pattern.
13649          * @param {Mixed} value The value to format
13650          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13651          * @return {String} The formatted date string
13652          */
13653         date : function(v, format){
13654             if(!v){
13655                 return "";
13656             }
13657             if(!(v instanceof Date)){
13658                 v = new Date(Date.parse(v));
13659             }
13660             return v.dateFormat(format || Roo.util.Format.defaults.date);
13661         },
13662
13663         /**
13664          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13665          * @param {String} format Any valid date format string
13666          * @return {Function} The date formatting function
13667          */
13668         dateRenderer : function(format){
13669             return function(v){
13670                 return Roo.util.Format.date(v, format);  
13671             };
13672         },
13673
13674         // private
13675         stripTagsRE : /<\/?[^>]+>/gi,
13676         
13677         /**
13678          * Strips all HTML tags
13679          * @param {Mixed} value The text from which to strip tags
13680          * @return {String} The stripped text
13681          */
13682         stripTags : function(v){
13683             return !v ? v : String(v).replace(this.stripTagsRE, "");
13684         }
13685     };
13686 }();
13687 Roo.util.Format.defaults = {
13688     date : 'd/M/Y'
13689 };/*
13690  * Based on:
13691  * Ext JS Library 1.1.1
13692  * Copyright(c) 2006-2007, Ext JS, LLC.
13693  *
13694  * Originally Released Under LGPL - original licence link has changed is not relivant.
13695  *
13696  * Fork - LGPL
13697  * <script type="text/javascript">
13698  */
13699
13700
13701  
13702
13703 /**
13704  * @class Roo.MasterTemplate
13705  * @extends Roo.Template
13706  * Provides a template that can have child templates. The syntax is:
13707 <pre><code>
13708 var t = new Roo.MasterTemplate(
13709         '&lt;select name="{name}"&gt;',
13710                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13711         '&lt;/select&gt;'
13712 );
13713 t.add('options', {value: 'foo', text: 'bar'});
13714 // or you can add multiple child elements in one shot
13715 t.addAll('options', [
13716     {value: 'foo', text: 'bar'},
13717     {value: 'foo2', text: 'bar2'},
13718     {value: 'foo3', text: 'bar3'}
13719 ]);
13720 // then append, applying the master template values
13721 t.append('my-form', {name: 'my-select'});
13722 </code></pre>
13723 * A name attribute for the child template is not required if you have only one child
13724 * template or you want to refer to them by index.
13725  */
13726 Roo.MasterTemplate = function(){
13727     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13728     this.originalHtml = this.html;
13729     var st = {};
13730     var m, re = this.subTemplateRe;
13731     re.lastIndex = 0;
13732     var subIndex = 0;
13733     while(m = re.exec(this.html)){
13734         var name = m[1], content = m[2];
13735         st[subIndex] = {
13736             name: name,
13737             index: subIndex,
13738             buffer: [],
13739             tpl : new Roo.Template(content)
13740         };
13741         if(name){
13742             st[name] = st[subIndex];
13743         }
13744         st[subIndex].tpl.compile();
13745         st[subIndex].tpl.call = this.call.createDelegate(this);
13746         subIndex++;
13747     }
13748     this.subCount = subIndex;
13749     this.subs = st;
13750 };
13751 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13752     /**
13753     * The regular expression used to match sub templates
13754     * @type RegExp
13755     * @property
13756     */
13757     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13758
13759     /**
13760      * Applies the passed values to a child template.
13761      * @param {String/Number} name (optional) The name or index of the child template
13762      * @param {Array/Object} values The values to be applied to the template
13763      * @return {MasterTemplate} this
13764      */
13765      add : function(name, values){
13766         if(arguments.length == 1){
13767             values = arguments[0];
13768             name = 0;
13769         }
13770         var s = this.subs[name];
13771         s.buffer[s.buffer.length] = s.tpl.apply(values);
13772         return this;
13773     },
13774
13775     /**
13776      * Applies all the passed values to a child template.
13777      * @param {String/Number} name (optional) The name or index of the child template
13778      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13779      * @param {Boolean} reset (optional) True to reset the template first
13780      * @return {MasterTemplate} this
13781      */
13782     fill : function(name, values, reset){
13783         var a = arguments;
13784         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13785             values = a[0];
13786             name = 0;
13787             reset = a[1];
13788         }
13789         if(reset){
13790             this.reset();
13791         }
13792         for(var i = 0, len = values.length; i < len; i++){
13793             this.add(name, values[i]);
13794         }
13795         return this;
13796     },
13797
13798     /**
13799      * Resets the template for reuse
13800      * @return {MasterTemplate} this
13801      */
13802      reset : function(){
13803         var s = this.subs;
13804         for(var i = 0; i < this.subCount; i++){
13805             s[i].buffer = [];
13806         }
13807         return this;
13808     },
13809
13810     applyTemplate : function(values){
13811         var s = this.subs;
13812         var replaceIndex = -1;
13813         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13814             return s[++replaceIndex].buffer.join("");
13815         });
13816         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13817     },
13818
13819     apply : function(){
13820         return this.applyTemplate.apply(this, arguments);
13821     },
13822
13823     compile : function(){return this;}
13824 });
13825
13826 /**
13827  * Alias for fill().
13828  * @method
13829  */
13830 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13831  /**
13832  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13833  * var tpl = Roo.MasterTemplate.from('element-id');
13834  * @param {String/HTMLElement} el
13835  * @param {Object} config
13836  * @static
13837  */
13838 Roo.MasterTemplate.from = function(el, config){
13839     el = Roo.getDom(el);
13840     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13841 };/*
13842  * Based on:
13843  * Ext JS Library 1.1.1
13844  * Copyright(c) 2006-2007, Ext JS, LLC.
13845  *
13846  * Originally Released Under LGPL - original licence link has changed is not relivant.
13847  *
13848  * Fork - LGPL
13849  * <script type="text/javascript">
13850  */
13851
13852  
13853 /**
13854  * @class Roo.util.CSS
13855  * Utility class for manipulating CSS rules
13856  * @singleton
13857  */
13858 Roo.util.CSS = function(){
13859         var rules = null;
13860         var doc = document;
13861
13862     var camelRe = /(-[a-z])/gi;
13863     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13864
13865    return {
13866    /**
13867     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13868     * tag and appended to the HEAD of the document.
13869     * @param {String|Object} cssText The text containing the css rules
13870     * @param {String} id An id to add to the stylesheet for later removal
13871     * @return {StyleSheet}
13872     */
13873     createStyleSheet : function(cssText, id){
13874         var ss;
13875         var head = doc.getElementsByTagName("head")[0];
13876         var nrules = doc.createElement("style");
13877         nrules.setAttribute("type", "text/css");
13878         if(id){
13879             nrules.setAttribute("id", id);
13880         }
13881         if (typeof(cssText) != 'string') {
13882             // support object maps..
13883             // not sure if this a good idea.. 
13884             // perhaps it should be merged with the general css handling
13885             // and handle js style props.
13886             var cssTextNew = [];
13887             for(var n in cssText) {
13888                 var citems = [];
13889                 for(var k in cssText[n]) {
13890                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13891                 }
13892                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13893                 
13894             }
13895             cssText = cssTextNew.join("\n");
13896             
13897         }
13898        
13899        
13900        if(Roo.isIE){
13901            head.appendChild(nrules);
13902            ss = nrules.styleSheet;
13903            ss.cssText = cssText;
13904        }else{
13905            try{
13906                 nrules.appendChild(doc.createTextNode(cssText));
13907            }catch(e){
13908                nrules.cssText = cssText; 
13909            }
13910            head.appendChild(nrules);
13911            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13912        }
13913        this.cacheStyleSheet(ss);
13914        return ss;
13915    },
13916
13917    /**
13918     * Removes a style or link tag by id
13919     * @param {String} id The id of the tag
13920     */
13921    removeStyleSheet : function(id){
13922        var existing = doc.getElementById(id);
13923        if(existing){
13924            existing.parentNode.removeChild(existing);
13925        }
13926    },
13927
13928    /**
13929     * Dynamically swaps an existing stylesheet reference for a new one
13930     * @param {String} id The id of an existing link tag to remove
13931     * @param {String} url The href of the new stylesheet to include
13932     */
13933    swapStyleSheet : function(id, url){
13934        this.removeStyleSheet(id);
13935        var ss = doc.createElement("link");
13936        ss.setAttribute("rel", "stylesheet");
13937        ss.setAttribute("type", "text/css");
13938        ss.setAttribute("id", id);
13939        ss.setAttribute("href", url);
13940        doc.getElementsByTagName("head")[0].appendChild(ss);
13941    },
13942    
13943    /**
13944     * Refresh the rule cache if you have dynamically added stylesheets
13945     * @return {Object} An object (hash) of rules indexed by selector
13946     */
13947    refreshCache : function(){
13948        return this.getRules(true);
13949    },
13950
13951    // private
13952    cacheStyleSheet : function(stylesheet){
13953        if(!rules){
13954            rules = {};
13955        }
13956        try{// try catch for cross domain access issue
13957            var ssRules = stylesheet.cssRules || stylesheet.rules;
13958            for(var j = ssRules.length-1; j >= 0; --j){
13959                rules[ssRules[j].selectorText] = ssRules[j];
13960            }
13961        }catch(e){}
13962    },
13963    
13964    /**
13965     * Gets all css rules for the document
13966     * @param {Boolean} refreshCache true to refresh the internal cache
13967     * @return {Object} An object (hash) of rules indexed by selector
13968     */
13969    getRules : function(refreshCache){
13970                 if(rules == null || refreshCache){
13971                         rules = {};
13972                         var ds = doc.styleSheets;
13973                         for(var i =0, len = ds.length; i < len; i++){
13974                             try{
13975                         this.cacheStyleSheet(ds[i]);
13976                     }catch(e){} 
13977                 }
13978                 }
13979                 return rules;
13980         },
13981         
13982         /**
13983     * Gets an an individual CSS rule by selector(s)
13984     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13985     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13986     * @return {CSSRule} The CSS rule or null if one is not found
13987     */
13988    getRule : function(selector, refreshCache){
13989                 var rs = this.getRules(refreshCache);
13990                 if(!(selector instanceof Array)){
13991                     return rs[selector];
13992                 }
13993                 for(var i = 0; i < selector.length; i++){
13994                         if(rs[selector[i]]){
13995                                 return rs[selector[i]];
13996                         }
13997                 }
13998                 return null;
13999         },
14000         
14001         
14002         /**
14003     * Updates a rule property
14004     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14005     * @param {String} property The css property
14006     * @param {String} value The new value for the property
14007     * @return {Boolean} true If a rule was found and updated
14008     */
14009    updateRule : function(selector, property, value){
14010                 if(!(selector instanceof Array)){
14011                         var rule = this.getRule(selector);
14012                         if(rule){
14013                                 rule.style[property.replace(camelRe, camelFn)] = value;
14014                                 return true;
14015                         }
14016                 }else{
14017                         for(var i = 0; i < selector.length; i++){
14018                                 if(this.updateRule(selector[i], property, value)){
14019                                         return true;
14020                                 }
14021                         }
14022                 }
14023                 return false;
14024         }
14025    };   
14026 }();/*
14027  * Based on:
14028  * Ext JS Library 1.1.1
14029  * Copyright(c) 2006-2007, Ext JS, LLC.
14030  *
14031  * Originally Released Under LGPL - original licence link has changed is not relivant.
14032  *
14033  * Fork - LGPL
14034  * <script type="text/javascript">
14035  */
14036
14037  
14038
14039 /**
14040  * @class Roo.util.ClickRepeater
14041  * @extends Roo.util.Observable
14042  * 
14043  * A wrapper class which can be applied to any element. Fires a "click" event while the
14044  * mouse is pressed. The interval between firings may be specified in the config but
14045  * defaults to 10 milliseconds.
14046  * 
14047  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14048  * 
14049  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14050  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14051  * Similar to an autorepeat key delay.
14052  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14053  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14054  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14055  *           "interval" and "delay" are ignored. "immediate" is honored.
14056  * @cfg {Boolean} preventDefault True to prevent the default click event
14057  * @cfg {Boolean} stopDefault True to stop the default click event
14058  * 
14059  * @history
14060  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14061  *     2007-02-02 jvs Renamed to ClickRepeater
14062  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14063  *
14064  *  @constructor
14065  * @param {String/HTMLElement/Element} el The element to listen on
14066  * @param {Object} config
14067  **/
14068 Roo.util.ClickRepeater = function(el, config)
14069 {
14070     this.el = Roo.get(el);
14071     this.el.unselectable();
14072
14073     Roo.apply(this, config);
14074
14075     this.addEvents({
14076     /**
14077      * @event mousedown
14078      * Fires when the mouse button is depressed.
14079      * @param {Roo.util.ClickRepeater} this
14080      */
14081         "mousedown" : true,
14082     /**
14083      * @event click
14084      * Fires on a specified interval during the time the element is pressed.
14085      * @param {Roo.util.ClickRepeater} this
14086      */
14087         "click" : true,
14088     /**
14089      * @event mouseup
14090      * Fires when the mouse key is released.
14091      * @param {Roo.util.ClickRepeater} this
14092      */
14093         "mouseup" : true
14094     });
14095
14096     this.el.on("mousedown", this.handleMouseDown, this);
14097     if(this.preventDefault || this.stopDefault){
14098         this.el.on("click", function(e){
14099             if(this.preventDefault){
14100                 e.preventDefault();
14101             }
14102             if(this.stopDefault){
14103                 e.stopEvent();
14104             }
14105         }, this);
14106     }
14107
14108     // allow inline handler
14109     if(this.handler){
14110         this.on("click", this.handler,  this.scope || this);
14111     }
14112
14113     Roo.util.ClickRepeater.superclass.constructor.call(this);
14114 };
14115
14116 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14117     interval : 20,
14118     delay: 250,
14119     preventDefault : true,
14120     stopDefault : false,
14121     timer : 0,
14122
14123     // private
14124     handleMouseDown : function(){
14125         clearTimeout(this.timer);
14126         this.el.blur();
14127         if(this.pressClass){
14128             this.el.addClass(this.pressClass);
14129         }
14130         this.mousedownTime = new Date();
14131
14132         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14133         this.el.on("mouseout", this.handleMouseOut, this);
14134
14135         this.fireEvent("mousedown", this);
14136         this.fireEvent("click", this);
14137         
14138         this.timer = this.click.defer(this.delay || this.interval, this);
14139     },
14140
14141     // private
14142     click : function(){
14143         this.fireEvent("click", this);
14144         this.timer = this.click.defer(this.getInterval(), this);
14145     },
14146
14147     // private
14148     getInterval: function(){
14149         if(!this.accelerate){
14150             return this.interval;
14151         }
14152         var pressTime = this.mousedownTime.getElapsed();
14153         if(pressTime < 500){
14154             return 400;
14155         }else if(pressTime < 1700){
14156             return 320;
14157         }else if(pressTime < 2600){
14158             return 250;
14159         }else if(pressTime < 3500){
14160             return 180;
14161         }else if(pressTime < 4400){
14162             return 140;
14163         }else if(pressTime < 5300){
14164             return 80;
14165         }else if(pressTime < 6200){
14166             return 50;
14167         }else{
14168             return 10;
14169         }
14170     },
14171
14172     // private
14173     handleMouseOut : function(){
14174         clearTimeout(this.timer);
14175         if(this.pressClass){
14176             this.el.removeClass(this.pressClass);
14177         }
14178         this.el.on("mouseover", this.handleMouseReturn, this);
14179     },
14180
14181     // private
14182     handleMouseReturn : function(){
14183         this.el.un("mouseover", this.handleMouseReturn);
14184         if(this.pressClass){
14185             this.el.addClass(this.pressClass);
14186         }
14187         this.click();
14188     },
14189
14190     // private
14191     handleMouseUp : function(){
14192         clearTimeout(this.timer);
14193         this.el.un("mouseover", this.handleMouseReturn);
14194         this.el.un("mouseout", this.handleMouseOut);
14195         Roo.get(document).un("mouseup", this.handleMouseUp);
14196         this.el.removeClass(this.pressClass);
14197         this.fireEvent("mouseup", this);
14198     }
14199 });/*
14200  * Based on:
14201  * Ext JS Library 1.1.1
14202  * Copyright(c) 2006-2007, Ext JS, LLC.
14203  *
14204  * Originally Released Under LGPL - original licence link has changed is not relivant.
14205  *
14206  * Fork - LGPL
14207  * <script type="text/javascript">
14208  */
14209
14210  
14211 /**
14212  * @class Roo.KeyNav
14213  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14214  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14215  * way to implement custom navigation schemes for any UI component.</p>
14216  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14217  * pageUp, pageDown, del, home, end.  Usage:</p>
14218  <pre><code>
14219 var nav = new Roo.KeyNav("my-element", {
14220     "left" : function(e){
14221         this.moveLeft(e.ctrlKey);
14222     },
14223     "right" : function(e){
14224         this.moveRight(e.ctrlKey);
14225     },
14226     "enter" : function(e){
14227         this.save();
14228     },
14229     scope : this
14230 });
14231 </code></pre>
14232  * @constructor
14233  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14234  * @param {Object} config The config
14235  */
14236 Roo.KeyNav = function(el, config){
14237     this.el = Roo.get(el);
14238     Roo.apply(this, config);
14239     if(!this.disabled){
14240         this.disabled = true;
14241         this.enable();
14242     }
14243 };
14244
14245 Roo.KeyNav.prototype = {
14246     /**
14247      * @cfg {Boolean} disabled
14248      * True to disable this KeyNav instance (defaults to false)
14249      */
14250     disabled : false,
14251     /**
14252      * @cfg {String} defaultEventAction
14253      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14254      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14255      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14256      */
14257     defaultEventAction: "stopEvent",
14258     /**
14259      * @cfg {Boolean} forceKeyDown
14260      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14261      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14262      * handle keydown instead of keypress.
14263      */
14264     forceKeyDown : false,
14265
14266     // private
14267     prepareEvent : function(e){
14268         var k = e.getKey();
14269         var h = this.keyToHandler[k];
14270         //if(h && this[h]){
14271         //    e.stopPropagation();
14272         //}
14273         if(Roo.isSafari && h && k >= 37 && k <= 40){
14274             e.stopEvent();
14275         }
14276     },
14277
14278     // private
14279     relay : function(e){
14280         var k = e.getKey();
14281         var h = this.keyToHandler[k];
14282         if(h && this[h]){
14283             if(this.doRelay(e, this[h], h) !== true){
14284                 e[this.defaultEventAction]();
14285             }
14286         }
14287     },
14288
14289     // private
14290     doRelay : function(e, h, hname){
14291         return h.call(this.scope || this, e);
14292     },
14293
14294     // possible handlers
14295     enter : false,
14296     left : false,
14297     right : false,
14298     up : false,
14299     down : false,
14300     tab : false,
14301     esc : false,
14302     pageUp : false,
14303     pageDown : false,
14304     del : false,
14305     home : false,
14306     end : false,
14307
14308     // quick lookup hash
14309     keyToHandler : {
14310         37 : "left",
14311         39 : "right",
14312         38 : "up",
14313         40 : "down",
14314         33 : "pageUp",
14315         34 : "pageDown",
14316         46 : "del",
14317         36 : "home",
14318         35 : "end",
14319         13 : "enter",
14320         27 : "esc",
14321         9  : "tab"
14322     },
14323
14324         /**
14325          * Enable this KeyNav
14326          */
14327         enable: function(){
14328                 if(this.disabled){
14329             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14330             // the EventObject will normalize Safari automatically
14331             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14332                 this.el.on("keydown", this.relay,  this);
14333             }else{
14334                 this.el.on("keydown", this.prepareEvent,  this);
14335                 this.el.on("keypress", this.relay,  this);
14336             }
14337                     this.disabled = false;
14338                 }
14339         },
14340
14341         /**
14342          * Disable this KeyNav
14343          */
14344         disable: function(){
14345                 if(!this.disabled){
14346                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14347                 this.el.un("keydown", this.relay);
14348             }else{
14349                 this.el.un("keydown", this.prepareEvent);
14350                 this.el.un("keypress", this.relay);
14351             }
14352                     this.disabled = true;
14353                 }
14354         }
14355 };/*
14356  * Based on:
14357  * Ext JS Library 1.1.1
14358  * Copyright(c) 2006-2007, Ext JS, LLC.
14359  *
14360  * Originally Released Under LGPL - original licence link has changed is not relivant.
14361  *
14362  * Fork - LGPL
14363  * <script type="text/javascript">
14364  */
14365
14366  
14367 /**
14368  * @class Roo.KeyMap
14369  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14370  * The constructor accepts the same config object as defined by {@link #addBinding}.
14371  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14372  * combination it will call the function with this signature (if the match is a multi-key
14373  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14374  * A KeyMap can also handle a string representation of keys.<br />
14375  * Usage:
14376  <pre><code>
14377 // map one key by key code
14378 var map = new Roo.KeyMap("my-element", {
14379     key: 13, // or Roo.EventObject.ENTER
14380     fn: myHandler,
14381     scope: myObject
14382 });
14383
14384 // map multiple keys to one action by string
14385 var map = new Roo.KeyMap("my-element", {
14386     key: "a\r\n\t",
14387     fn: myHandler,
14388     scope: myObject
14389 });
14390
14391 // map multiple keys to multiple actions by strings and array of codes
14392 var map = new Roo.KeyMap("my-element", [
14393     {
14394         key: [10,13],
14395         fn: function(){ alert("Return was pressed"); }
14396     }, {
14397         key: "abc",
14398         fn: function(){ alert('a, b or c was pressed'); }
14399     }, {
14400         key: "\t",
14401         ctrl:true,
14402         shift:true,
14403         fn: function(){ alert('Control + shift + tab was pressed.'); }
14404     }
14405 ]);
14406 </code></pre>
14407  * <b>Note: A KeyMap starts enabled</b>
14408  * @constructor
14409  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14410  * @param {Object} config The config (see {@link #addBinding})
14411  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14412  */
14413 Roo.KeyMap = function(el, config, eventName){
14414     this.el  = Roo.get(el);
14415     this.eventName = eventName || "keydown";
14416     this.bindings = [];
14417     if(config){
14418         this.addBinding(config);
14419     }
14420     this.enable();
14421 };
14422
14423 Roo.KeyMap.prototype = {
14424     /**
14425      * True to stop the event from bubbling and prevent the default browser action if the
14426      * key was handled by the KeyMap (defaults to false)
14427      * @type Boolean
14428      */
14429     stopEvent : false,
14430
14431     /**
14432      * Add a new binding to this KeyMap. The following config object properties are supported:
14433      * <pre>
14434 Property    Type             Description
14435 ----------  ---------------  ----------------------------------------------------------------------
14436 key         String/Array     A single keycode or an array of keycodes to handle
14437 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14438 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14439 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14440 fn          Function         The function to call when KeyMap finds the expected key combination
14441 scope       Object           The scope of the callback function
14442 </pre>
14443      *
14444      * Usage:
14445      * <pre><code>
14446 // Create a KeyMap
14447 var map = new Roo.KeyMap(document, {
14448     key: Roo.EventObject.ENTER,
14449     fn: handleKey,
14450     scope: this
14451 });
14452
14453 //Add a new binding to the existing KeyMap later
14454 map.addBinding({
14455     key: 'abc',
14456     shift: true,
14457     fn: handleKey,
14458     scope: this
14459 });
14460 </code></pre>
14461      * @param {Object/Array} config A single KeyMap config or an array of configs
14462      */
14463         addBinding : function(config){
14464         if(config instanceof Array){
14465             for(var i = 0, len = config.length; i < len; i++){
14466                 this.addBinding(config[i]);
14467             }
14468             return;
14469         }
14470         var keyCode = config.key,
14471             shift = config.shift, 
14472             ctrl = config.ctrl, 
14473             alt = config.alt,
14474             fn = config.fn,
14475             scope = config.scope;
14476         if(typeof keyCode == "string"){
14477             var ks = [];
14478             var keyString = keyCode.toUpperCase();
14479             for(var j = 0, len = keyString.length; j < len; j++){
14480                 ks.push(keyString.charCodeAt(j));
14481             }
14482             keyCode = ks;
14483         }
14484         var keyArray = keyCode instanceof Array;
14485         var handler = function(e){
14486             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14487                 var k = e.getKey();
14488                 if(keyArray){
14489                     for(var i = 0, len = keyCode.length; i < len; i++){
14490                         if(keyCode[i] == k){
14491                           if(this.stopEvent){
14492                               e.stopEvent();
14493                           }
14494                           fn.call(scope || window, k, e);
14495                           return;
14496                         }
14497                     }
14498                 }else{
14499                     if(k == keyCode){
14500                         if(this.stopEvent){
14501                            e.stopEvent();
14502                         }
14503                         fn.call(scope || window, k, e);
14504                     }
14505                 }
14506             }
14507         };
14508         this.bindings.push(handler);  
14509         },
14510
14511     /**
14512      * Shorthand for adding a single key listener
14513      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14514      * following options:
14515      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14516      * @param {Function} fn The function to call
14517      * @param {Object} scope (optional) The scope of the function
14518      */
14519     on : function(key, fn, scope){
14520         var keyCode, shift, ctrl, alt;
14521         if(typeof key == "object" && !(key instanceof Array)){
14522             keyCode = key.key;
14523             shift = key.shift;
14524             ctrl = key.ctrl;
14525             alt = key.alt;
14526         }else{
14527             keyCode = key;
14528         }
14529         this.addBinding({
14530             key: keyCode,
14531             shift: shift,
14532             ctrl: ctrl,
14533             alt: alt,
14534             fn: fn,
14535             scope: scope
14536         })
14537     },
14538
14539     // private
14540     handleKeyDown : function(e){
14541             if(this.enabled){ //just in case
14542             var b = this.bindings;
14543             for(var i = 0, len = b.length; i < len; i++){
14544                 b[i].call(this, e);
14545             }
14546             }
14547         },
14548         
14549         /**
14550          * Returns true if this KeyMap is enabled
14551          * @return {Boolean} 
14552          */
14553         isEnabled : function(){
14554             return this.enabled;  
14555         },
14556         
14557         /**
14558          * Enables this KeyMap
14559          */
14560         enable: function(){
14561                 if(!this.enabled){
14562                     this.el.on(this.eventName, this.handleKeyDown, this);
14563                     this.enabled = true;
14564                 }
14565         },
14566
14567         /**
14568          * Disable this KeyMap
14569          */
14570         disable: function(){
14571                 if(this.enabled){
14572                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14573                     this.enabled = false;
14574                 }
14575         }
14576 };/*
14577  * Based on:
14578  * Ext JS Library 1.1.1
14579  * Copyright(c) 2006-2007, Ext JS, LLC.
14580  *
14581  * Originally Released Under LGPL - original licence link has changed is not relivant.
14582  *
14583  * Fork - LGPL
14584  * <script type="text/javascript">
14585  */
14586
14587  
14588 /**
14589  * @class Roo.util.TextMetrics
14590  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14591  * wide, in pixels, a given block of text will be.
14592  * @singleton
14593  */
14594 Roo.util.TextMetrics = function(){
14595     var shared;
14596     return {
14597         /**
14598          * Measures the size of the specified text
14599          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14600          * that can affect the size of the rendered text
14601          * @param {String} text The text to measure
14602          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14603          * in order to accurately measure the text height
14604          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14605          */
14606         measure : function(el, text, fixedWidth){
14607             if(!shared){
14608                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14609             }
14610             shared.bind(el);
14611             shared.setFixedWidth(fixedWidth || 'auto');
14612             return shared.getSize(text);
14613         },
14614
14615         /**
14616          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14617          * the overhead of multiple calls to initialize the style properties on each measurement.
14618          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14619          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14620          * in order to accurately measure the text height
14621          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14622          */
14623         createInstance : function(el, fixedWidth){
14624             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14625         }
14626     };
14627 }();
14628
14629  
14630
14631 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14632     var ml = new Roo.Element(document.createElement('div'));
14633     document.body.appendChild(ml.dom);
14634     ml.position('absolute');
14635     ml.setLeftTop(-1000, -1000);
14636     ml.hide();
14637
14638     if(fixedWidth){
14639         ml.setWidth(fixedWidth);
14640     }
14641      
14642     var instance = {
14643         /**
14644          * Returns the size of the specified text based on the internal element's style and width properties
14645          * @memberOf Roo.util.TextMetrics.Instance#
14646          * @param {String} text The text to measure
14647          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14648          */
14649         getSize : function(text){
14650             ml.update(text);
14651             var s = ml.getSize();
14652             ml.update('');
14653             return s;
14654         },
14655
14656         /**
14657          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14658          * that can affect the size of the rendered text
14659          * @memberOf Roo.util.TextMetrics.Instance#
14660          * @param {String/HTMLElement} el The element, dom node or id
14661          */
14662         bind : function(el){
14663             ml.setStyle(
14664                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14665             );
14666         },
14667
14668         /**
14669          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14670          * to set a fixed width in order to accurately measure the text height.
14671          * @memberOf Roo.util.TextMetrics.Instance#
14672          * @param {Number} width The width to set on the element
14673          */
14674         setFixedWidth : function(width){
14675             ml.setWidth(width);
14676         },
14677
14678         /**
14679          * Returns the measured width of the specified text
14680          * @memberOf Roo.util.TextMetrics.Instance#
14681          * @param {String} text The text to measure
14682          * @return {Number} width The width in pixels
14683          */
14684         getWidth : function(text){
14685             ml.dom.style.width = 'auto';
14686             return this.getSize(text).width;
14687         },
14688
14689         /**
14690          * Returns the measured height of the specified text.  For multiline text, be sure to call
14691          * {@link #setFixedWidth} if necessary.
14692          * @memberOf Roo.util.TextMetrics.Instance#
14693          * @param {String} text The text to measure
14694          * @return {Number} height The height in pixels
14695          */
14696         getHeight : function(text){
14697             return this.getSize(text).height;
14698         }
14699     };
14700
14701     instance.bind(bindTo);
14702
14703     return instance;
14704 };
14705
14706 // backwards compat
14707 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14708  * Based on:
14709  * Ext JS Library 1.1.1
14710  * Copyright(c) 2006-2007, Ext JS, LLC.
14711  *
14712  * Originally Released Under LGPL - original licence link has changed is not relivant.
14713  *
14714  * Fork - LGPL
14715  * <script type="text/javascript">
14716  */
14717
14718 /**
14719  * @class Roo.state.Provider
14720  * Abstract base class for state provider implementations. This class provides methods
14721  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14722  * Provider interface.
14723  */
14724 Roo.state.Provider = function(){
14725     /**
14726      * @event statechange
14727      * Fires when a state change occurs.
14728      * @param {Provider} this This state provider
14729      * @param {String} key The state key which was changed
14730      * @param {String} value The encoded value for the state
14731      */
14732     this.addEvents({
14733         "statechange": true
14734     });
14735     this.state = {};
14736     Roo.state.Provider.superclass.constructor.call(this);
14737 };
14738 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14739     /**
14740      * Returns the current value for a key
14741      * @param {String} name The key name
14742      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14743      * @return {Mixed} The state data
14744      */
14745     get : function(name, defaultValue){
14746         return typeof this.state[name] == "undefined" ?
14747             defaultValue : this.state[name];
14748     },
14749     
14750     /**
14751      * Clears a value from the state
14752      * @param {String} name The key name
14753      */
14754     clear : function(name){
14755         delete this.state[name];
14756         this.fireEvent("statechange", this, name, null);
14757     },
14758     
14759     /**
14760      * Sets the value for a key
14761      * @param {String} name The key name
14762      * @param {Mixed} value The value to set
14763      */
14764     set : function(name, value){
14765         this.state[name] = value;
14766         this.fireEvent("statechange", this, name, value);
14767     },
14768     
14769     /**
14770      * Decodes a string previously encoded with {@link #encodeValue}.
14771      * @param {String} value The value to decode
14772      * @return {Mixed} The decoded value
14773      */
14774     decodeValue : function(cookie){
14775         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14776         var matches = re.exec(unescape(cookie));
14777         if(!matches || !matches[1]) return; // non state cookie
14778         var type = matches[1];
14779         var v = matches[2];
14780         switch(type){
14781             case "n":
14782                 return parseFloat(v);
14783             case "d":
14784                 return new Date(Date.parse(v));
14785             case "b":
14786                 return (v == "1");
14787             case "a":
14788                 var all = [];
14789                 var values = v.split("^");
14790                 for(var i = 0, len = values.length; i < len; i++){
14791                     all.push(this.decodeValue(values[i]));
14792                 }
14793                 return all;
14794            case "o":
14795                 var all = {};
14796                 var values = v.split("^");
14797                 for(var i = 0, len = values.length; i < len; i++){
14798                     var kv = values[i].split("=");
14799                     all[kv[0]] = this.decodeValue(kv[1]);
14800                 }
14801                 return all;
14802            default:
14803                 return v;
14804         }
14805     },
14806     
14807     /**
14808      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14809      * @param {Mixed} value The value to encode
14810      * @return {String} The encoded value
14811      */
14812     encodeValue : function(v){
14813         var enc;
14814         if(typeof v == "number"){
14815             enc = "n:" + v;
14816         }else if(typeof v == "boolean"){
14817             enc = "b:" + (v ? "1" : "0");
14818         }else if(v instanceof Date){
14819             enc = "d:" + v.toGMTString();
14820         }else if(v instanceof Array){
14821             var flat = "";
14822             for(var i = 0, len = v.length; i < len; i++){
14823                 flat += this.encodeValue(v[i]);
14824                 if(i != len-1) flat += "^";
14825             }
14826             enc = "a:" + flat;
14827         }else if(typeof v == "object"){
14828             var flat = "";
14829             for(var key in v){
14830                 if(typeof v[key] != "function"){
14831                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14832                 }
14833             }
14834             enc = "o:" + flat.substring(0, flat.length-1);
14835         }else{
14836             enc = "s:" + v;
14837         }
14838         return escape(enc);        
14839     }
14840 });
14841
14842 /*
14843  * Based on:
14844  * Ext JS Library 1.1.1
14845  * Copyright(c) 2006-2007, Ext JS, LLC.
14846  *
14847  * Originally Released Under LGPL - original licence link has changed is not relivant.
14848  *
14849  * Fork - LGPL
14850  * <script type="text/javascript">
14851  */
14852 /**
14853  * @class Roo.state.Manager
14854  * This is the global state manager. By default all components that are "state aware" check this class
14855  * for state information if you don't pass them a custom state provider. In order for this class
14856  * to be useful, it must be initialized with a provider when your application initializes.
14857  <pre><code>
14858 // in your initialization function
14859 init : function(){
14860    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14861    ...
14862    // supposed you have a {@link Roo.BorderLayout}
14863    var layout = new Roo.BorderLayout(...);
14864    layout.restoreState();
14865    // or a {Roo.BasicDialog}
14866    var dialog = new Roo.BasicDialog(...);
14867    dialog.restoreState();
14868  </code></pre>
14869  * @singleton
14870  */
14871 Roo.state.Manager = function(){
14872     var provider = new Roo.state.Provider();
14873     
14874     return {
14875         /**
14876          * Configures the default state provider for your application
14877          * @param {Provider} stateProvider The state provider to set
14878          */
14879         setProvider : function(stateProvider){
14880             provider = stateProvider;
14881         },
14882         
14883         /**
14884          * Returns the current value for a key
14885          * @param {String} name The key name
14886          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14887          * @return {Mixed} The state data
14888          */
14889         get : function(key, defaultValue){
14890             return provider.get(key, defaultValue);
14891         },
14892         
14893         /**
14894          * Sets the value for a key
14895          * @param {String} name The key name
14896          * @param {Mixed} value The state data
14897          */
14898          set : function(key, value){
14899             provider.set(key, value);
14900         },
14901         
14902         /**
14903          * Clears a value from the state
14904          * @param {String} name The key name
14905          */
14906         clear : function(key){
14907             provider.clear(key);
14908         },
14909         
14910         /**
14911          * Gets the currently configured state provider
14912          * @return {Provider} The state provider
14913          */
14914         getProvider : function(){
14915             return provider;
14916         }
14917     };
14918 }();
14919 /*
14920  * Based on:
14921  * Ext JS Library 1.1.1
14922  * Copyright(c) 2006-2007, Ext JS, LLC.
14923  *
14924  * Originally Released Under LGPL - original licence link has changed is not relivant.
14925  *
14926  * Fork - LGPL
14927  * <script type="text/javascript">
14928  */
14929 /**
14930  * @class Roo.state.CookieProvider
14931  * @extends Roo.state.Provider
14932  * The default Provider implementation which saves state via cookies.
14933  * <br />Usage:
14934  <pre><code>
14935    var cp = new Roo.state.CookieProvider({
14936        path: "/cgi-bin/",
14937        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14938        domain: "roojs.com"
14939    })
14940    Roo.state.Manager.setProvider(cp);
14941  </code></pre>
14942  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14943  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14944  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14945  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14946  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14947  * domain the page is running on including the 'www' like 'www.roojs.com')
14948  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14949  * @constructor
14950  * Create a new CookieProvider
14951  * @param {Object} config The configuration object
14952  */
14953 Roo.state.CookieProvider = function(config){
14954     Roo.state.CookieProvider.superclass.constructor.call(this);
14955     this.path = "/";
14956     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14957     this.domain = null;
14958     this.secure = false;
14959     Roo.apply(this, config);
14960     this.state = this.readCookies();
14961 };
14962
14963 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14964     // private
14965     set : function(name, value){
14966         if(typeof value == "undefined" || value === null){
14967             this.clear(name);
14968             return;
14969         }
14970         this.setCookie(name, value);
14971         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14972     },
14973
14974     // private
14975     clear : function(name){
14976         this.clearCookie(name);
14977         Roo.state.CookieProvider.superclass.clear.call(this, name);
14978     },
14979
14980     // private
14981     readCookies : function(){
14982         var cookies = {};
14983         var c = document.cookie + ";";
14984         var re = /\s?(.*?)=(.*?);/g;
14985         var matches;
14986         while((matches = re.exec(c)) != null){
14987             var name = matches[1];
14988             var value = matches[2];
14989             if(name && name.substring(0,3) == "ys-"){
14990                 cookies[name.substr(3)] = this.decodeValue(value);
14991             }
14992         }
14993         return cookies;
14994     },
14995
14996     // private
14997     setCookie : function(name, value){
14998         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14999            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15000            ((this.path == null) ? "" : ("; path=" + this.path)) +
15001            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15002            ((this.secure == true) ? "; secure" : "");
15003     },
15004
15005     // private
15006     clearCookie : function(name){
15007         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15008            ((this.path == null) ? "" : ("; path=" + this.path)) +
15009            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15010            ((this.secure == true) ? "; secure" : "");
15011     }
15012 });/*
15013  * Based on:
15014  * Ext JS Library 1.1.1
15015  * Copyright(c) 2006-2007, Ext JS, LLC.
15016  *
15017  * Originally Released Under LGPL - original licence link has changed is not relivant.
15018  *
15019  * Fork - LGPL
15020  * <script type="text/javascript">
15021  */
15022  
15023
15024 /**
15025  * @class Roo.ComponentMgr
15026  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15027  * @singleton
15028  */
15029 Roo.ComponentMgr = function(){
15030     var all = new Roo.util.MixedCollection();
15031
15032     return {
15033         /**
15034          * Registers a component.
15035          * @param {Roo.Component} c The component
15036          */
15037         register : function(c){
15038             all.add(c);
15039         },
15040
15041         /**
15042          * Unregisters a component.
15043          * @param {Roo.Component} c The component
15044          */
15045         unregister : function(c){
15046             all.remove(c);
15047         },
15048
15049         /**
15050          * Returns a component by id
15051          * @param {String} id The component id
15052          */
15053         get : function(id){
15054             return all.get(id);
15055         },
15056
15057         /**
15058          * Registers a function that will be called when a specified component is added to ComponentMgr
15059          * @param {String} id The component id
15060          * @param {Funtction} fn The callback function
15061          * @param {Object} scope The scope of the callback
15062          */
15063         onAvailable : function(id, fn, scope){
15064             all.on("add", function(index, o){
15065                 if(o.id == id){
15066                     fn.call(scope || o, o);
15067                     all.un("add", fn, scope);
15068                 }
15069             });
15070         }
15071     };
15072 }();/*
15073  * Based on:
15074  * Ext JS Library 1.1.1
15075  * Copyright(c) 2006-2007, Ext JS, LLC.
15076  *
15077  * Originally Released Under LGPL - original licence link has changed is not relivant.
15078  *
15079  * Fork - LGPL
15080  * <script type="text/javascript">
15081  */
15082  
15083 /**
15084  * @class Roo.Component
15085  * @extends Roo.util.Observable
15086  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15087  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15088  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15089  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15090  * All visual components (widgets) that require rendering into a layout should subclass Component.
15091  * @constructor
15092  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15093  * element and its id used as the component id.  If a string is passed, it is assumed to be the id of an existing element
15094  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15095  */
15096 Roo.Component = function(config){
15097     config = config || {};
15098     if(config.tagName || config.dom || typeof config == "string"){ // element object
15099         config = {el: config, id: config.id || config};
15100     }
15101     this.initialConfig = config;
15102
15103     Roo.apply(this, config);
15104     this.addEvents({
15105         /**
15106          * @event disable
15107          * Fires after the component is disabled.
15108              * @param {Roo.Component} this
15109              */
15110         disable : true,
15111         /**
15112          * @event enable
15113          * Fires after the component is enabled.
15114              * @param {Roo.Component} this
15115              */
15116         enable : true,
15117         /**
15118          * @event beforeshow
15119          * Fires before the component is shown.  Return false to stop the show.
15120              * @param {Roo.Component} this
15121              */
15122         beforeshow : true,
15123         /**
15124          * @event show
15125          * Fires after the component is shown.
15126              * @param {Roo.Component} this
15127              */
15128         show : true,
15129         /**
15130          * @event beforehide
15131          * Fires before the component is hidden. Return false to stop the hide.
15132              * @param {Roo.Component} this
15133              */
15134         beforehide : true,
15135         /**
15136          * @event hide
15137          * Fires after the component is hidden.
15138              * @param {Roo.Component} this
15139              */
15140         hide : true,
15141         /**
15142          * @event beforerender
15143          * Fires before the component is rendered. Return false to stop the render.
15144              * @param {Roo.Component} this
15145              */
15146         beforerender : true,
15147         /**
15148          * @event render
15149          * Fires after the component is rendered.
15150              * @param {Roo.Component} this
15151              */
15152         render : true,
15153         /**
15154          * @event beforedestroy
15155          * Fires before the component is destroyed. Return false to stop the destroy.
15156              * @param {Roo.Component} this
15157              */
15158         beforedestroy : true,
15159         /**
15160          * @event destroy
15161          * Fires after the component is destroyed.
15162              * @param {Roo.Component} this
15163              */
15164         destroy : true
15165     });
15166     if(!this.id){
15167         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15168     }
15169     Roo.ComponentMgr.register(this);
15170     Roo.Component.superclass.constructor.call(this);
15171     this.initComponent();
15172     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15173         this.render(this.renderTo);
15174         delete this.renderTo;
15175     }
15176 };
15177
15178 /** @private */
15179 Roo.Component.AUTO_ID = 1000;
15180
15181 Roo.extend(Roo.Component, Roo.util.Observable, {
15182     /**
15183      * @scope Roo.Component.prototype
15184      * @type {Boolean}
15185      * true if this component is hidden. Read-only.
15186      */
15187     hidden : false,
15188     /**
15189      * @type {Boolean}
15190      * true if this component is disabled. Read-only.
15191      */
15192     disabled : false,
15193     /**
15194      * @type {Boolean}
15195      * true if this component has been rendered. Read-only.
15196      */
15197     rendered : false,
15198     
15199     /** @cfg {String} disableClass
15200      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15201      */
15202     disabledClass : "x-item-disabled",
15203         /** @cfg {Boolean} allowDomMove
15204          * Whether the component can move the Dom node when rendering (defaults to true).
15205          */
15206     allowDomMove : true,
15207     /** @cfg {String} hideMode
15208      * How this component should hidden. Supported values are
15209      * "visibility" (css visibility), "offsets" (negative offset position) and
15210      * "display" (css display) - defaults to "display".
15211      */
15212     hideMode: 'display',
15213
15214     /** @private */
15215     ctype : "Roo.Component",
15216
15217     /**
15218      * @cfg {String} actionMode 
15219      * which property holds the element that used for  hide() / show() / disable() / enable()
15220      * default is 'el' 
15221      */
15222     actionMode : "el",
15223
15224     /** @private */
15225     getActionEl : function(){
15226         return this[this.actionMode];
15227     },
15228
15229     initComponent : Roo.emptyFn,
15230     /**
15231      * If this is a lazy rendering component, render it to its container element.
15232      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15233      */
15234     render : function(container, position){
15235         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15236             if(!container && this.el){
15237                 this.el = Roo.get(this.el);
15238                 container = this.el.dom.parentNode;
15239                 this.allowDomMove = false;
15240             }
15241             this.container = Roo.get(container);
15242             this.rendered = true;
15243             if(position !== undefined){
15244                 if(typeof position == 'number'){
15245                     position = this.container.dom.childNodes[position];
15246                 }else{
15247                     position = Roo.getDom(position);
15248                 }
15249             }
15250             this.onRender(this.container, position || null);
15251             if(this.cls){
15252                 this.el.addClass(this.cls);
15253                 delete this.cls;
15254             }
15255             if(this.style){
15256                 this.el.applyStyles(this.style);
15257                 delete this.style;
15258             }
15259             this.fireEvent("render", this);
15260             this.afterRender(this.container);
15261             if(this.hidden){
15262                 this.hide();
15263             }
15264             if(this.disabled){
15265                 this.disable();
15266             }
15267         }
15268         return this;
15269     },
15270
15271     /** @private */
15272     // default function is not really useful
15273     onRender : function(ct, position){
15274         if(this.el){
15275             this.el = Roo.get(this.el);
15276             if(this.allowDomMove !== false){
15277                 ct.dom.insertBefore(this.el.dom, position);
15278             }
15279         }
15280     },
15281
15282     /** @private */
15283     getAutoCreate : function(){
15284         var cfg = typeof this.autoCreate == "object" ?
15285                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15286         if(this.id && !cfg.id){
15287             cfg.id = this.id;
15288         }
15289         return cfg;
15290     },
15291
15292     /** @private */
15293     afterRender : Roo.emptyFn,
15294
15295     /**
15296      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15297      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15298      */
15299     destroy : function(){
15300         if(this.fireEvent("beforedestroy", this) !== false){
15301             this.purgeListeners();
15302             this.beforeDestroy();
15303             if(this.rendered){
15304                 this.el.removeAllListeners();
15305                 this.el.remove();
15306                 if(this.actionMode == "container"){
15307                     this.container.remove();
15308                 }
15309             }
15310             this.onDestroy();
15311             Roo.ComponentMgr.unregister(this);
15312             this.fireEvent("destroy", this);
15313         }
15314     },
15315
15316         /** @private */
15317     beforeDestroy : function(){
15318
15319     },
15320
15321         /** @private */
15322         onDestroy : function(){
15323
15324     },
15325
15326     /**
15327      * Returns the underlying {@link Roo.Element}.
15328      * @return {Roo.Element} The element
15329      */
15330     getEl : function(){
15331         return this.el;
15332     },
15333
15334     /**
15335      * Returns the id of this component.
15336      * @return {String}
15337      */
15338     getId : function(){
15339         return this.id;
15340     },
15341
15342     /**
15343      * Try to focus this component.
15344      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15345      * @return {Roo.Component} this
15346      */
15347     focus : function(selectText){
15348         if(this.rendered){
15349             this.el.focus();
15350             if(selectText === true){
15351                 this.el.dom.select();
15352             }
15353         }
15354         return this;
15355     },
15356
15357     /** @private */
15358     blur : function(){
15359         if(this.rendered){
15360             this.el.blur();
15361         }
15362         return this;
15363     },
15364
15365     /**
15366      * Disable this component.
15367      * @return {Roo.Component} this
15368      */
15369     disable : function(){
15370         if(this.rendered){
15371             this.onDisable();
15372         }
15373         this.disabled = true;
15374         this.fireEvent("disable", this);
15375         return this;
15376     },
15377
15378         // private
15379     onDisable : function(){
15380         this.getActionEl().addClass(this.disabledClass);
15381         this.el.dom.disabled = true;
15382     },
15383
15384     /**
15385      * Enable this component.
15386      * @return {Roo.Component} this
15387      */
15388     enable : function(){
15389         if(this.rendered){
15390             this.onEnable();
15391         }
15392         this.disabled = false;
15393         this.fireEvent("enable", this);
15394         return this;
15395     },
15396
15397         // private
15398     onEnable : function(){
15399         this.getActionEl().removeClass(this.disabledClass);
15400         this.el.dom.disabled = false;
15401     },
15402
15403     /**
15404      * Convenience function for setting disabled/enabled by boolean.
15405      * @param {Boolean} disabled
15406      */
15407     setDisabled : function(disabled){
15408         this[disabled ? "disable" : "enable"]();
15409     },
15410
15411     /**
15412      * Show this component.
15413      * @return {Roo.Component} this
15414      */
15415     show: function(){
15416         if(this.fireEvent("beforeshow", this) !== false){
15417             this.hidden = false;
15418             if(this.rendered){
15419                 this.onShow();
15420             }
15421             this.fireEvent("show", this);
15422         }
15423         return this;
15424     },
15425
15426     // private
15427     onShow : function(){
15428         var ae = this.getActionEl();
15429         if(this.hideMode == 'visibility'){
15430             ae.dom.style.visibility = "visible";
15431         }else if(this.hideMode == 'offsets'){
15432             ae.removeClass('x-hidden');
15433         }else{
15434             ae.dom.style.display = "";
15435         }
15436     },
15437
15438     /**
15439      * Hide this component.
15440      * @return {Roo.Component} this
15441      */
15442     hide: function(){
15443         if(this.fireEvent("beforehide", this) !== false){
15444             this.hidden = true;
15445             if(this.rendered){
15446                 this.onHide();
15447             }
15448             this.fireEvent("hide", this);
15449         }
15450         return this;
15451     },
15452
15453     // private
15454     onHide : function(){
15455         var ae = this.getActionEl();
15456         if(this.hideMode == 'visibility'){
15457             ae.dom.style.visibility = "hidden";
15458         }else if(this.hideMode == 'offsets'){
15459             ae.addClass('x-hidden');
15460         }else{
15461             ae.dom.style.display = "none";
15462         }
15463     },
15464
15465     /**
15466      * Convenience function to hide or show this component by boolean.
15467      * @param {Boolean} visible True to show, false to hide
15468      * @return {Roo.Component} this
15469      */
15470     setVisible: function(visible){
15471         if(visible) {
15472             this.show();
15473         }else{
15474             this.hide();
15475         }
15476         return this;
15477     },
15478
15479     /**
15480      * Returns true if this component is visible.
15481      */
15482     isVisible : function(){
15483         return this.getActionEl().isVisible();
15484     },
15485
15486     cloneConfig : function(overrides){
15487         overrides = overrides || {};
15488         var id = overrides.id || Roo.id();
15489         var cfg = Roo.applyIf(overrides, this.initialConfig);
15490         cfg.id = id; // prevent dup id
15491         return new this.constructor(cfg);
15492     }
15493 });/*
15494  * Based on:
15495  * Ext JS Library 1.1.1
15496  * Copyright(c) 2006-2007, Ext JS, LLC.
15497  *
15498  * Originally Released Under LGPL - original licence link has changed is not relivant.
15499  *
15500  * Fork - LGPL
15501  * <script type="text/javascript">
15502  */
15503
15504 /**
15505  * @class Roo.BoxComponent
15506  * @extends Roo.Component
15507  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15508  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15509  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15510  * layout containers.
15511  * @constructor
15512  * @param {Roo.Element/String/Object} config The configuration options.
15513  */
15514 Roo.BoxComponent = function(config){
15515     Roo.Component.call(this, config);
15516     this.addEvents({
15517         /**
15518          * @event resize
15519          * Fires after the component is resized.
15520              * @param {Roo.Component} this
15521              * @param {Number} adjWidth The box-adjusted width that was set
15522              * @param {Number} adjHeight The box-adjusted height that was set
15523              * @param {Number} rawWidth The width that was originally specified
15524              * @param {Number} rawHeight The height that was originally specified
15525              */
15526         resize : true,
15527         /**
15528          * @event move
15529          * Fires after the component is moved.
15530              * @param {Roo.Component} this
15531              * @param {Number} x The new x position
15532              * @param {Number} y The new y position
15533              */
15534         move : true
15535     });
15536 };
15537
15538 Roo.extend(Roo.BoxComponent, Roo.Component, {
15539     // private, set in afterRender to signify that the component has been rendered
15540     boxReady : false,
15541     // private, used to defer height settings to subclasses
15542     deferHeight: false,
15543     /** @cfg {Number} width
15544      * width (optional) size of component
15545      */
15546      /** @cfg {Number} height
15547      * height (optional) size of component
15548      */
15549      
15550     /**
15551      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15552      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15553      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15554      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15555      * @return {Roo.BoxComponent} this
15556      */
15557     setSize : function(w, h){
15558         // support for standard size objects
15559         if(typeof w == 'object'){
15560             h = w.height;
15561             w = w.width;
15562         }
15563         // not rendered
15564         if(!this.boxReady){
15565             this.width = w;
15566             this.height = h;
15567             return this;
15568         }
15569
15570         // prevent recalcs when not needed
15571         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15572             return this;
15573         }
15574         this.lastSize = {width: w, height: h};
15575
15576         var adj = this.adjustSize(w, h);
15577         var aw = adj.width, ah = adj.height;
15578         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15579             var rz = this.getResizeEl();
15580             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15581                 rz.setSize(aw, ah);
15582             }else if(!this.deferHeight && ah !== undefined){
15583                 rz.setHeight(ah);
15584             }else if(aw !== undefined){
15585                 rz.setWidth(aw);
15586             }
15587             this.onResize(aw, ah, w, h);
15588             this.fireEvent('resize', this, aw, ah, w, h);
15589         }
15590         return this;
15591     },
15592
15593     /**
15594      * Gets the current size of the component's underlying element.
15595      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15596      */
15597     getSize : function(){
15598         return this.el.getSize();
15599     },
15600
15601     /**
15602      * Gets the current XY position of the component's underlying element.
15603      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15604      * @return {Array} The XY position of the element (e.g., [100, 200])
15605      */
15606     getPosition : function(local){
15607         if(local === true){
15608             return [this.el.getLeft(true), this.el.getTop(true)];
15609         }
15610         return this.xy || this.el.getXY();
15611     },
15612
15613     /**
15614      * Gets the current box measurements of the component's underlying element.
15615      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15616      * @returns {Object} box An object in the format {x, y, width, height}
15617      */
15618     getBox : function(local){
15619         var s = this.el.getSize();
15620         if(local){
15621             s.x = this.el.getLeft(true);
15622             s.y = this.el.getTop(true);
15623         }else{
15624             var xy = this.xy || this.el.getXY();
15625             s.x = xy[0];
15626             s.y = xy[1];
15627         }
15628         return s;
15629     },
15630
15631     /**
15632      * Sets the current box measurements of the component's underlying element.
15633      * @param {Object} box An object in the format {x, y, width, height}
15634      * @returns {Roo.BoxComponent} this
15635      */
15636     updateBox : function(box){
15637         this.setSize(box.width, box.height);
15638         this.setPagePosition(box.x, box.y);
15639         return this;
15640     },
15641
15642     // protected
15643     getResizeEl : function(){
15644         return this.resizeEl || this.el;
15645     },
15646
15647     // protected
15648     getPositionEl : function(){
15649         return this.positionEl || this.el;
15650     },
15651
15652     /**
15653      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15654      * This method fires the move event.
15655      * @param {Number} left The new left
15656      * @param {Number} top The new top
15657      * @returns {Roo.BoxComponent} this
15658      */
15659     setPosition : function(x, y){
15660         this.x = x;
15661         this.y = y;
15662         if(!this.boxReady){
15663             return this;
15664         }
15665         var adj = this.adjustPosition(x, y);
15666         var ax = adj.x, ay = adj.y;
15667
15668         var el = this.getPositionEl();
15669         if(ax !== undefined || ay !== undefined){
15670             if(ax !== undefined && ay !== undefined){
15671                 el.setLeftTop(ax, ay);
15672             }else if(ax !== undefined){
15673                 el.setLeft(ax);
15674             }else if(ay !== undefined){
15675                 el.setTop(ay);
15676             }
15677             this.onPosition(ax, ay);
15678             this.fireEvent('move', this, ax, ay);
15679         }
15680         return this;
15681     },
15682
15683     /**
15684      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15685      * This method fires the move event.
15686      * @param {Number} x The new x position
15687      * @param {Number} y The new y position
15688      * @returns {Roo.BoxComponent} this
15689      */
15690     setPagePosition : function(x, y){
15691         this.pageX = x;
15692         this.pageY = y;
15693         if(!this.boxReady){
15694             return;
15695         }
15696         if(x === undefined || y === undefined){ // cannot translate undefined points
15697             return;
15698         }
15699         var p = this.el.translatePoints(x, y);
15700         this.setPosition(p.left, p.top);
15701         return this;
15702     },
15703
15704     // private
15705     onRender : function(ct, position){
15706         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15707         if(this.resizeEl){
15708             this.resizeEl = Roo.get(this.resizeEl);
15709         }
15710         if(this.positionEl){
15711             this.positionEl = Roo.get(this.positionEl);
15712         }
15713     },
15714
15715     // private
15716     afterRender : function(){
15717         Roo.BoxComponent.superclass.afterRender.call(this);
15718         this.boxReady = true;
15719         this.setSize(this.width, this.height);
15720         if(this.x || this.y){
15721             this.setPosition(this.x, this.y);
15722         }
15723         if(this.pageX || this.pageY){
15724             this.setPagePosition(this.pageX, this.pageY);
15725         }
15726     },
15727
15728     /**
15729      * Force the component's size to recalculate based on the underlying element's current height and width.
15730      * @returns {Roo.BoxComponent} this
15731      */
15732     syncSize : function(){
15733         delete this.lastSize;
15734         this.setSize(this.el.getWidth(), this.el.getHeight());
15735         return this;
15736     },
15737
15738     /**
15739      * Called after the component is resized, this method is empty by default but can be implemented by any
15740      * subclass that needs to perform custom logic after a resize occurs.
15741      * @param {Number} adjWidth The box-adjusted width that was set
15742      * @param {Number} adjHeight The box-adjusted height that was set
15743      * @param {Number} rawWidth The width that was originally specified
15744      * @param {Number} rawHeight The height that was originally specified
15745      */
15746     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15747
15748     },
15749
15750     /**
15751      * Called after the component is moved, this method is empty by default but can be implemented by any
15752      * subclass that needs to perform custom logic after a move occurs.
15753      * @param {Number} x The new x position
15754      * @param {Number} y The new y position
15755      */
15756     onPosition : function(x, y){
15757
15758     },
15759
15760     // private
15761     adjustSize : function(w, h){
15762         if(this.autoWidth){
15763             w = 'auto';
15764         }
15765         if(this.autoHeight){
15766             h = 'auto';
15767         }
15768         return {width : w, height: h};
15769     },
15770
15771     // private
15772     adjustPosition : function(x, y){
15773         return {x : x, y: y};
15774     }
15775 });/*
15776  * Original code for Roojs - LGPL
15777  * <script type="text/javascript">
15778  */
15779  
15780 /**
15781  * @class Roo.XComponent
15782  * A delayed Element creator...
15783  * Or a way to group chunks of interface together.
15784  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15785  *  used in conjunction with XComponent.build() it will create an instance of each element,
15786  *  then call addxtype() to build the User interface.
15787  * 
15788  * Mypart.xyx = new Roo.XComponent({
15789
15790     parent : 'Mypart.xyz', // empty == document.element.!!
15791     order : '001',
15792     name : 'xxxx'
15793     region : 'xxxx'
15794     disabled : function() {} 
15795      
15796     tree : function() { // return an tree of xtype declared components
15797         var MODULE = this;
15798         return 
15799         {
15800             xtype : 'NestedLayoutPanel',
15801             // technicall
15802         }
15803      ]
15804  *})
15805  *
15806  *
15807  * It can be used to build a big heiracy, with parent etc.
15808  * or you can just use this to render a single compoent to a dom element
15809  * MYPART.render(Roo.Element | String(id) | dom_element )
15810  *
15811  *
15812  * Usage patterns.
15813  *
15814  * Classic Roo
15815  *
15816  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15817  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15818  *
15819  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15820  *
15821  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15822  * - if mulitple topModules exist, the last one is defined as the top module.
15823  *
15824  * Embeded Roo
15825  * 
15826  * When the top level or multiple modules are to embedded into a existing HTML page,
15827  * the parent element can container '#id' of the element where the module will be drawn.
15828  *
15829  * Bootstrap Roo
15830  *
15831  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15832  * it relies more on a include mechanism, where sub modules are included into an outer page.
15833  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15834  * 
15835  * Bootstrap Roo Included elements
15836  *
15837  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15838  * hence confusing the component builder as it thinks there are multiple top level elements. 
15839  *
15840  * 
15841  * 
15842  * @extends Roo.util.Observable
15843  * @constructor
15844  * @param cfg {Object} configuration of component
15845  * 
15846  */
15847 Roo.XComponent = function(cfg) {
15848     Roo.apply(this, cfg);
15849     this.addEvents({ 
15850         /**
15851              * @event built
15852              * Fires when this the componnt is built
15853              * @param {Roo.XComponent} c the component
15854              */
15855         'built' : true
15856         
15857     });
15858     this.region = this.region || 'center'; // default..
15859     Roo.XComponent.register(this);
15860     this.modules = false;
15861     this.el = false; // where the layout goes..
15862     
15863     
15864 }
15865 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15866     /**
15867      * @property el
15868      * The created element (with Roo.factory())
15869      * @type {Roo.Layout}
15870      */
15871     el  : false,
15872     
15873     /**
15874      * @property el
15875      * for BC  - use el in new code
15876      * @type {Roo.Layout}
15877      */
15878     panel : false,
15879     
15880     /**
15881      * @property layout
15882      * for BC  - use el in new code
15883      * @type {Roo.Layout}
15884      */
15885     layout : false,
15886     
15887      /**
15888      * @cfg {Function|boolean} disabled
15889      * If this module is disabled by some rule, return true from the funtion
15890      */
15891     disabled : false,
15892     
15893     /**
15894      * @cfg {String} parent 
15895      * Name of parent element which it get xtype added to..
15896      */
15897     parent: false,
15898     
15899     /**
15900      * @cfg {String} order
15901      * Used to set the order in which elements are created (usefull for multiple tabs)
15902      */
15903     
15904     order : false,
15905     /**
15906      * @cfg {String} name
15907      * String to display while loading.
15908      */
15909     name : false,
15910     /**
15911      * @cfg {String} region
15912      * Region to render component to (defaults to center)
15913      */
15914     region : 'center',
15915     
15916     /**
15917      * @cfg {Array} items
15918      * A single item array - the first element is the root of the tree..
15919      * It's done this way to stay compatible with the Xtype system...
15920      */
15921     items : false,
15922     
15923     /**
15924      * @property _tree
15925      * The method that retuns the tree of parts that make up this compoennt 
15926      * @type {function}
15927      */
15928     _tree  : false,
15929     
15930      /**
15931      * render
15932      * render element to dom or tree
15933      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15934      */
15935     
15936     render : function(el)
15937     {
15938         
15939         el = el || false;
15940         var hp = this.parent ? 1 : 0;
15941         Roo.debug &&  Roo.log(this);
15942         
15943         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15944             // if parent is a '#.....' string, then let's use that..
15945             var ename = this.parent.substr(1);
15946             this.parent = false;
15947             Roo.debug && Roo.log(ename);
15948             switch (ename) {
15949                 case 'bootstrap-body' :
15950                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15951                         this.parent = { el :  new  Roo.bootstrap.Body() };
15952                         Roo.debug && Roo.log("setting el to doc body");
15953                          
15954                     } else {
15955                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15956                     }
15957                     break;
15958                 case 'bootstrap':
15959                     this.parent = { el : true};
15960                     // fall through
15961                 default:
15962                     el = Roo.get(ename);
15963                     break;
15964             }
15965                 
15966             
15967             if (!el && !this.parent) {
15968                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15969                 return;
15970             }
15971         }
15972         Roo.debug && Roo.log("EL:");
15973         Roo.debug && Roo.log(el);
15974         Roo.debug && Roo.log("this.parent.el:");
15975         Roo.debug && Roo.log(this.parent.el);
15976         
15977         var tree = this._tree ? this._tree() : this.tree();
15978
15979         // altertive root elements ??? - we need a better way to indicate these.
15980         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15981                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15982         
15983         if (!this.parent && is_alt) {
15984             //el = Roo.get(document.body);
15985             this.parent = { el : true };
15986         }
15987             
15988             
15989         
15990         if (!this.parent) {
15991             
15992             Roo.debug && Roo.log("no parent - creating one");
15993             
15994             el = el ? Roo.get(el) : false;      
15995             
15996             // it's a top level one..
15997             this.parent =  {
15998                 el : new Roo.BorderLayout(el || document.body, {
15999                 
16000                      center: {
16001                          titlebar: false,
16002                          autoScroll:false,
16003                          closeOnTab: true,
16004                          tabPosition: 'top',
16005                           //resizeTabs: true,
16006                          alwaysShowTabs: el && hp? false :  true,
16007                          hideTabs: el || !hp ? true :  false,
16008                          minTabWidth: 140
16009                      }
16010                  })
16011             }
16012         }
16013         
16014         if (!this.parent.el) {
16015                 // probably an old style ctor, which has been disabled.
16016                 return;
16017
16018         }
16019                 // The 'tree' method is  '_tree now' 
16020             
16021         tree.region = tree.region || this.region;
16022         
16023         if (this.parent.el === true) {
16024             // bootstrap... - body..
16025             this.parent.el = Roo.factory(tree);
16026         }
16027         
16028         this.el = this.parent.el.addxtype(tree);
16029         this.fireEvent('built', this);
16030         
16031         this.panel = this.el;
16032         this.layout = this.panel.layout;
16033         this.parentLayout = this.parent.layout  || false;  
16034          
16035     }
16036     
16037 });
16038
16039 Roo.apply(Roo.XComponent, {
16040     /**
16041      * @property  hideProgress
16042      * true to disable the building progress bar.. usefull on single page renders.
16043      * @type Boolean
16044      */
16045     hideProgress : false,
16046     /**
16047      * @property  buildCompleted
16048      * True when the builder has completed building the interface.
16049      * @type Boolean
16050      */
16051     buildCompleted : false,
16052      
16053     /**
16054      * @property  topModule
16055      * the upper most module - uses document.element as it's constructor.
16056      * @type Object
16057      */
16058      
16059     topModule  : false,
16060       
16061     /**
16062      * @property  modules
16063      * array of modules to be created by registration system.
16064      * @type {Array} of Roo.XComponent
16065      */
16066     
16067     modules : [],
16068     /**
16069      * @property  elmodules
16070      * array of modules to be created by which use #ID 
16071      * @type {Array} of Roo.XComponent
16072      */
16073      
16074     elmodules : [],
16075
16076      /**
16077      * @property  build_from_html
16078      * Build elements from html - used by bootstrap HTML stuff 
16079      *    - this is cleared after build is completed
16080      * @type {boolean} true  (default false)
16081      */
16082      
16083     build_from_html : false,
16084
16085     /**
16086      * Register components to be built later.
16087      *
16088      * This solves the following issues
16089      * - Building is not done on page load, but after an authentication process has occured.
16090      * - Interface elements are registered on page load
16091      * - Parent Interface elements may not be loaded before child, so this handles that..
16092      * 
16093      *
16094      * example:
16095      * 
16096      * MyApp.register({
16097           order : '000001',
16098           module : 'Pman.Tab.projectMgr',
16099           region : 'center',
16100           parent : 'Pman.layout',
16101           disabled : false,  // or use a function..
16102         })
16103      
16104      * * @param {Object} details about module
16105      */
16106     register : function(obj) {
16107                 
16108         Roo.XComponent.event.fireEvent('register', obj);
16109         switch(typeof(obj.disabled) ) {
16110                 
16111             case 'undefined':
16112                 break;
16113             
16114             case 'function':
16115                 if ( obj.disabled() ) {
16116                         return;
16117                 }
16118                 break;
16119             
16120             default:
16121                 if (obj.disabled) {
16122                         return;
16123                 }
16124                 break;
16125         }
16126                 
16127         this.modules.push(obj);
16128          
16129     },
16130     /**
16131      * convert a string to an object..
16132      * eg. 'AAA.BBB' -> finds AAA.BBB
16133
16134      */
16135     
16136     toObject : function(str)
16137     {
16138         if (!str || typeof(str) == 'object') {
16139             return str;
16140         }
16141         if (str.substring(0,1) == '#') {
16142             return str;
16143         }
16144
16145         var ar = str.split('.');
16146         var rt, o;
16147         rt = ar.shift();
16148             /** eval:var:o */
16149         try {
16150             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16151         } catch (e) {
16152             throw "Module not found : " + str;
16153         }
16154         
16155         if (o === false) {
16156             throw "Module not found : " + str;
16157         }
16158         Roo.each(ar, function(e) {
16159             if (typeof(o[e]) == 'undefined') {
16160                 throw "Module not found : " + str;
16161             }
16162             o = o[e];
16163         });
16164         
16165         return o;
16166         
16167     },
16168     
16169     
16170     /**
16171      * move modules into their correct place in the tree..
16172      * 
16173      */
16174     preBuild : function ()
16175     {
16176         var _t = this;
16177         Roo.each(this.modules , function (obj)
16178         {
16179             Roo.XComponent.event.fireEvent('beforebuild', obj);
16180             
16181             var opar = obj.parent;
16182             try { 
16183                 obj.parent = this.toObject(opar);
16184             } catch(e) {
16185                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16186                 return;
16187             }
16188             
16189             if (!obj.parent) {
16190                 Roo.debug && Roo.log("GOT top level module");
16191                 Roo.debug && Roo.log(obj);
16192                 obj.modules = new Roo.util.MixedCollection(false, 
16193                     function(o) { return o.order + '' }
16194                 );
16195                 this.topModule = obj;
16196                 return;
16197             }
16198                         // parent is a string (usually a dom element name..)
16199             if (typeof(obj.parent) == 'string') {
16200                 this.elmodules.push(obj);
16201                 return;
16202             }
16203             if (obj.parent.constructor != Roo.XComponent) {
16204                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16205             }
16206             if (!obj.parent.modules) {
16207                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16208                     function(o) { return o.order + '' }
16209                 );
16210             }
16211             if (obj.parent.disabled) {
16212                 obj.disabled = true;
16213             }
16214             obj.parent.modules.add(obj);
16215         }, this);
16216     },
16217     
16218      /**
16219      * make a list of modules to build.
16220      * @return {Array} list of modules. 
16221      */ 
16222     
16223     buildOrder : function()
16224     {
16225         var _this = this;
16226         var cmp = function(a,b) {   
16227             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16228         };
16229         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16230             throw "No top level modules to build";
16231         }
16232         
16233         // make a flat list in order of modules to build.
16234         var mods = this.topModule ? [ this.topModule ] : [];
16235                 
16236         
16237         // elmodules (is a list of DOM based modules )
16238         Roo.each(this.elmodules, function(e) {
16239             mods.push(e);
16240             if (!this.topModule &&
16241                 typeof(e.parent) == 'string' &&
16242                 e.parent.substring(0,1) == '#' &&
16243                 Roo.get(e.parent.substr(1))
16244                ) {
16245                 
16246                 _this.topModule = e;
16247             }
16248             
16249         });
16250
16251         
16252         // add modules to their parents..
16253         var addMod = function(m) {
16254             Roo.debug && Roo.log("build Order: add: " + m.name);
16255                 
16256             mods.push(m);
16257             if (m.modules && !m.disabled) {
16258                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16259                 m.modules.keySort('ASC',  cmp );
16260                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16261     
16262                 m.modules.each(addMod);
16263             } else {
16264                 Roo.debug && Roo.log("build Order: no child modules");
16265             }
16266             // not sure if this is used any more..
16267             if (m.finalize) {
16268                 m.finalize.name = m.name + " (clean up) ";
16269                 mods.push(m.finalize);
16270             }
16271             
16272         }
16273         if (this.topModule && this.topModule.modules) { 
16274             this.topModule.modules.keySort('ASC',  cmp );
16275             this.topModule.modules.each(addMod);
16276         } 
16277         return mods;
16278     },
16279     
16280      /**
16281      * Build the registered modules.
16282      * @param {Object} parent element.
16283      * @param {Function} optional method to call after module has been added.
16284      * 
16285      */ 
16286    
16287     build : function(opts) 
16288     {
16289         
16290         if (typeof(opts) != 'undefined') {
16291             Roo.apply(this,opts);
16292         }
16293         
16294         this.preBuild();
16295         var mods = this.buildOrder();
16296       
16297         //this.allmods = mods;
16298         //Roo.debug && Roo.log(mods);
16299         //return;
16300         if (!mods.length) { // should not happen
16301             throw "NO modules!!!";
16302         }
16303         
16304         
16305         var msg = "Building Interface...";
16306         // flash it up as modal - so we store the mask!?
16307         if (!this.hideProgress && Roo.MessageBox) {
16308             Roo.MessageBox.show({ title: 'loading' });
16309             Roo.MessageBox.show({
16310                title: "Please wait...",
16311                msg: msg,
16312                width:450,
16313                progress:true,
16314                closable:false,
16315                modal: false
16316               
16317             });
16318         }
16319         var total = mods.length;
16320         
16321         var _this = this;
16322         var progressRun = function() {
16323             if (!mods.length) {
16324                 Roo.debug && Roo.log('hide?');
16325                 if (!this.hideProgress && Roo.MessageBox) {
16326                     Roo.MessageBox.hide();
16327                 }
16328                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16329                 
16330                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16331                 
16332                 // THE END...
16333                 return false;   
16334             }
16335             
16336             var m = mods.shift();
16337             
16338             
16339             Roo.debug && Roo.log(m);
16340             // not sure if this is supported any more.. - modules that are are just function
16341             if (typeof(m) == 'function') { 
16342                 m.call(this);
16343                 return progressRun.defer(10, _this);
16344             } 
16345             
16346             
16347             msg = "Building Interface " + (total  - mods.length) + 
16348                     " of " + total + 
16349                     (m.name ? (' - ' + m.name) : '');
16350                         Roo.debug && Roo.log(msg);
16351             if (!this.hideProgress &&  Roo.MessageBox) { 
16352                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16353             }
16354             
16355          
16356             // is the module disabled?
16357             var disabled = (typeof(m.disabled) == 'function') ?
16358                 m.disabled.call(m.module.disabled) : m.disabled;    
16359             
16360             
16361             if (disabled) {
16362                 return progressRun(); // we do not update the display!
16363             }
16364             
16365             // now build 
16366             
16367                         
16368                         
16369             m.render();
16370             // it's 10 on top level, and 1 on others??? why...
16371             return progressRun.defer(10, _this);
16372              
16373         }
16374         progressRun.defer(1, _this);
16375      
16376         
16377         
16378     },
16379         
16380         
16381         /**
16382          * Event Object.
16383          *
16384          *
16385          */
16386         event: false, 
16387     /**
16388          * wrapper for event.on - aliased later..  
16389          * Typically use to register a event handler for register:
16390          *
16391          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16392          *
16393          */
16394     on : false
16395    
16396     
16397     
16398 });
16399
16400 Roo.XComponent.event = new Roo.util.Observable({
16401                 events : { 
16402                         /**
16403                          * @event register
16404                          * Fires when an Component is registered,
16405                          * set the disable property on the Component to stop registration.
16406                          * @param {Roo.XComponent} c the component being registerd.
16407                          * 
16408                          */
16409                         'register' : true,
16410             /**
16411                          * @event beforebuild
16412                          * Fires before each Component is built
16413                          * can be used to apply permissions.
16414                          * @param {Roo.XComponent} c the component being registerd.
16415                          * 
16416                          */
16417                         'beforebuild' : true,
16418                         /**
16419                          * @event buildcomplete
16420                          * Fires on the top level element when all elements have been built
16421                          * @param {Roo.XComponent} the top level component.
16422                          */
16423                         'buildcomplete' : true
16424                         
16425                 }
16426 });
16427
16428 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16429