roojs-core-debug.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
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 = 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, "=", 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, "=", 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         /**
360          * 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]}.
361          * @param {String} string
362          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
363          * @return {Object} A literal with members
364          */
365         urlDecode : function(string, overwrite){
366             if(!string || !string.length){
367                 return {};
368             }
369             var obj = {};
370             var pairs = string.split('&');
371             var pair, name, value;
372             for(var i = 0, len = pairs.length; i < len; i++){
373                 pair = pairs[i].split('=');
374                 name = decodeURIComponent(pair[0]);
375                 value = decodeURIComponent(pair[1]);
376                 if(overwrite !== true){
377                     if(typeof obj[name] == "undefined"){
378                         obj[name] = value;
379                     }else if(typeof obj[name] == "string"){
380                         obj[name] = [obj[name]];
381                         obj[name].push(value);
382                     }else{
383                         obj[name].push(value);
384                     }
385                 }else{
386                     obj[name] = value;
387                 }
388             }
389             return obj;
390         },
391
392         /**
393          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
394          * passed array is not really an array, your function is called once with it.
395          * The supplied function is called with (Object item, Number index, Array allItems).
396          * @param {Array/NodeList/Mixed} array
397          * @param {Function} fn
398          * @param {Object} scope
399          */
400         each : function(array, fn, scope){
401             if(typeof array.length == "undefined" || typeof array == "string"){
402                 array = [array];
403             }
404             for(var i = 0, len = array.length; i < len; i++){
405                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
406             }
407         },
408
409         // deprecated
410         combine : function(){
411             var as = arguments, l = as.length, r = [];
412             for(var i = 0; i < l; i++){
413                 var a = as[i];
414                 if(a instanceof Array){
415                     r = r.concat(a);
416                 }else if(a.length !== undefined && !a.substr){
417                     r = r.concat(Array.prototype.slice.call(a, 0));
418                 }else{
419                     r.push(a);
420                 }
421             }
422             return r;
423         },
424
425         /**
426          * Escapes the passed string for use in a regular expression
427          * @param {String} str
428          * @return {String}
429          */
430         escapeRe : function(s) {
431             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
432         },
433
434         // internal
435         callback : function(cb, scope, args, delay){
436             if(typeof cb == "function"){
437                 if(delay){
438                     cb.defer(delay, scope, args || []);
439                 }else{
440                     cb.apply(scope, args || []);
441                 }
442             }
443         },
444
445         /**
446          * Return the dom node for the passed string (id), dom node, or Roo.Element
447          * @param {String/HTMLElement/Roo.Element} el
448          * @return HTMLElement
449          */
450         getDom : function(el){
451             if(!el){
452                 return null;
453             }
454             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
455         },
456
457         /**
458         * Shorthand for {@link Roo.ComponentMgr#get}
459         * @param {String} id
460         * @return Roo.Component
461         */
462         getCmp : function(id){
463             return Roo.ComponentMgr.get(id);
464         },
465          
466         num : function(v, defaultValue){
467             if(typeof v != 'number'){
468                 return defaultValue;
469             }
470             return v;
471         },
472
473         destroy : function(){
474             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
475                 var as = a[i];
476                 if(as){
477                     if(as.dom){
478                         as.removeAllListeners();
479                         as.remove();
480                         continue;
481                     }
482                     if(typeof as.purgeListeners == 'function'){
483                         as.purgeListeners();
484                     }
485                     if(typeof as.destroy == 'function'){
486                         as.destroy();
487                     }
488                 }
489             }
490         },
491
492         // inpired by a similar function in mootools library
493         /**
494          * Returns the type of object that is passed in. If the object passed in is null or undefined it
495          * return false otherwise it returns one of the following values:<ul>
496          * <li><b>string</b>: If the object passed is a string</li>
497          * <li><b>number</b>: If the object passed is a number</li>
498          * <li><b>boolean</b>: If the object passed is a boolean value</li>
499          * <li><b>function</b>: If the object passed is a function reference</li>
500          * <li><b>object</b>: If the object passed is an object</li>
501          * <li><b>array</b>: If the object passed is an array</li>
502          * <li><b>regexp</b>: If the object passed is a regular expression</li>
503          * <li><b>element</b>: If the object passed is a DOM Element</li>
504          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
505          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
506          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
507          * @param {Mixed} object
508          * @return {String}
509          */
510         type : function(o){
511             if(o === undefined || o === null){
512                 return false;
513             }
514             if(o.htmlElement){
515                 return 'element';
516             }
517             var t = typeof o;
518             if(t == 'object' && o.nodeName) {
519                 switch(o.nodeType) {
520                     case 1: return 'element';
521                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
522                 }
523             }
524             if(t == 'object' || t == 'function') {
525                 switch(o.constructor) {
526                     case Array: return 'array';
527                     case RegExp: return 'regexp';
528                 }
529                 if(typeof o.length == 'number' && typeof o.item == 'function') {
530                     return 'nodelist';
531                 }
532             }
533             return t;
534         },
535
536         /**
537          * Returns true if the passed value is null, undefined or an empty string (optional).
538          * @param {Mixed} value The value to test
539          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
540          * @return {Boolean}
541          */
542         isEmpty : function(v, allowBlank){
543             return v === null || v === undefined || (!allowBlank ? v === '' : false);
544         },
545         
546         /** @type Boolean */
547         isOpera : isOpera,
548         /** @type Boolean */
549         isSafari : isSafari,
550         /** @type Boolean */
551         isIE : isIE,
552         /** @type Boolean */
553         isIE7 : isIE7,
554         /** @type Boolean */
555         isGecko : isGecko,
556         /** @type Boolean */
557         isBorderBox : isBorderBox,
558         /** @type Boolean */
559         isWindows : isWindows,
560         /** @type Boolean */
561         isLinux : isLinux,
562         /** @type Boolean */
563         isMac : isMac,
564
565         /**
566          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
567          * you may want to set this to true.
568          * @type Boolean
569          */
570         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
571         
572         
573                 
574         /**
575          * Selects a single element as a Roo Element
576          * This is about as close as you can get to jQuery's $('do crazy stuff')
577          * @param {String} selector The selector/xpath query
578          * @param {Node} root (optional) The start of the query (defaults to document).
579          * @return {Roo.Element}
580          */
581         selectNode : function(selector, root) 
582         {
583             var node = Roo.DomQuery.selectNode(selector,root);
584             return node ? Roo.get(node) : false;
585         }
586         
587     });
588
589
590 })();
591
592 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
593                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
594 /*
595  * Based on:
596  * Ext JS Library 1.1.1
597  * Copyright(c) 2006-2007, Ext JS, LLC.
598  *
599  * Originally Released Under LGPL - original licence link has changed is not relivant.
600  *
601  * Fork - LGPL
602  * <script type="text/javascript">
603  */
604
605 (function() {    
606     // wrappedn so fnCleanup is not in global scope...
607     if(Roo.isIE) {
608         function fnCleanUp() {
609             var p = Function.prototype;
610             delete p.createSequence;
611             delete p.defer;
612             delete p.createDelegate;
613             delete p.createCallback;
614             delete p.createInterceptor;
615
616             window.detachEvent("onunload", fnCleanUp);
617         }
618         window.attachEvent("onunload", fnCleanUp);
619     }
620 })();
621
622
623 /**
624  * @class Function
625  * These functions are available on every Function object (any JavaScript function).
626  */
627 Roo.apply(Function.prototype, {
628      /**
629      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
630      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
631      * Will create a function that is bound to those 2 args.
632      * @return {Function} The new function
633     */
634     createCallback : function(/*args...*/){
635         // make args available, in function below
636         var args = arguments;
637         var method = this;
638         return function() {
639             return method.apply(window, args);
640         };
641     },
642
643     /**
644      * Creates a delegate (callback) that sets the scope to obj.
645      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
646      * Will create a function that is automatically scoped to this.
647      * @param {Object} obj (optional) The object for which the scope is set
648      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
649      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
650      *                                             if a number the args are inserted at the specified position
651      * @return {Function} The new function
652      */
653     createDelegate : function(obj, args, appendArgs){
654         var method = this;
655         return function() {
656             var callArgs = args || arguments;
657             if(appendArgs === true){
658                 callArgs = Array.prototype.slice.call(arguments, 0);
659                 callArgs = callArgs.concat(args);
660             }else if(typeof appendArgs == "number"){
661                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
662                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
663                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
664             }
665             return method.apply(obj || window, callArgs);
666         };
667     },
668
669     /**
670      * Calls this function after the number of millseconds specified.
671      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
672      * @param {Object} obj (optional) The object for which the scope is set
673      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
674      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
675      *                                             if a number the args are inserted at the specified position
676      * @return {Number} The timeout id that can be used with clearTimeout
677      */
678     defer : function(millis, obj, args, appendArgs){
679         var fn = this.createDelegate(obj, args, appendArgs);
680         if(millis){
681             return setTimeout(fn, millis);
682         }
683         fn();
684         return 0;
685     },
686     /**
687      * Create a combined function call sequence of the original function + the passed function.
688      * The resulting function returns the results of the original function.
689      * The passed fcn is called with the parameters of the original function
690      * @param {Function} fcn The function to sequence
691      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
692      * @return {Function} The new function
693      */
694     createSequence : function(fcn, scope){
695         if(typeof fcn != "function"){
696             return this;
697         }
698         var method = this;
699         return function() {
700             var retval = method.apply(this || window, arguments);
701             fcn.apply(scope || this || window, arguments);
702             return retval;
703         };
704     },
705
706     /**
707      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
708      * The resulting function returns the results of the original function.
709      * The passed fcn is called with the parameters of the original function.
710      * @addon
711      * @param {Function} fcn The function to call before the original
712      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
713      * @return {Function} The new function
714      */
715     createInterceptor : function(fcn, scope){
716         if(typeof fcn != "function"){
717             return this;
718         }
719         var method = this;
720         return function() {
721             fcn.target = this;
722             fcn.method = method;
723             if(fcn.apply(scope || this || window, arguments) === false){
724                 return;
725             }
726             return method.apply(this || window, arguments);
727         };
728     }
729 });
730 /*
731  * Based on:
732  * Ext JS Library 1.1.1
733  * Copyright(c) 2006-2007, Ext JS, LLC.
734  *
735  * Originally Released Under LGPL - original licence link has changed is not relivant.
736  *
737  * Fork - LGPL
738  * <script type="text/javascript">
739  */
740
741 Roo.applyIf(String, {
742     
743     /** @scope String */
744     
745     /**
746      * Escapes the passed string for ' and \
747      * @param {String} string The string to escape
748      * @return {String} The escaped string
749      * @static
750      */
751     escape : function(string) {
752         return string.replace(/('|\\)/g, "\\$1");
753     },
754
755     /**
756      * Pads the left side of a string with a specified character.  This is especially useful
757      * for normalizing number and date strings.  Example usage:
758      * <pre><code>
759 var s = String.leftPad('123', 5, '0');
760 // s now contains the string: '00123'
761 </code></pre>
762      * @param {String} string The original string
763      * @param {Number} size The total length of the output string
764      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
765      * @return {String} The padded string
766      * @static
767      */
768     leftPad : function (val, size, ch) {
769         var result = new String(val);
770         if(ch === null || ch === undefined || ch === '') {
771             ch = " ";
772         }
773         while (result.length < size) {
774             result = ch + result;
775         }
776         return result;
777     },
778
779     /**
780      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
781      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
782      * <pre><code>
783 var cls = 'my-class', text = 'Some text';
784 var s = String.format('<div class="{0}">{1}</div>', cls, text);
785 // s now contains the string: '<div class="my-class">Some text</div>'
786 </code></pre>
787      * @param {String} string The tokenized string to be formatted
788      * @param {String} value1 The value to replace token {0}
789      * @param {String} value2 Etc...
790      * @return {String} The formatted string
791      * @static
792      */
793     format : function(format){
794         var args = Array.prototype.slice.call(arguments, 1);
795         return format.replace(/\{(\d+)\}/g, function(m, i){
796             return Roo.util.Format.htmlEncode(args[i]);
797         });
798     }
799 });
800
801 /**
802  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
803  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
804  * they are already different, the first value passed in is returned.  Note that this method returns the new value
805  * but does not change the current string.
806  * <pre><code>
807 // alternate sort directions
808 sort = sort.toggle('ASC', 'DESC');
809
810 // instead of conditional logic:
811 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
812 </code></pre>
813  * @param {String} value The value to compare to the current string
814  * @param {String} other The new value to use if the string already equals the first value passed in
815  * @return {String} The new value
816  */
817  
818 String.prototype.toggle = function(value, other){
819     return this == value ? other : value;
820 };/*
821  * Based on:
822  * Ext JS Library 1.1.1
823  * Copyright(c) 2006-2007, Ext JS, LLC.
824  *
825  * Originally Released Under LGPL - original licence link has changed is not relivant.
826  *
827  * Fork - LGPL
828  * <script type="text/javascript">
829  */
830
831  /**
832  * @class Number
833  */
834 Roo.applyIf(Number.prototype, {
835     /**
836      * Checks whether or not the current number is within a desired range.  If the number is already within the
837      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
838      * exceeded.  Note that this method returns the constrained value but does not change the current number.
839      * @param {Number} min The minimum number in the range
840      * @param {Number} max The maximum number in the range
841      * @return {Number} The constrained value if outside the range, otherwise the current value
842      */
843     constrain : function(min, max){
844         return Math.min(Math.max(this, min), max);
845     }
846 });/*
847  * Based on:
848  * Ext JS Library 1.1.1
849  * Copyright(c) 2006-2007, Ext JS, LLC.
850  *
851  * Originally Released Under LGPL - original licence link has changed is not relivant.
852  *
853  * Fork - LGPL
854  * <script type="text/javascript">
855  */
856  /**
857  * @class Array
858  */
859 Roo.applyIf(Array.prototype, {
860     /**
861      * Checks whether or not the specified object exists in the array.
862      * @param {Object} o The object to check for
863      * @return {Number} The index of o in the array (or -1 if it is not found)
864      */
865     indexOf : function(o){
866        for (var i = 0, len = this.length; i < len; i++){
867               if(this[i] == o) return i;
868        }
869            return -1;
870     },
871
872     /**
873      * Removes the specified object from the array.  If the object is not found nothing happens.
874      * @param {Object} o The object to remove
875      */
876     remove : function(o){
877        var index = this.indexOf(o);
878        if(index != -1){
879            this.splice(index, 1);
880        }
881     },
882     /**
883      * Map (JS 1.6 compatibility)
884      * @param {Function} function  to call
885      */
886     map : function(fun )
887     {
888         var len = this.length >>> 0;
889         if (typeof fun != "function")
890             throw new TypeError();
891
892         var res = new Array(len);
893         var thisp = arguments[1];
894         for (var i = 0; i < len; i++)
895         {
896             if (i in this)
897                 res[i] = fun.call(thisp, this[i], i, this);
898         }
899
900         return res;
901     }
902     
903 });
904
905
906  /*
907  * Based on:
908  * Ext JS Library 1.1.1
909  * Copyright(c) 2006-2007, Ext JS, LLC.
910  *
911  * Originally Released Under LGPL - original licence link has changed is not relivant.
912  *
913  * Fork - LGPL
914  * <script type="text/javascript">
915  */
916
917 /**
918  * @class Date
919  *
920  * The date parsing and format syntax is a subset of
921  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
922  * supported will provide results equivalent to their PHP versions.
923  *
924  * Following is the list of all currently supported formats:
925  *<pre>
926 Sample date:
927 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
928
929 Format  Output      Description
930 ------  ----------  --------------------------------------------------------------
931   d      10         Day of the month, 2 digits with leading zeros
932   D      Wed        A textual representation of a day, three letters
933   j      10         Day of the month without leading zeros
934   l      Wednesday  A full textual representation of the day of the week
935   S      th         English ordinal day of month suffix, 2 chars (use with j)
936   w      3          Numeric representation of the day of the week
937   z      9          The julian date, or day of the year (0-365)
938   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
939   F      January    A full textual representation of the month
940   m      01         Numeric representation of a month, with leading zeros
941   M      Jan        Month name abbreviation, three letters
942   n      1          Numeric representation of a month, without leading zeros
943   t      31         Number of days in the given month
944   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
945   Y      2007       A full numeric representation of a year, 4 digits
946   y      07         A two digit representation of a year
947   a      pm         Lowercase Ante meridiem and Post meridiem
948   A      PM         Uppercase Ante meridiem and Post meridiem
949   g      3          12-hour format of an hour without leading zeros
950   G      15         24-hour format of an hour without leading zeros
951   h      03         12-hour format of an hour with leading zeros
952   H      15         24-hour format of an hour with leading zeros
953   i      05         Minutes with leading zeros
954   s      01         Seconds, with leading zeros
955   O      -0600      Difference to Greenwich time (GMT) in hours
956   T      CST        Timezone setting of the machine running the code
957   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
958 </pre>
959  *
960  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
961  * <pre><code>
962 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
963 document.write(dt.format('Y-m-d'));                         //2007-01-10
964 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
965 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
966  </code></pre>
967  *
968  * Here are some standard date/time patterns that you might find helpful.  They
969  * are not part of the source of Date.js, but to use them you can simply copy this
970  * block of code into any script that is included after Date.js and they will also become
971  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
972  * <pre><code>
973 Date.patterns = {
974     ISO8601Long:"Y-m-d H:i:s",
975     ISO8601Short:"Y-m-d",
976     ShortDate: "n/j/Y",
977     LongDate: "l, F d, Y",
978     FullDateTime: "l, F d, Y g:i:s A",
979     MonthDay: "F d",
980     ShortTime: "g:i A",
981     LongTime: "g:i:s A",
982     SortableDateTime: "Y-m-d\\TH:i:s",
983     UniversalSortableDateTime: "Y-m-d H:i:sO",
984     YearMonth: "F, Y"
985 };
986 </code></pre>
987  *
988  * Example usage:
989  * <pre><code>
990 var dt = new Date();
991 document.write(dt.format(Date.patterns.ShortDate));
992  </code></pre>
993  */
994
995 /*
996  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
997  * They generate precompiled functions from date formats instead of parsing and
998  * processing the pattern every time you format a date.  These functions are available
999  * on every Date object (any javascript function).
1000  *
1001  * The original article and download are here:
1002  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1003  *
1004  */
1005  
1006  
1007  // was in core
1008 /**
1009  Returns the number of milliseconds between this date and date
1010  @param {Date} date (optional) Defaults to now
1011  @return {Number} The diff in milliseconds
1012  @member Date getElapsed
1013  */
1014 Date.prototype.getElapsed = function(date) {
1015         return Math.abs((date || new Date()).getTime()-this.getTime());
1016 };
1017 // was in date file..
1018
1019
1020 // private
1021 Date.parseFunctions = {count:0};
1022 // private
1023 Date.parseRegexes = [];
1024 // private
1025 Date.formatFunctions = {count:0};
1026
1027 // private
1028 Date.prototype.dateFormat = function(format) {
1029     if (Date.formatFunctions[format] == null) {
1030         Date.createNewFormat(format);
1031     }
1032     var func = Date.formatFunctions[format];
1033     return this[func]();
1034 };
1035
1036
1037 /**
1038  * Formats a date given the supplied format string
1039  * @param {String} format The format string
1040  * @return {String} The formatted date
1041  * @method
1042  */
1043 Date.prototype.format = Date.prototype.dateFormat;
1044
1045 // private
1046 Date.createNewFormat = function(format) {
1047     var funcName = "format" + Date.formatFunctions.count++;
1048     Date.formatFunctions[format] = funcName;
1049     var code = "Date.prototype." + funcName + " = function(){return ";
1050     var special = false;
1051     var ch = '';
1052     for (var i = 0; i < format.length; ++i) {
1053         ch = format.charAt(i);
1054         if (!special && ch == "\\") {
1055             special = true;
1056         }
1057         else if (special) {
1058             special = false;
1059             code += "'" + String.escape(ch) + "' + ";
1060         }
1061         else {
1062             code += Date.getFormatCode(ch);
1063         }
1064     }
1065     /** eval:var:zzzzzzzzzzzzz */
1066     eval(code.substring(0, code.length - 3) + ";}");
1067 };
1068
1069 // private
1070 Date.getFormatCode = function(character) {
1071     switch (character) {
1072     case "d":
1073         return "String.leftPad(this.getDate(), 2, '0') + ";
1074     case "D":
1075         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1076     case "j":
1077         return "this.getDate() + ";
1078     case "l":
1079         return "Date.dayNames[this.getDay()] + ";
1080     case "S":
1081         return "this.getSuffix() + ";
1082     case "w":
1083         return "this.getDay() + ";
1084     case "z":
1085         return "this.getDayOfYear() + ";
1086     case "W":
1087         return "this.getWeekOfYear() + ";
1088     case "F":
1089         return "Date.monthNames[this.getMonth()] + ";
1090     case "m":
1091         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1092     case "M":
1093         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1094     case "n":
1095         return "(this.getMonth() + 1) + ";
1096     case "t":
1097         return "this.getDaysInMonth() + ";
1098     case "L":
1099         return "(this.isLeapYear() ? 1 : 0) + ";
1100     case "Y":
1101         return "this.getFullYear() + ";
1102     case "y":
1103         return "('' + this.getFullYear()).substring(2, 4) + ";
1104     case "a":
1105         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1106     case "A":
1107         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1108     case "g":
1109         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1110     case "G":
1111         return "this.getHours() + ";
1112     case "h":
1113         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1114     case "H":
1115         return "String.leftPad(this.getHours(), 2, '0') + ";
1116     case "i":
1117         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1118     case "s":
1119         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1120     case "O":
1121         return "this.getGMTOffset() + ";
1122     case "T":
1123         return "this.getTimezone() + ";
1124     case "Z":
1125         return "(this.getTimezoneOffset() * -60) + ";
1126     default:
1127         return "'" + String.escape(character) + "' + ";
1128     }
1129 };
1130
1131 /**
1132  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1133  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1134  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1135  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1136  * string or the parse operation will fail.
1137  * Example Usage:
1138 <pre><code>
1139 //dt = Fri May 25 2007 (current date)
1140 var dt = new Date();
1141
1142 //dt = Thu May 25 2006 (today's month/day in 2006)
1143 dt = Date.parseDate("2006", "Y");
1144
1145 //dt = Sun Jan 15 2006 (all date parts specified)
1146 dt = Date.parseDate("2006-1-15", "Y-m-d");
1147
1148 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1149 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1150 </code></pre>
1151  * @param {String} input The unparsed date as a string
1152  * @param {String} format The format the date is in
1153  * @return {Date} The parsed date
1154  * @static
1155  */
1156 Date.parseDate = function(input, format) {
1157     if (Date.parseFunctions[format] == null) {
1158         Date.createParser(format);
1159     }
1160     var func = Date.parseFunctions[format];
1161     return Date[func](input);
1162 };
1163 /**
1164  * @private
1165  */
1166 Date.createParser = function(format) {
1167     var funcName = "parse" + Date.parseFunctions.count++;
1168     var regexNum = Date.parseRegexes.length;
1169     var currentGroup = 1;
1170     Date.parseFunctions[format] = funcName;
1171
1172     var code = "Date." + funcName + " = function(input){\n"
1173         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1174         + "var d = new Date();\n"
1175         + "y = d.getFullYear();\n"
1176         + "m = d.getMonth();\n"
1177         + "d = d.getDate();\n"
1178         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1179         + "if (results && results.length > 0) {";
1180     var regex = "";
1181
1182     var special = false;
1183     var ch = '';
1184     for (var i = 0; i < format.length; ++i) {
1185         ch = format.charAt(i);
1186         if (!special && ch == "\\") {
1187             special = true;
1188         }
1189         else if (special) {
1190             special = false;
1191             regex += String.escape(ch);
1192         }
1193         else {
1194             var obj = Date.formatCodeToRegex(ch, currentGroup);
1195             currentGroup += obj.g;
1196             regex += obj.s;
1197             if (obj.g && obj.c) {
1198                 code += obj.c;
1199             }
1200         }
1201     }
1202
1203     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1204         + "{v = new Date(y, m, d, h, i, s);}\n"
1205         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1206         + "{v = new Date(y, m, d, h, i);}\n"
1207         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1208         + "{v = new Date(y, m, d, h);}\n"
1209         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1210         + "{v = new Date(y, m, d);}\n"
1211         + "else if (y >= 0 && m >= 0)\n"
1212         + "{v = new Date(y, m);}\n"
1213         + "else if (y >= 0)\n"
1214         + "{v = new Date(y);}\n"
1215         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1216         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1217         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1218         + ";}";
1219
1220     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1221     /** eval:var:zzzzzzzzzzzzz */
1222     eval(code);
1223 };
1224
1225 // private
1226 Date.formatCodeToRegex = function(character, currentGroup) {
1227     switch (character) {
1228     case "D":
1229         return {g:0,
1230         c:null,
1231         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1232     case "j":
1233         return {g:1,
1234             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1235             s:"(\\d{1,2})"}; // day of month without leading zeroes
1236     case "d":
1237         return {g:1,
1238             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1239             s:"(\\d{2})"}; // day of month with leading zeroes
1240     case "l":
1241         return {g:0,
1242             c:null,
1243             s:"(?:" + Date.dayNames.join("|") + ")"};
1244     case "S":
1245         return {g:0,
1246             c:null,
1247             s:"(?:st|nd|rd|th)"};
1248     case "w":
1249         return {g:0,
1250             c:null,
1251             s:"\\d"};
1252     case "z":
1253         return {g:0,
1254             c:null,
1255             s:"(?:\\d{1,3})"};
1256     case "W":
1257         return {g:0,
1258             c:null,
1259             s:"(?:\\d{2})"};
1260     case "F":
1261         return {g:1,
1262             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1263             s:"(" + Date.monthNames.join("|") + ")"};
1264     case "M":
1265         return {g:1,
1266             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1267             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1268     case "n":
1269         return {g:1,
1270             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1271             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1272     case "m":
1273         return {g:1,
1274             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1275             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1276     case "t":
1277         return {g:0,
1278             c:null,
1279             s:"\\d{1,2}"};
1280     case "L":
1281         return {g:0,
1282             c:null,
1283             s:"(?:1|0)"};
1284     case "Y":
1285         return {g:1,
1286             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1287             s:"(\\d{4})"};
1288     case "y":
1289         return {g:1,
1290             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1291                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1292             s:"(\\d{1,2})"};
1293     case "a":
1294         return {g:1,
1295             c:"if (results[" + currentGroup + "] == 'am') {\n"
1296                 + "if (h == 12) { h = 0; }\n"
1297                 + "} else { if (h < 12) { h += 12; }}",
1298             s:"(am|pm)"};
1299     case "A":
1300         return {g:1,
1301             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1302                 + "if (h == 12) { h = 0; }\n"
1303                 + "} else { if (h < 12) { h += 12; }}",
1304             s:"(AM|PM)"};
1305     case "g":
1306     case "G":
1307         return {g:1,
1308             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1309             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1310     case "h":
1311     case "H":
1312         return {g:1,
1313             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1314             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1315     case "i":
1316         return {g:1,
1317             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1318             s:"(\\d{2})"};
1319     case "s":
1320         return {g:1,
1321             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1322             s:"(\\d{2})"};
1323     case "O":
1324         return {g:1,
1325             c:[
1326                 "o = results[", currentGroup, "];\n",
1327                 "var sn = o.substring(0,1);\n", // get + / - sign
1328                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1329                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1330                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1331                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1332             ].join(""),
1333             s:"([+\-]\\d{4})"};
1334     case "T":
1335         return {g:0,
1336             c:null,
1337             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1338     case "Z":
1339         return {g:1,
1340             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1341                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1342             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1343     default:
1344         return {g:0,
1345             c:null,
1346             s:String.escape(character)};
1347     }
1348 };
1349
1350 /**
1351  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1352  * @return {String} The abbreviated timezone name (e.g. 'CST')
1353  */
1354 Date.prototype.getTimezone = function() {
1355     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1356 };
1357
1358 /**
1359  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1360  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1361  */
1362 Date.prototype.getGMTOffset = function() {
1363     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1364         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1365         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1366 };
1367
1368 /**
1369  * Get the numeric day number of the year, adjusted for leap year.
1370  * @return {Number} 0 through 364 (365 in leap years)
1371  */
1372 Date.prototype.getDayOfYear = function() {
1373     var num = 0;
1374     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1375     for (var i = 0; i < this.getMonth(); ++i) {
1376         num += Date.daysInMonth[i];
1377     }
1378     return num + this.getDate() - 1;
1379 };
1380
1381 /**
1382  * Get the string representation of the numeric week number of the year
1383  * (equivalent to the format specifier 'W').
1384  * @return {String} '00' through '52'
1385  */
1386 Date.prototype.getWeekOfYear = function() {
1387     // Skip to Thursday of this week
1388     var now = this.getDayOfYear() + (4 - this.getDay());
1389     // Find the first Thursday of the year
1390     var jan1 = new Date(this.getFullYear(), 0, 1);
1391     var then = (7 - jan1.getDay() + 4);
1392     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1393 };
1394
1395 /**
1396  * Whether or not the current date is in a leap year.
1397  * @return {Boolean} True if the current date is in a leap year, else false
1398  */
1399 Date.prototype.isLeapYear = function() {
1400     var year = this.getFullYear();
1401     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1402 };
1403
1404 /**
1405  * Get the first day of the current month, adjusted for leap year.  The returned value
1406  * is the numeric day index within the week (0-6) which can be used in conjunction with
1407  * the {@link #monthNames} array to retrieve the textual day name.
1408  * Example:
1409  *<pre><code>
1410 var dt = new Date('1/10/2007');
1411 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1412 </code></pre>
1413  * @return {Number} The day number (0-6)
1414  */
1415 Date.prototype.getFirstDayOfMonth = function() {
1416     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1417     return (day < 0) ? (day + 7) : day;
1418 };
1419
1420 /**
1421  * Get the last day of the current month, adjusted for leap year.  The returned value
1422  * is the numeric day index within the week (0-6) which can be used in conjunction with
1423  * the {@link #monthNames} array to retrieve the textual day name.
1424  * Example:
1425  *<pre><code>
1426 var dt = new Date('1/10/2007');
1427 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1428 </code></pre>
1429  * @return {Number} The day number (0-6)
1430  */
1431 Date.prototype.getLastDayOfMonth = function() {
1432     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1433     return (day < 0) ? (day + 7) : day;
1434 };
1435
1436
1437 /**
1438  * Get the first date of this date's month
1439  * @return {Date}
1440  */
1441 Date.prototype.getFirstDateOfMonth = function() {
1442     return new Date(this.getFullYear(), this.getMonth(), 1);
1443 };
1444
1445 /**
1446  * Get the last date of this date's month
1447  * @return {Date}
1448  */
1449 Date.prototype.getLastDateOfMonth = function() {
1450     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1451 };
1452 /**
1453  * Get the number of days in the current month, adjusted for leap year.
1454  * @return {Number} The number of days in the month
1455  */
1456 Date.prototype.getDaysInMonth = function() {
1457     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1458     return Date.daysInMonth[this.getMonth()];
1459 };
1460
1461 /**
1462  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1463  * @return {String} 'st, 'nd', 'rd' or 'th'
1464  */
1465 Date.prototype.getSuffix = function() {
1466     switch (this.getDate()) {
1467         case 1:
1468         case 21:
1469         case 31:
1470             return "st";
1471         case 2:
1472         case 22:
1473             return "nd";
1474         case 3:
1475         case 23:
1476             return "rd";
1477         default:
1478             return "th";
1479     }
1480 };
1481
1482 // private
1483 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1484
1485 /**
1486  * An array of textual month names.
1487  * Override these values for international dates, for example...
1488  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1489  * @type Array
1490  * @static
1491  */
1492 Date.monthNames =
1493    ["January",
1494     "February",
1495     "March",
1496     "April",
1497     "May",
1498     "June",
1499     "July",
1500     "August",
1501     "September",
1502     "October",
1503     "November",
1504     "December"];
1505
1506 /**
1507  * An array of textual day names.
1508  * Override these values for international dates, for example...
1509  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1510  * @type Array
1511  * @static
1512  */
1513 Date.dayNames =
1514    ["Sunday",
1515     "Monday",
1516     "Tuesday",
1517     "Wednesday",
1518     "Thursday",
1519     "Friday",
1520     "Saturday"];
1521
1522 // private
1523 Date.y2kYear = 50;
1524 // private
1525 Date.monthNumbers = {
1526     Jan:0,
1527     Feb:1,
1528     Mar:2,
1529     Apr:3,
1530     May:4,
1531     Jun:5,
1532     Jul:6,
1533     Aug:7,
1534     Sep:8,
1535     Oct:9,
1536     Nov:10,
1537     Dec:11};
1538
1539 /**
1540  * Creates and returns a new Date instance with the exact same date value as the called instance.
1541  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1542  * variable will also be changed.  When the intention is to create a new variable that will not
1543  * modify the original instance, you should create a clone.
1544  *
1545  * Example of correctly cloning a date:
1546  * <pre><code>
1547 //wrong way:
1548 var orig = new Date('10/1/2006');
1549 var copy = orig;
1550 copy.setDate(5);
1551 document.write(orig);  //returns 'Thu Oct 05 2006'!
1552
1553 //correct way:
1554 var orig = new Date('10/1/2006');
1555 var copy = orig.clone();
1556 copy.setDate(5);
1557 document.write(orig);  //returns 'Thu Oct 01 2006'
1558 </code></pre>
1559  * @return {Date} The new Date instance
1560  */
1561 Date.prototype.clone = function() {
1562         return new Date(this.getTime());
1563 };
1564
1565 /**
1566  * Clears any time information from this date
1567  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1568  @return {Date} this or the clone
1569  */
1570 Date.prototype.clearTime = function(clone){
1571     if(clone){
1572         return this.clone().clearTime();
1573     }
1574     this.setHours(0);
1575     this.setMinutes(0);
1576     this.setSeconds(0);
1577     this.setMilliseconds(0);
1578     return this;
1579 };
1580
1581 // private
1582 // safari setMonth is broken
1583 if(Roo.isSafari){
1584     Date.brokenSetMonth = Date.prototype.setMonth;
1585         Date.prototype.setMonth = function(num){
1586                 if(num <= -1){
1587                         var n = Math.ceil(-num);
1588                         var back_year = Math.ceil(n/12);
1589                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1590                         this.setFullYear(this.getFullYear() - back_year);
1591                         return Date.brokenSetMonth.call(this, month);
1592                 } else {
1593                         return Date.brokenSetMonth.apply(this, arguments);
1594                 }
1595         };
1596 }
1597
1598 /** Date interval constant 
1599 * @static 
1600 * @type String */
1601 Date.MILLI = "ms";
1602 /** Date interval constant 
1603 * @static 
1604 * @type String */
1605 Date.SECOND = "s";
1606 /** Date interval constant 
1607 * @static 
1608 * @type String */
1609 Date.MINUTE = "mi";
1610 /** Date interval constant 
1611 * @static 
1612 * @type String */
1613 Date.HOUR = "h";
1614 /** Date interval constant 
1615 * @static 
1616 * @type String */
1617 Date.DAY = "d";
1618 /** Date interval constant 
1619 * @static 
1620 * @type String */
1621 Date.MONTH = "mo";
1622 /** Date interval constant 
1623 * @static 
1624 * @type String */
1625 Date.YEAR = "y";
1626
1627 /**
1628  * Provides a convenient method of performing basic date arithmetic.  This method
1629  * does not modify the Date instance being called - it creates and returns
1630  * a new Date instance containing the resulting date value.
1631  *
1632  * Examples:
1633  * <pre><code>
1634 //Basic usage:
1635 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1636 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1637
1638 //Negative values will subtract correctly:
1639 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1640 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1641
1642 //You can even chain several calls together in one line!
1643 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1644 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1645  </code></pre>
1646  *
1647  * @param {String} interval   A valid date interval enum value
1648  * @param {Number} value      The amount to add to the current date
1649  * @return {Date} The new Date instance
1650  */
1651 Date.prototype.add = function(interval, value){
1652   var d = this.clone();
1653   if (!interval || value === 0) return d;
1654   switch(interval.toLowerCase()){
1655     case Date.MILLI:
1656       d.setMilliseconds(this.getMilliseconds() + value);
1657       break;
1658     case Date.SECOND:
1659       d.setSeconds(this.getSeconds() + value);
1660       break;
1661     case Date.MINUTE:
1662       d.setMinutes(this.getMinutes() + value);
1663       break;
1664     case Date.HOUR:
1665       d.setHours(this.getHours() + value);
1666       break;
1667     case Date.DAY:
1668       d.setDate(this.getDate() + value);
1669       break;
1670     case Date.MONTH:
1671       var day = this.getDate();
1672       if(day > 28){
1673           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1674       }
1675       d.setDate(day);
1676       d.setMonth(this.getMonth() + value);
1677       break;
1678     case Date.YEAR:
1679       d.setFullYear(this.getFullYear() + value);
1680       break;
1681   }
1682   return d;
1683 };/*
1684  * Based on:
1685  * Ext JS Library 1.1.1
1686  * Copyright(c) 2006-2007, Ext JS, LLC.
1687  *
1688  * Originally Released Under LGPL - original licence link has changed is not relivant.
1689  *
1690  * Fork - LGPL
1691  * <script type="text/javascript">
1692  */
1693
1694 Roo.lib.Dom = {
1695     getViewWidth : function(full) {
1696         return full ? this.getDocumentWidth() : this.getViewportWidth();
1697     },
1698
1699     getViewHeight : function(full) {
1700         return full ? this.getDocumentHeight() : this.getViewportHeight();
1701     },
1702
1703     getDocumentHeight: function() {
1704         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1705         return Math.max(scrollHeight, this.getViewportHeight());
1706     },
1707
1708     getDocumentWidth: function() {
1709         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1710         return Math.max(scrollWidth, this.getViewportWidth());
1711     },
1712
1713     getViewportHeight: function() {
1714         var height = self.innerHeight;
1715         var mode = document.compatMode;
1716
1717         if ((mode || Roo.isIE) && !Roo.isOpera) {
1718             height = (mode == "CSS1Compat") ?
1719                      document.documentElement.clientHeight :
1720                      document.body.clientHeight;
1721         }
1722
1723         return height;
1724     },
1725
1726     getViewportWidth: function() {
1727         var width = self.innerWidth;
1728         var mode = document.compatMode;
1729
1730         if (mode || Roo.isIE) {
1731             width = (mode == "CSS1Compat") ?
1732                     document.documentElement.clientWidth :
1733                     document.body.clientWidth;
1734         }
1735         return width;
1736     },
1737
1738     isAncestor : function(p, c) {
1739         p = Roo.getDom(p);
1740         c = Roo.getDom(c);
1741         if (!p || !c) {
1742             return false;
1743         }
1744
1745         if (p.contains && !Roo.isSafari) {
1746             return p.contains(c);
1747         } else if (p.compareDocumentPosition) {
1748             return !!(p.compareDocumentPosition(c) & 16);
1749         } else {
1750             var parent = c.parentNode;
1751             while (parent) {
1752                 if (parent == p) {
1753                     return true;
1754                 }
1755                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1756                     return false;
1757                 }
1758                 parent = parent.parentNode;
1759             }
1760             return false;
1761         }
1762     },
1763
1764     getRegion : function(el) {
1765         return Roo.lib.Region.getRegion(el);
1766     },
1767
1768     getY : function(el) {
1769         return this.getXY(el)[1];
1770     },
1771
1772     getX : function(el) {
1773         return this.getXY(el)[0];
1774     },
1775
1776     getXY : function(el) {
1777         var p, pe, b, scroll, bd = document.body;
1778         el = Roo.getDom(el);
1779         var fly = Roo.lib.AnimBase.fly;
1780         if (el.getBoundingClientRect) {
1781             b = el.getBoundingClientRect();
1782             scroll = fly(document).getScroll();
1783             return [b.left + scroll.left, b.top + scroll.top];
1784         }
1785         var x = 0, y = 0;
1786
1787         p = el;
1788
1789         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1790
1791         while (p) {
1792
1793             x += p.offsetLeft;
1794             y += p.offsetTop;
1795
1796             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1797                 hasAbsolute = true;
1798             }
1799
1800             if (Roo.isGecko) {
1801                 pe = fly(p);
1802
1803                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1804                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1805
1806
1807                 x += bl;
1808                 y += bt;
1809
1810
1811                 if (p != el && pe.getStyle('overflow') != 'visible') {
1812                     x += bl;
1813                     y += bt;
1814                 }
1815             }
1816             p = p.offsetParent;
1817         }
1818
1819         if (Roo.isSafari && hasAbsolute) {
1820             x -= bd.offsetLeft;
1821             y -= bd.offsetTop;
1822         }
1823
1824         if (Roo.isGecko && !hasAbsolute) {
1825             var dbd = fly(bd);
1826             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1827             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1828         }
1829
1830         p = el.parentNode;
1831         while (p && p != bd) {
1832             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1833                 x -= p.scrollLeft;
1834                 y -= p.scrollTop;
1835             }
1836             p = p.parentNode;
1837         }
1838         return [x, y];
1839     },
1840  
1841   
1842
1843
1844     setXY : function(el, xy) {
1845         el = Roo.fly(el, '_setXY');
1846         el.position();
1847         var pts = el.translatePoints(xy);
1848         if (xy[0] !== false) {
1849             el.dom.style.left = pts.left + "px";
1850         }
1851         if (xy[1] !== false) {
1852             el.dom.style.top = pts.top + "px";
1853         }
1854     },
1855
1856     setX : function(el, x) {
1857         this.setXY(el, [x, false]);
1858     },
1859
1860     setY : function(el, y) {
1861         this.setXY(el, [false, y]);
1862     }
1863 };
1864 /*
1865  * Portions of this file are based on pieces of Yahoo User Interface Library
1866  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1867  * YUI licensed under the BSD License:
1868  * http://developer.yahoo.net/yui/license.txt
1869  * <script type="text/javascript">
1870  *
1871  */
1872
1873 Roo.lib.Event = function() {
1874     var loadComplete = false;
1875     var listeners = [];
1876     var unloadListeners = [];
1877     var retryCount = 0;
1878     var onAvailStack = [];
1879     var counter = 0;
1880     var lastError = null;
1881
1882     return {
1883         POLL_RETRYS: 200,
1884         POLL_INTERVAL: 20,
1885         EL: 0,
1886         TYPE: 1,
1887         FN: 2,
1888         WFN: 3,
1889         OBJ: 3,
1890         ADJ_SCOPE: 4,
1891         _interval: null,
1892
1893         startInterval: function() {
1894             if (!this._interval) {
1895                 var self = this;
1896                 var callback = function() {
1897                     self._tryPreloadAttach();
1898                 };
1899                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1900
1901             }
1902         },
1903
1904         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1905             onAvailStack.push({ id:         p_id,
1906                 fn:         p_fn,
1907                 obj:        p_obj,
1908                 override:   p_override,
1909                 checkReady: false    });
1910
1911             retryCount = this.POLL_RETRYS;
1912             this.startInterval();
1913         },
1914
1915
1916         addListener: function(el, eventName, fn) {
1917             el = Roo.getDom(el);
1918             if (!el || !fn) {
1919                 return false;
1920             }
1921
1922             if ("unload" == eventName) {
1923                 unloadListeners[unloadListeners.length] =
1924                 [el, eventName, fn];
1925                 return true;
1926             }
1927
1928             var wrappedFn = function(e) {
1929                 return fn(Roo.lib.Event.getEvent(e));
1930             };
1931
1932             var li = [el, eventName, fn, wrappedFn];
1933
1934             var index = listeners.length;
1935             listeners[index] = li;
1936
1937             this.doAdd(el, eventName, wrappedFn, false);
1938             return true;
1939
1940         },
1941
1942
1943         removeListener: function(el, eventName, fn) {
1944             var i, len;
1945
1946             el = Roo.getDom(el);
1947
1948             if(!fn) {
1949                 return this.purgeElement(el, false, eventName);
1950             }
1951
1952
1953             if ("unload" == eventName) {
1954
1955                 for (i = 0,len = unloadListeners.length; i < len; i++) {
1956                     var li = unloadListeners[i];
1957                     if (li &&
1958                         li[0] == el &&
1959                         li[1] == eventName &&
1960                         li[2] == fn) {
1961                         unloadListeners.splice(i, 1);
1962                         return true;
1963                     }
1964                 }
1965
1966                 return false;
1967             }
1968
1969             var cacheItem = null;
1970
1971
1972             var index = arguments[3];
1973
1974             if ("undefined" == typeof index) {
1975                 index = this._getCacheIndex(el, eventName, fn);
1976             }
1977
1978             if (index >= 0) {
1979                 cacheItem = listeners[index];
1980             }
1981
1982             if (!el || !cacheItem) {
1983                 return false;
1984             }
1985
1986             this.doRemove(el, eventName, cacheItem[this.WFN], false);
1987
1988             delete listeners[index][this.WFN];
1989             delete listeners[index][this.FN];
1990             listeners.splice(index, 1);
1991
1992             return true;
1993
1994         },
1995
1996
1997         getTarget: function(ev, resolveTextNode) {
1998             ev = ev.browserEvent || ev;
1999             var t = ev.target || ev.srcElement;
2000             return this.resolveTextNode(t);
2001         },
2002
2003
2004         resolveTextNode: function(node) {
2005             if (Roo.isSafari && node && 3 == node.nodeType) {
2006                 return node.parentNode;
2007             } else {
2008                 return node;
2009             }
2010         },
2011
2012
2013         getPageX: function(ev) {
2014             ev = ev.browserEvent || ev;
2015             var x = ev.pageX;
2016             if (!x && 0 !== x) {
2017                 x = ev.clientX || 0;
2018
2019                 if (Roo.isIE) {
2020                     x += this.getScroll()[1];
2021                 }
2022             }
2023
2024             return x;
2025         },
2026
2027
2028         getPageY: function(ev) {
2029             ev = ev.browserEvent || ev;
2030             var y = ev.pageY;
2031             if (!y && 0 !== y) {
2032                 y = ev.clientY || 0;
2033
2034                 if (Roo.isIE) {
2035                     y += this.getScroll()[0];
2036                 }
2037             }
2038
2039
2040             return y;
2041         },
2042
2043
2044         getXY: function(ev) {
2045             ev = ev.browserEvent || ev;
2046             return [this.getPageX(ev), this.getPageY(ev)];
2047         },
2048
2049
2050         getRelatedTarget: function(ev) {
2051             ev = ev.browserEvent || ev;
2052             var t = ev.relatedTarget;
2053             if (!t) {
2054                 if (ev.type == "mouseout") {
2055                     t = ev.toElement;
2056                 } else if (ev.type == "mouseover") {
2057                     t = ev.fromElement;
2058                 }
2059             }
2060
2061             return this.resolveTextNode(t);
2062         },
2063
2064
2065         getTime: function(ev) {
2066             ev = ev.browserEvent || ev;
2067             if (!ev.time) {
2068                 var t = new Date().getTime();
2069                 try {
2070                     ev.time = t;
2071                 } catch(ex) {
2072                     this.lastError = ex;
2073                     return t;
2074                 }
2075             }
2076
2077             return ev.time;
2078         },
2079
2080
2081         stopEvent: function(ev) {
2082             this.stopPropagation(ev);
2083             this.preventDefault(ev);
2084         },
2085
2086
2087         stopPropagation: function(ev) {
2088             ev = ev.browserEvent || ev;
2089             if (ev.stopPropagation) {
2090                 ev.stopPropagation();
2091             } else {
2092                 ev.cancelBubble = true;
2093             }
2094         },
2095
2096
2097         preventDefault: function(ev) {
2098             ev = ev.browserEvent || ev;
2099             if(ev.preventDefault) {
2100                 ev.preventDefault();
2101             } else {
2102                 ev.returnValue = false;
2103             }
2104         },
2105
2106
2107         getEvent: function(e) {
2108             var ev = e || window.event;
2109             if (!ev) {
2110                 var c = this.getEvent.caller;
2111                 while (c) {
2112                     ev = c.arguments[0];
2113                     if (ev && Event == ev.constructor) {
2114                         break;
2115                     }
2116                     c = c.caller;
2117                 }
2118             }
2119             return ev;
2120         },
2121
2122
2123         getCharCode: function(ev) {
2124             ev = ev.browserEvent || ev;
2125             return ev.charCode || ev.keyCode || 0;
2126         },
2127
2128
2129         _getCacheIndex: function(el, eventName, fn) {
2130             for (var i = 0,len = listeners.length; i < len; ++i) {
2131                 var li = listeners[i];
2132                 if (li &&
2133                     li[this.FN] == fn &&
2134                     li[this.EL] == el &&
2135                     li[this.TYPE] == eventName) {
2136                     return i;
2137                 }
2138             }
2139
2140             return -1;
2141         },
2142
2143
2144         elCache: {},
2145
2146
2147         getEl: function(id) {
2148             return document.getElementById(id);
2149         },
2150
2151
2152         clearCache: function() {
2153         },
2154
2155
2156         _load: function(e) {
2157             loadComplete = true;
2158             var EU = Roo.lib.Event;
2159
2160
2161             if (Roo.isIE) {
2162                 EU.doRemove(window, "load", EU._load);
2163             }
2164         },
2165
2166
2167         _tryPreloadAttach: function() {
2168
2169             if (this.locked) {
2170                 return false;
2171             }
2172
2173             this.locked = true;
2174
2175
2176             var tryAgain = !loadComplete;
2177             if (!tryAgain) {
2178                 tryAgain = (retryCount > 0);
2179             }
2180
2181
2182             var notAvail = [];
2183             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2184                 var item = onAvailStack[i];
2185                 if (item) {
2186                     var el = this.getEl(item.id);
2187
2188                     if (el) {
2189                         if (!item.checkReady ||
2190                             loadComplete ||
2191                             el.nextSibling ||
2192                             (document && document.body)) {
2193
2194                             var scope = el;
2195                             if (item.override) {
2196                                 if (item.override === true) {
2197                                     scope = item.obj;
2198                                 } else {
2199                                     scope = item.override;
2200                                 }
2201                             }
2202                             item.fn.call(scope, item.obj);
2203                             onAvailStack[i] = null;
2204                         }
2205                     } else {
2206                         notAvail.push(item);
2207                     }
2208                 }
2209             }
2210
2211             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2212
2213             if (tryAgain) {
2214
2215                 this.startInterval();
2216             } else {
2217                 clearInterval(this._interval);
2218                 this._interval = null;
2219             }
2220
2221             this.locked = false;
2222
2223             return true;
2224
2225         },
2226
2227
2228         purgeElement: function(el, recurse, eventName) {
2229             var elListeners = this.getListeners(el, eventName);
2230             if (elListeners) {
2231                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2232                     var l = elListeners[i];
2233                     this.removeListener(el, l.type, l.fn);
2234                 }
2235             }
2236
2237             if (recurse && el && el.childNodes) {
2238                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2239                     this.purgeElement(el.childNodes[i], recurse, eventName);
2240                 }
2241             }
2242         },
2243
2244
2245         getListeners: function(el, eventName) {
2246             var results = [], searchLists;
2247             if (!eventName) {
2248                 searchLists = [listeners, unloadListeners];
2249             } else if (eventName == "unload") {
2250                 searchLists = [unloadListeners];
2251             } else {
2252                 searchLists = [listeners];
2253             }
2254
2255             for (var j = 0; j < searchLists.length; ++j) {
2256                 var searchList = searchLists[j];
2257                 if (searchList && searchList.length > 0) {
2258                     for (var i = 0,len = searchList.length; i < len; ++i) {
2259                         var l = searchList[i];
2260                         if (l && l[this.EL] === el &&
2261                             (!eventName || eventName === l[this.TYPE])) {
2262                             results.push({
2263                                 type:   l[this.TYPE],
2264                                 fn:     l[this.FN],
2265                                 obj:    l[this.OBJ],
2266                                 adjust: l[this.ADJ_SCOPE],
2267                                 index:  i
2268                             });
2269                         }
2270                     }
2271                 }
2272             }
2273
2274             return (results.length) ? results : null;
2275         },
2276
2277
2278         _unload: function(e) {
2279
2280             var EU = Roo.lib.Event, i, j, l, len, index;
2281
2282             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2283                 l = unloadListeners[i];
2284                 if (l) {
2285                     var scope = window;
2286                     if (l[EU.ADJ_SCOPE]) {
2287                         if (l[EU.ADJ_SCOPE] === true) {
2288                             scope = l[EU.OBJ];
2289                         } else {
2290                             scope = l[EU.ADJ_SCOPE];
2291                         }
2292                     }
2293                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2294                     unloadListeners[i] = null;
2295                     l = null;
2296                     scope = null;
2297                 }
2298             }
2299
2300             unloadListeners = null;
2301
2302             if (listeners && listeners.length > 0) {
2303                 j = listeners.length;
2304                 while (j) {
2305                     index = j - 1;
2306                     l = listeners[index];
2307                     if (l) {
2308                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2309                                 l[EU.FN], index);
2310                     }
2311                     j = j - 1;
2312                 }
2313                 l = null;
2314
2315                 EU.clearCache();
2316             }
2317
2318             EU.doRemove(window, "unload", EU._unload);
2319
2320         },
2321
2322
2323         getScroll: function() {
2324             var dd = document.documentElement, db = document.body;
2325             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2326                 return [dd.scrollTop, dd.scrollLeft];
2327             } else if (db) {
2328                 return [db.scrollTop, db.scrollLeft];
2329             } else {
2330                 return [0, 0];
2331             }
2332         },
2333
2334
2335         doAdd: function () {
2336             if (window.addEventListener) {
2337                 return function(el, eventName, fn, capture) {
2338                     el.addEventListener(eventName, fn, (capture));
2339                 };
2340             } else if (window.attachEvent) {
2341                 return function(el, eventName, fn, capture) {
2342                     el.attachEvent("on" + eventName, fn);
2343                 };
2344             } else {
2345                 return function() {
2346                 };
2347             }
2348         }(),
2349
2350
2351         doRemove: function() {
2352             if (window.removeEventListener) {
2353                 return function (el, eventName, fn, capture) {
2354                     el.removeEventListener(eventName, fn, (capture));
2355                 };
2356             } else if (window.detachEvent) {
2357                 return function (el, eventName, fn) {
2358                     el.detachEvent("on" + eventName, fn);
2359                 };
2360             } else {
2361                 return function() {
2362                 };
2363             }
2364         }()
2365     };
2366     
2367 }();
2368 (function() {     
2369    
2370     var E = Roo.lib.Event;
2371     E.on = E.addListener;
2372     E.un = E.removeListener;
2373
2374     if (document && document.body) {
2375         E._load();
2376     } else {
2377         E.doAdd(window, "load", E._load);
2378     }
2379     E.doAdd(window, "unload", E._unload);
2380     E._tryPreloadAttach();
2381 })();
2382
2383 /*
2384  * Portions of this file are based on pieces of Yahoo User Interface Library
2385  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2386  * YUI licensed under the BSD License:
2387  * http://developer.yahoo.net/yui/license.txt
2388  * <script type="text/javascript">
2389  *
2390  */
2391
2392 (function() {
2393     
2394     Roo.lib.Ajax = {
2395         request : function(method, uri, cb, data, options) {
2396             if(options){
2397                 var hs = options.headers;
2398                 if(hs){
2399                     for(var h in hs){
2400                         if(hs.hasOwnProperty(h)){
2401                             this.initHeader(h, hs[h], false);
2402                         }
2403                     }
2404                 }
2405                 if(options.xmlData){
2406                     this.initHeader('Content-Type', 'text/xml', false);
2407                     method = 'POST';
2408                     data = options.xmlData;
2409                 }
2410             }
2411
2412             return this.asyncRequest(method, uri, cb, data);
2413         },
2414
2415         serializeForm : function(form) {
2416             if(typeof form == 'string') {
2417                 form = (document.getElementById(form) || document.forms[form]);
2418             }
2419
2420             var el, name, val, disabled, data = '', hasSubmit = false;
2421             for (var i = 0; i < form.elements.length; i++) {
2422                 el = form.elements[i];
2423                 disabled = form.elements[i].disabled;
2424                 name = form.elements[i].name;
2425                 val = form.elements[i].value;
2426
2427                 if (!disabled && name){
2428                     switch (el.type)
2429                             {
2430                         case 'select-one':
2431                         case 'select-multiple':
2432                             for (var j = 0; j < el.options.length; j++) {
2433                                 if (el.options[j].selected) {
2434                                     if (Roo.isIE) {
2435                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2436                                     }
2437                                     else {
2438                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2439                                     }
2440                                 }
2441                             }
2442                             break;
2443                         case 'radio':
2444                         case 'checkbox':
2445                             if (el.checked) {
2446                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2447                             }
2448                             break;
2449                         case 'file':
2450
2451                         case undefined:
2452
2453                         case 'reset':
2454
2455                         case 'button':
2456
2457                             break;
2458                         case 'submit':
2459                             if(hasSubmit == false) {
2460                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2461                                 hasSubmit = true;
2462                             }
2463                             break;
2464                         default:
2465                             data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2466                             break;
2467                     }
2468                 }
2469             }
2470             data = data.substr(0, data.length - 1);
2471             return data;
2472         },
2473
2474         headers:{},
2475
2476         hasHeaders:false,
2477
2478         useDefaultHeader:true,
2479
2480         defaultPostHeader:'application/x-www-form-urlencoded',
2481
2482         useDefaultXhrHeader:true,
2483
2484         defaultXhrHeader:'XMLHttpRequest',
2485
2486         hasDefaultHeaders:true,
2487
2488         defaultHeaders:{},
2489
2490         poll:{},
2491
2492         timeout:{},
2493
2494         pollInterval:50,
2495
2496         transactionId:0,
2497
2498         setProgId:function(id)
2499         {
2500             this.activeX.unshift(id);
2501         },
2502
2503         setDefaultPostHeader:function(b)
2504         {
2505             this.useDefaultHeader = b;
2506         },
2507
2508         setDefaultXhrHeader:function(b)
2509         {
2510             this.useDefaultXhrHeader = b;
2511         },
2512
2513         setPollingInterval:function(i)
2514         {
2515             if (typeof i == 'number' && isFinite(i)) {
2516                 this.pollInterval = i;
2517             }
2518         },
2519
2520         createXhrObject:function(transactionId)
2521         {
2522             var obj,http;
2523             try
2524             {
2525
2526                 http = new XMLHttpRequest();
2527
2528                 obj = { conn:http, tId:transactionId };
2529             }
2530             catch(e)
2531             {
2532                 for (var i = 0; i < this.activeX.length; ++i) {
2533                     try
2534                     {
2535
2536                         http = new ActiveXObject(this.activeX[i]);
2537
2538                         obj = { conn:http, tId:transactionId };
2539                         break;
2540                     }
2541                     catch(e) {
2542                     }
2543                 }
2544             }
2545             finally
2546             {
2547                 return obj;
2548             }
2549         },
2550
2551         getConnectionObject:function()
2552         {
2553             var o;
2554             var tId = this.transactionId;
2555
2556             try
2557             {
2558                 o = this.createXhrObject(tId);
2559                 if (o) {
2560                     this.transactionId++;
2561                 }
2562             }
2563             catch(e) {
2564             }
2565             finally
2566             {
2567                 return o;
2568             }
2569         },
2570
2571         asyncRequest:function(method, uri, callback, postData)
2572         {
2573             var o = this.getConnectionObject();
2574
2575             if (!o) {
2576                 return null;
2577             }
2578             else {
2579                 o.conn.open(method, uri, true);
2580
2581                 if (this.useDefaultXhrHeader) {
2582                     if (!this.defaultHeaders['X-Requested-With']) {
2583                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2584                     }
2585                 }
2586
2587                 if(postData && this.useDefaultHeader){
2588                     this.initHeader('Content-Type', this.defaultPostHeader);
2589                 }
2590
2591                  if (this.hasDefaultHeaders || this.hasHeaders) {
2592                     this.setHeader(o);
2593                 }
2594
2595                 this.handleReadyState(o, callback);
2596                 o.conn.send(postData || null);
2597
2598                 return o;
2599             }
2600         },
2601
2602         handleReadyState:function(o, callback)
2603         {
2604             var oConn = this;
2605
2606             if (callback && callback.timeout) {
2607                 this.timeout[o.tId] = window.setTimeout(function() {
2608                     oConn.abort(o, callback, true);
2609                 }, callback.timeout);
2610             }
2611
2612             this.poll[o.tId] = window.setInterval(
2613                     function() {
2614                         if (o.conn && o.conn.readyState == 4) {
2615                             window.clearInterval(oConn.poll[o.tId]);
2616                             delete oConn.poll[o.tId];
2617
2618                             if(callback && callback.timeout) {
2619                                 window.clearTimeout(oConn.timeout[o.tId]);
2620                                 delete oConn.timeout[o.tId];
2621                             }
2622
2623                             oConn.handleTransactionResponse(o, callback);
2624                         }
2625                     }
2626                     , this.pollInterval);
2627         },
2628
2629         handleTransactionResponse:function(o, callback, isAbort)
2630         {
2631
2632             if (!callback) {
2633                 this.releaseObject(o);
2634                 return;
2635             }
2636
2637             var httpStatus, responseObject;
2638
2639             try
2640             {
2641                 if (o.conn.status !== undefined && o.conn.status != 0) {
2642                     httpStatus = o.conn.status;
2643                 }
2644                 else {
2645                     httpStatus = 13030;
2646                 }
2647             }
2648             catch(e) {
2649
2650
2651                 httpStatus = 13030;
2652             }
2653
2654             if (httpStatus >= 200 && httpStatus < 300) {
2655                 responseObject = this.createResponseObject(o, callback.argument);
2656                 if (callback.success) {
2657                     if (!callback.scope) {
2658                         callback.success(responseObject);
2659                     }
2660                     else {
2661
2662
2663                         callback.success.apply(callback.scope, [responseObject]);
2664                     }
2665                 }
2666             }
2667             else {
2668                 switch (httpStatus) {
2669
2670                     case 12002:
2671                     case 12029:
2672                     case 12030:
2673                     case 12031:
2674                     case 12152:
2675                     case 13030:
2676                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2677                         if (callback.failure) {
2678                             if (!callback.scope) {
2679                                 callback.failure(responseObject);
2680                             }
2681                             else {
2682                                 callback.failure.apply(callback.scope, [responseObject]);
2683                             }
2684                         }
2685                         break;
2686                     default:
2687                         responseObject = this.createResponseObject(o, callback.argument);
2688                         if (callback.failure) {
2689                             if (!callback.scope) {
2690                                 callback.failure(responseObject);
2691                             }
2692                             else {
2693                                 callback.failure.apply(callback.scope, [responseObject]);
2694                             }
2695                         }
2696                 }
2697             }
2698
2699             this.releaseObject(o);
2700             responseObject = null;
2701         },
2702
2703         createResponseObject:function(o, callbackArg)
2704         {
2705             var obj = {};
2706             var headerObj = {};
2707
2708             try
2709             {
2710                 var headerStr = o.conn.getAllResponseHeaders();
2711                 var header = headerStr.split('\n');
2712                 for (var i = 0; i < header.length; i++) {
2713                     var delimitPos = header[i].indexOf(':');
2714                     if (delimitPos != -1) {
2715                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2716                     }
2717                 }
2718             }
2719             catch(e) {
2720             }
2721
2722             obj.tId = o.tId;
2723             obj.status = o.conn.status;
2724             obj.statusText = o.conn.statusText;
2725             obj.getResponseHeader = headerObj;
2726             obj.getAllResponseHeaders = headerStr;
2727             obj.responseText = o.conn.responseText;
2728             obj.responseXML = o.conn.responseXML;
2729
2730             if (typeof callbackArg !== undefined) {
2731                 obj.argument = callbackArg;
2732             }
2733
2734             return obj;
2735         },
2736
2737         createExceptionObject:function(tId, callbackArg, isAbort)
2738         {
2739             var COMM_CODE = 0;
2740             var COMM_ERROR = 'communication failure';
2741             var ABORT_CODE = -1;
2742             var ABORT_ERROR = 'transaction aborted';
2743
2744             var obj = {};
2745
2746             obj.tId = tId;
2747             if (isAbort) {
2748                 obj.status = ABORT_CODE;
2749                 obj.statusText = ABORT_ERROR;
2750             }
2751             else {
2752                 obj.status = COMM_CODE;
2753                 obj.statusText = COMM_ERROR;
2754             }
2755
2756             if (callbackArg) {
2757                 obj.argument = callbackArg;
2758             }
2759
2760             return obj;
2761         },
2762
2763         initHeader:function(label, value, isDefault)
2764         {
2765             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2766
2767             if (headerObj[label] === undefined) {
2768                 headerObj[label] = value;
2769             }
2770             else {
2771
2772
2773                 headerObj[label] = value + "," + headerObj[label];
2774             }
2775
2776             if (isDefault) {
2777                 this.hasDefaultHeaders = true;
2778             }
2779             else {
2780                 this.hasHeaders = true;
2781             }
2782         },
2783
2784
2785         setHeader:function(o)
2786         {
2787             if (this.hasDefaultHeaders) {
2788                 for (var prop in this.defaultHeaders) {
2789                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2790                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2791                     }
2792                 }
2793             }
2794
2795             if (this.hasHeaders) {
2796                 for (var prop in this.headers) {
2797                     if (this.headers.hasOwnProperty(prop)) {
2798                         o.conn.setRequestHeader(prop, this.headers[prop]);
2799                     }
2800                 }
2801                 this.headers = {};
2802                 this.hasHeaders = false;
2803             }
2804         },
2805
2806         resetDefaultHeaders:function() {
2807             delete this.defaultHeaders;
2808             this.defaultHeaders = {};
2809             this.hasDefaultHeaders = false;
2810         },
2811
2812         abort:function(o, callback, isTimeout)
2813         {
2814             if(this.isCallInProgress(o)) {
2815                 o.conn.abort();
2816                 window.clearInterval(this.poll[o.tId]);
2817                 delete this.poll[o.tId];
2818                 if (isTimeout) {
2819                     delete this.timeout[o.tId];
2820                 }
2821
2822                 this.handleTransactionResponse(o, callback, true);
2823
2824                 return true;
2825             }
2826             else {
2827                 return false;
2828             }
2829         },
2830
2831
2832         isCallInProgress:function(o)
2833         {
2834             if (o && o.conn) {
2835                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2836             }
2837             else {
2838
2839                 return false;
2840             }
2841         },
2842
2843
2844         releaseObject:function(o)
2845         {
2846
2847             o.conn = null;
2848
2849             o = null;
2850         },
2851
2852         activeX:[
2853         'MSXML2.XMLHTTP.3.0',
2854         'MSXML2.XMLHTTP',
2855         'Microsoft.XMLHTTP'
2856         ]
2857
2858
2859     };
2860 })();/*
2861  * Portions of this file are based on pieces of Yahoo User Interface Library
2862  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2863  * YUI licensed under the BSD License:
2864  * http://developer.yahoo.net/yui/license.txt
2865  * <script type="text/javascript">
2866  *
2867  */
2868
2869 Roo.lib.Region = function(t, r, b, l) {
2870     this.top = t;
2871     this[1] = t;
2872     this.right = r;
2873     this.bottom = b;
2874     this.left = l;
2875     this[0] = l;
2876 };
2877
2878
2879 Roo.lib.Region.prototype = {
2880     contains : function(region) {
2881         return ( region.left >= this.left &&
2882                  region.right <= this.right &&
2883                  region.top >= this.top &&
2884                  region.bottom <= this.bottom    );
2885
2886     },
2887
2888     getArea : function() {
2889         return ( (this.bottom - this.top) * (this.right - this.left) );
2890     },
2891
2892     intersect : function(region) {
2893         var t = Math.max(this.top, region.top);
2894         var r = Math.min(this.right, region.right);
2895         var b = Math.min(this.bottom, region.bottom);
2896         var l = Math.max(this.left, region.left);
2897
2898         if (b >= t && r >= l) {
2899             return new Roo.lib.Region(t, r, b, l);
2900         } else {
2901             return null;
2902         }
2903     },
2904     union : function(region) {
2905         var t = Math.min(this.top, region.top);
2906         var r = Math.max(this.right, region.right);
2907         var b = Math.max(this.bottom, region.bottom);
2908         var l = Math.min(this.left, region.left);
2909
2910         return new Roo.lib.Region(t, r, b, l);
2911     },
2912
2913     adjust : function(t, l, b, r) {
2914         this.top += t;
2915         this.left += l;
2916         this.right += r;
2917         this.bottom += b;
2918         return this;
2919     }
2920 };
2921
2922 Roo.lib.Region.getRegion = function(el) {
2923     var p = Roo.lib.Dom.getXY(el);
2924
2925     var t = p[1];
2926     var r = p[0] + el.offsetWidth;
2927     var b = p[1] + el.offsetHeight;
2928     var l = p[0];
2929
2930     return new Roo.lib.Region(t, r, b, l);
2931 };
2932 /*
2933  * Portions of this file are based on pieces of Yahoo User Interface Library
2934  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2935  * YUI licensed under the BSD License:
2936  * http://developer.yahoo.net/yui/license.txt
2937  * <script type="text/javascript">
2938  *
2939  */
2940 //@@dep Roo.lib.Region
2941
2942
2943 Roo.lib.Point = function(x, y) {
2944     if (x instanceof Array) {
2945         y = x[1];
2946         x = x[0];
2947     }
2948     this.x = this.right = this.left = this[0] = x;
2949     this.y = this.top = this.bottom = this[1] = y;
2950 };
2951
2952 Roo.lib.Point.prototype = new Roo.lib.Region();
2953 /*
2954  * Portions of this file are based on pieces of Yahoo User Interface Library
2955  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2956  * YUI licensed under the BSD License:
2957  * http://developer.yahoo.net/yui/license.txt
2958  * <script type="text/javascript">
2959  *
2960  */
2961  
2962 (function() {   
2963
2964     Roo.lib.Anim = {
2965         scroll : function(el, args, duration, easing, cb, scope) {
2966             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2967         },
2968
2969         motion : function(el, args, duration, easing, cb, scope) {
2970             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2971         },
2972
2973         color : function(el, args, duration, easing, cb, scope) {
2974             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2975         },
2976
2977         run : function(el, args, duration, easing, cb, scope, type) {
2978             type = type || Roo.lib.AnimBase;
2979             if (typeof easing == "string") {
2980                 easing = Roo.lib.Easing[easing];
2981             }
2982             var anim = new type(el, args, duration, easing);
2983             anim.animateX(function() {
2984                 Roo.callback(cb, scope);
2985             });
2986             return anim;
2987         }
2988     };
2989 })();/*
2990  * Portions of this file are based on pieces of Yahoo User Interface Library
2991  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2992  * YUI licensed under the BSD License:
2993  * http://developer.yahoo.net/yui/license.txt
2994  * <script type="text/javascript">
2995  *
2996  */
2997
2998 (function() {    
2999     var libFlyweight;
3000     
3001     function fly(el) {
3002         if (!libFlyweight) {
3003             libFlyweight = new Roo.Element.Flyweight();
3004         }
3005         libFlyweight.dom = el;
3006         return libFlyweight;
3007     }
3008
3009     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3010     
3011    
3012     
3013     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3014         if (el) {
3015             this.init(el, attributes, duration, method);
3016         }
3017     };
3018
3019     Roo.lib.AnimBase.fly = fly;
3020     
3021     
3022     
3023     Roo.lib.AnimBase.prototype = {
3024
3025         toString: function() {
3026             var el = this.getEl();
3027             var id = el.id || el.tagName;
3028             return ("Anim " + id);
3029         },
3030
3031         patterns: {
3032             noNegatives:        /width|height|opacity|padding/i,
3033             offsetAttribute:  /^((width|height)|(top|left))$/,
3034             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3035             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3036         },
3037
3038
3039         doMethod: function(attr, start, end) {
3040             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3041         },
3042
3043
3044         setAttribute: function(attr, val, unit) {
3045             if (this.patterns.noNegatives.test(attr)) {
3046                 val = (val > 0) ? val : 0;
3047             }
3048
3049             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3050         },
3051
3052
3053         getAttribute: function(attr) {
3054             var el = this.getEl();
3055             var val = fly(el).getStyle(attr);
3056
3057             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3058                 return parseFloat(val);
3059             }
3060
3061             var a = this.patterns.offsetAttribute.exec(attr) || [];
3062             var pos = !!( a[3] );
3063             var box = !!( a[2] );
3064
3065
3066             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3067                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3068             } else {
3069                 val = 0;
3070             }
3071
3072             return val;
3073         },
3074
3075
3076         getDefaultUnit: function(attr) {
3077             if (this.patterns.defaultUnit.test(attr)) {
3078                 return 'px';
3079             }
3080
3081             return '';
3082         },
3083
3084         animateX : function(callback, scope) {
3085             var f = function() {
3086                 this.onComplete.removeListener(f);
3087                 if (typeof callback == "function") {
3088                     callback.call(scope || this, this);
3089                 }
3090             };
3091             this.onComplete.addListener(f, this);
3092             this.animate();
3093         },
3094
3095
3096         setRuntimeAttribute: function(attr) {
3097             var start;
3098             var end;
3099             var attributes = this.attributes;
3100
3101             this.runtimeAttributes[attr] = {};
3102
3103             var isset = function(prop) {
3104                 return (typeof prop !== 'undefined');
3105             };
3106
3107             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3108                 return false;
3109             }
3110
3111             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3112
3113
3114             if (isset(attributes[attr]['to'])) {
3115                 end = attributes[attr]['to'];
3116             } else if (isset(attributes[attr]['by'])) {
3117                 if (start.constructor == Array) {
3118                     end = [];
3119                     for (var i = 0, len = start.length; i < len; ++i) {
3120                         end[i] = start[i] + attributes[attr]['by'][i];
3121                     }
3122                 } else {
3123                     end = start + attributes[attr]['by'];
3124                 }
3125             }
3126
3127             this.runtimeAttributes[attr].start = start;
3128             this.runtimeAttributes[attr].end = end;
3129
3130
3131             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3132         },
3133
3134
3135         init: function(el, attributes, duration, method) {
3136
3137             var isAnimated = false;
3138
3139
3140             var startTime = null;
3141
3142
3143             var actualFrames = 0;
3144
3145
3146             el = Roo.getDom(el);
3147
3148
3149             this.attributes = attributes || {};
3150
3151
3152             this.duration = duration || 1;
3153
3154
3155             this.method = method || Roo.lib.Easing.easeNone;
3156
3157
3158             this.useSeconds = true;
3159
3160
3161             this.currentFrame = 0;
3162
3163
3164             this.totalFrames = Roo.lib.AnimMgr.fps;
3165
3166
3167             this.getEl = function() {
3168                 return el;
3169             };
3170
3171
3172             this.isAnimated = function() {
3173                 return isAnimated;
3174             };
3175
3176
3177             this.getStartTime = function() {
3178                 return startTime;
3179             };
3180
3181             this.runtimeAttributes = {};
3182
3183
3184             this.animate = function() {
3185                 if (this.isAnimated()) {
3186                     return false;
3187                 }
3188
3189                 this.currentFrame = 0;
3190
3191                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3192
3193                 Roo.lib.AnimMgr.registerElement(this);
3194             };
3195
3196
3197             this.stop = function(finish) {
3198                 if (finish) {
3199                     this.currentFrame = this.totalFrames;
3200                     this._onTween.fire();
3201                 }
3202                 Roo.lib.AnimMgr.stop(this);
3203             };
3204
3205             var onStart = function() {
3206                 this.onStart.fire();
3207
3208                 this.runtimeAttributes = {};
3209                 for (var attr in this.attributes) {
3210                     this.setRuntimeAttribute(attr);
3211                 }
3212
3213                 isAnimated = true;
3214                 actualFrames = 0;
3215                 startTime = new Date();
3216             };
3217
3218
3219             var onTween = function() {
3220                 var data = {
3221                     duration: new Date() - this.getStartTime(),
3222                     currentFrame: this.currentFrame
3223                 };
3224
3225                 data.toString = function() {
3226                     return (
3227                             'duration: ' + data.duration +
3228                             ', currentFrame: ' + data.currentFrame
3229                             );
3230                 };
3231
3232                 this.onTween.fire(data);
3233
3234                 var runtimeAttributes = this.runtimeAttributes;
3235
3236                 for (var attr in runtimeAttributes) {
3237                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3238                 }
3239
3240                 actualFrames += 1;
3241             };
3242
3243             var onComplete = function() {
3244                 var actual_duration = (new Date() - startTime) / 1000 ;
3245
3246                 var data = {
3247                     duration: actual_duration,
3248                     frames: actualFrames,
3249                     fps: actualFrames / actual_duration
3250                 };
3251
3252                 data.toString = function() {
3253                     return (
3254                             'duration: ' + data.duration +
3255                             ', frames: ' + data.frames +
3256                             ', fps: ' + data.fps
3257                             );
3258                 };
3259
3260                 isAnimated = false;
3261                 actualFrames = 0;
3262                 this.onComplete.fire(data);
3263             };
3264
3265
3266             this._onStart = new Roo.util.Event(this);
3267             this.onStart = new Roo.util.Event(this);
3268             this.onTween = new Roo.util.Event(this);
3269             this._onTween = new Roo.util.Event(this);
3270             this.onComplete = new Roo.util.Event(this);
3271             this._onComplete = new Roo.util.Event(this);
3272             this._onStart.addListener(onStart);
3273             this._onTween.addListener(onTween);
3274             this._onComplete.addListener(onComplete);
3275         }
3276     };
3277 })();
3278 /*
3279  * Portions of this file are based on pieces of Yahoo User Interface Library
3280  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3281  * YUI licensed under the BSD License:
3282  * http://developer.yahoo.net/yui/license.txt
3283  * <script type="text/javascript">
3284  *
3285  */
3286
3287 Roo.lib.AnimMgr = new function() {
3288
3289         var thread = null;
3290
3291
3292         var queue = [];
3293
3294
3295         var tweenCount = 0;
3296
3297
3298         this.fps = 1000;
3299
3300
3301         this.delay = 1;
3302
3303
3304         this.registerElement = function(tween) {
3305             queue[queue.length] = tween;
3306             tweenCount += 1;
3307             tween._onStart.fire();
3308             this.start();
3309         };
3310
3311
3312         this.unRegister = function(tween, index) {
3313             tween._onComplete.fire();
3314             index = index || getIndex(tween);
3315             if (index != -1) {
3316                 queue.splice(index, 1);
3317             }
3318
3319             tweenCount -= 1;
3320             if (tweenCount <= 0) {
3321                 this.stop();
3322             }
3323         };
3324
3325
3326         this.start = function() {
3327             if (thread === null) {
3328                 thread = setInterval(this.run, this.delay);
3329             }
3330         };
3331
3332
3333         this.stop = function(tween) {
3334             if (!tween) {
3335                 clearInterval(thread);
3336
3337                 for (var i = 0, len = queue.length; i < len; ++i) {
3338                     if (queue[0].isAnimated()) {
3339                         this.unRegister(queue[0], 0);
3340                     }
3341                 }
3342
3343                 queue = [];
3344                 thread = null;
3345                 tweenCount = 0;
3346             }
3347             else {
3348                 this.unRegister(tween);
3349             }
3350         };
3351
3352
3353         this.run = function() {
3354             for (var i = 0, len = queue.length; i < len; ++i) {
3355                 var tween = queue[i];
3356                 if (!tween || !tween.isAnimated()) {
3357                     continue;
3358                 }
3359
3360                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3361                 {
3362                     tween.currentFrame += 1;
3363
3364                     if (tween.useSeconds) {
3365                         correctFrame(tween);
3366                     }
3367                     tween._onTween.fire();
3368                 }
3369                 else {
3370                     Roo.lib.AnimMgr.stop(tween, i);
3371                 }
3372             }
3373         };
3374
3375         var getIndex = function(anim) {
3376             for (var i = 0, len = queue.length; i < len; ++i) {
3377                 if (queue[i] == anim) {
3378                     return i;
3379                 }
3380             }
3381             return -1;
3382         };
3383
3384
3385         var correctFrame = function(tween) {
3386             var frames = tween.totalFrames;
3387             var frame = tween.currentFrame;
3388             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3389             var elapsed = (new Date() - tween.getStartTime());
3390             var tweak = 0;
3391
3392             if (elapsed < tween.duration * 1000) {
3393                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3394             } else {
3395                 tweak = frames - (frame + 1);
3396             }
3397             if (tweak > 0 && isFinite(tweak)) {
3398                 if (tween.currentFrame + tweak >= frames) {
3399                     tweak = frames - (frame + 1);
3400                 }
3401
3402                 tween.currentFrame += tweak;
3403             }
3404         };
3405     };/*
3406  * Portions of this file are based on pieces of Yahoo User Interface Library
3407  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3408  * YUI licensed under the BSD License:
3409  * http://developer.yahoo.net/yui/license.txt
3410  * <script type="text/javascript">
3411  *
3412  */
3413 Roo.lib.Bezier = new function() {
3414
3415         this.getPosition = function(points, t) {
3416             var n = points.length;
3417             var tmp = [];
3418
3419             for (var i = 0; i < n; ++i) {
3420                 tmp[i] = [points[i][0], points[i][1]];
3421             }
3422
3423             for (var j = 1; j < n; ++j) {
3424                 for (i = 0; i < n - j; ++i) {
3425                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3426                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3427                 }
3428             }
3429
3430             return [ tmp[0][0], tmp[0][1] ];
3431
3432         };
3433     };/*
3434  * Portions of this file are based on pieces of Yahoo User Interface Library
3435  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3436  * YUI licensed under the BSD License:
3437  * http://developer.yahoo.net/yui/license.txt
3438  * <script type="text/javascript">
3439  *
3440  */
3441 (function() {
3442
3443     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3444         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3445     };
3446
3447     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3448
3449     var fly = Roo.lib.AnimBase.fly;
3450     var Y = Roo.lib;
3451     var superclass = Y.ColorAnim.superclass;
3452     var proto = Y.ColorAnim.prototype;
3453
3454     proto.toString = function() {
3455         var el = this.getEl();
3456         var id = el.id || el.tagName;
3457         return ("ColorAnim " + id);
3458     };
3459
3460     proto.patterns.color = /color$/i;
3461     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3462     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3463     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3464     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3465
3466
3467     proto.parseColor = function(s) {
3468         if (s.length == 3) {
3469             return s;
3470         }
3471
3472         var c = this.patterns.hex.exec(s);
3473         if (c && c.length == 4) {
3474             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3475         }
3476
3477         c = this.patterns.rgb.exec(s);
3478         if (c && c.length == 4) {
3479             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3480         }
3481
3482         c = this.patterns.hex3.exec(s);
3483         if (c && c.length == 4) {
3484             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3485         }
3486
3487         return null;
3488     };
3489     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3490     proto.getAttribute = function(attr) {
3491         var el = this.getEl();
3492         if (this.patterns.color.test(attr)) {
3493             var val = fly(el).getStyle(attr);
3494
3495             if (this.patterns.transparent.test(val)) {
3496                 var parent = el.parentNode;
3497                 val = fly(parent).getStyle(attr);
3498
3499                 while (parent && this.patterns.transparent.test(val)) {
3500                     parent = parent.parentNode;
3501                     val = fly(parent).getStyle(attr);
3502                     if (parent.tagName.toUpperCase() == 'HTML') {
3503                         val = '#fff';
3504                     }
3505                 }
3506             }
3507         } else {
3508             val = superclass.getAttribute.call(this, attr);
3509         }
3510
3511         return val;
3512     };
3513     proto.getAttribute = function(attr) {
3514         var el = this.getEl();
3515         if (this.patterns.color.test(attr)) {
3516             var val = fly(el).getStyle(attr);
3517
3518             if (this.patterns.transparent.test(val)) {
3519                 var parent = el.parentNode;
3520                 val = fly(parent).getStyle(attr);
3521
3522                 while (parent && this.patterns.transparent.test(val)) {
3523                     parent = parent.parentNode;
3524                     val = fly(parent).getStyle(attr);
3525                     if (parent.tagName.toUpperCase() == 'HTML') {
3526                         val = '#fff';
3527                     }
3528                 }
3529             }
3530         } else {
3531             val = superclass.getAttribute.call(this, attr);
3532         }
3533
3534         return val;
3535     };
3536
3537     proto.doMethod = function(attr, start, end) {
3538         var val;
3539
3540         if (this.patterns.color.test(attr)) {
3541             val = [];
3542             for (var i = 0, len = start.length; i < len; ++i) {
3543                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3544             }
3545
3546             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3547         }
3548         else {
3549             val = superclass.doMethod.call(this, attr, start, end);
3550         }
3551
3552         return val;
3553     };
3554
3555     proto.setRuntimeAttribute = function(attr) {
3556         superclass.setRuntimeAttribute.call(this, attr);
3557
3558         if (this.patterns.color.test(attr)) {
3559             var attributes = this.attributes;
3560             var start = this.parseColor(this.runtimeAttributes[attr].start);
3561             var end = this.parseColor(this.runtimeAttributes[attr].end);
3562
3563             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3564                 end = this.parseColor(attributes[attr].by);
3565
3566                 for (var i = 0, len = start.length; i < len; ++i) {
3567                     end[i] = start[i] + end[i];
3568                 }
3569             }
3570
3571             this.runtimeAttributes[attr].start = start;
3572             this.runtimeAttributes[attr].end = end;
3573         }
3574     };
3575 })();
3576
3577 /*
3578  * Portions of this file are based on pieces of Yahoo User Interface Library
3579  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3580  * YUI licensed under the BSD License:
3581  * http://developer.yahoo.net/yui/license.txt
3582  * <script type="text/javascript">
3583  *
3584  */
3585 Roo.lib.Easing = {
3586
3587
3588     easeNone: function (t, b, c, d) {
3589         return c * t / d + b;
3590     },
3591
3592
3593     easeIn: function (t, b, c, d) {
3594         return c * (t /= d) * t + b;
3595     },
3596
3597
3598     easeOut: function (t, b, c, d) {
3599         return -c * (t /= d) * (t - 2) + b;
3600     },
3601
3602
3603     easeBoth: function (t, b, c, d) {
3604         if ((t /= d / 2) < 1) {
3605             return c / 2 * t * t + b;
3606         }
3607
3608         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3609     },
3610
3611
3612     easeInStrong: function (t, b, c, d) {
3613         return c * (t /= d) * t * t * t + b;
3614     },
3615
3616
3617     easeOutStrong: function (t, b, c, d) {
3618         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3619     },
3620
3621
3622     easeBothStrong: function (t, b, c, d) {
3623         if ((t /= d / 2) < 1) {
3624             return c / 2 * t * t * t * t + b;
3625         }
3626
3627         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3628     },
3629
3630
3631
3632     elasticIn: function (t, b, c, d, a, p) {
3633         if (t == 0) {
3634             return b;
3635         }
3636         if ((t /= d) == 1) {
3637             return b + c;
3638         }
3639         if (!p) {
3640             p = d * .3;
3641         }
3642
3643         if (!a || a < Math.abs(c)) {
3644             a = c;
3645             var s = p / 4;
3646         }
3647         else {
3648             var s = p / (2 * Math.PI) * Math.asin(c / a);
3649         }
3650
3651         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3652     },
3653
3654
3655     elasticOut: function (t, b, c, d, a, p) {
3656         if (t == 0) {
3657             return b;
3658         }
3659         if ((t /= d) == 1) {
3660             return b + c;
3661         }
3662         if (!p) {
3663             p = d * .3;
3664         }
3665
3666         if (!a || a < Math.abs(c)) {
3667             a = c;
3668             var s = p / 4;
3669         }
3670         else {
3671             var s = p / (2 * Math.PI) * Math.asin(c / a);
3672         }
3673
3674         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3675     },
3676
3677
3678     elasticBoth: function (t, b, c, d, a, p) {
3679         if (t == 0) {
3680             return b;
3681         }
3682
3683         if ((t /= d / 2) == 2) {
3684             return b + c;
3685         }
3686
3687         if (!p) {
3688             p = d * (.3 * 1.5);
3689         }
3690
3691         if (!a || a < Math.abs(c)) {
3692             a = c;
3693             var s = p / 4;
3694         }
3695         else {
3696             var s = p / (2 * Math.PI) * Math.asin(c / a);
3697         }
3698
3699         if (t < 1) {
3700             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3701                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3702         }
3703         return a * Math.pow(2, -10 * (t -= 1)) *
3704                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3705     },
3706
3707
3708
3709     backIn: function (t, b, c, d, s) {
3710         if (typeof s == 'undefined') {
3711             s = 1.70158;
3712         }
3713         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3714     },
3715
3716
3717     backOut: function (t, b, c, d, s) {
3718         if (typeof s == 'undefined') {
3719             s = 1.70158;
3720         }
3721         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3722     },
3723
3724
3725     backBoth: function (t, b, c, d, s) {
3726         if (typeof s == 'undefined') {
3727             s = 1.70158;
3728         }
3729
3730         if ((t /= d / 2 ) < 1) {
3731             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3732         }
3733         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3734     },
3735
3736
3737     bounceIn: function (t, b, c, d) {
3738         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3739     },
3740
3741
3742     bounceOut: function (t, b, c, d) {
3743         if ((t /= d) < (1 / 2.75)) {
3744             return c * (7.5625 * t * t) + b;
3745         } else if (t < (2 / 2.75)) {
3746             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3747         } else if (t < (2.5 / 2.75)) {
3748             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3749         }
3750         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3751     },
3752
3753
3754     bounceBoth: function (t, b, c, d) {
3755         if (t < d / 2) {
3756             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3757         }
3758         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3759     }
3760 };/*
3761  * Portions of this file are based on pieces of Yahoo User Interface Library
3762  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3763  * YUI licensed under the BSD License:
3764  * http://developer.yahoo.net/yui/license.txt
3765  * <script type="text/javascript">
3766  *
3767  */
3768     (function() {
3769         Roo.lib.Motion = function(el, attributes, duration, method) {
3770             if (el) {
3771                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3772             }
3773         };
3774
3775         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3776
3777
3778         var Y = Roo.lib;
3779         var superclass = Y.Motion.superclass;
3780         var proto = Y.Motion.prototype;
3781
3782         proto.toString = function() {
3783             var el = this.getEl();
3784             var id = el.id || el.tagName;
3785             return ("Motion " + id);
3786         };
3787
3788         proto.patterns.points = /^points$/i;
3789
3790         proto.setAttribute = function(attr, val, unit) {
3791             if (this.patterns.points.test(attr)) {
3792                 unit = unit || 'px';
3793                 superclass.setAttribute.call(this, 'left', val[0], unit);
3794                 superclass.setAttribute.call(this, 'top', val[1], unit);
3795             } else {
3796                 superclass.setAttribute.call(this, attr, val, unit);
3797             }
3798         };
3799
3800         proto.getAttribute = function(attr) {
3801             if (this.patterns.points.test(attr)) {
3802                 var val = [
3803                         superclass.getAttribute.call(this, 'left'),
3804                         superclass.getAttribute.call(this, 'top')
3805                         ];
3806             } else {
3807                 val = superclass.getAttribute.call(this, attr);
3808             }
3809
3810             return val;
3811         };
3812
3813         proto.doMethod = function(attr, start, end) {
3814             var val = null;
3815
3816             if (this.patterns.points.test(attr)) {
3817                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3818                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3819             } else {
3820                 val = superclass.doMethod.call(this, attr, start, end);
3821             }
3822             return val;
3823         };
3824
3825         proto.setRuntimeAttribute = function(attr) {
3826             if (this.patterns.points.test(attr)) {
3827                 var el = this.getEl();
3828                 var attributes = this.attributes;
3829                 var start;
3830                 var control = attributes['points']['control'] || [];
3831                 var end;
3832                 var i, len;
3833
3834                 if (control.length > 0 && !(control[0] instanceof Array)) {
3835                     control = [control];
3836                 } else {
3837                     var tmp = [];
3838                     for (i = 0,len = control.length; i < len; ++i) {
3839                         tmp[i] = control[i];
3840                     }
3841                     control = tmp;
3842                 }
3843
3844                 Roo.fly(el).position();
3845
3846                 if (isset(attributes['points']['from'])) {
3847                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3848                 }
3849                 else {
3850                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3851                 }
3852
3853                 start = this.getAttribute('points');
3854
3855
3856                 if (isset(attributes['points']['to'])) {
3857                     end = translateValues.call(this, attributes['points']['to'], start);
3858
3859                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3860                     for (i = 0,len = control.length; i < len; ++i) {
3861                         control[i] = translateValues.call(this, control[i], start);
3862                     }
3863
3864
3865                 } else if (isset(attributes['points']['by'])) {
3866                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3867
3868                     for (i = 0,len = control.length; i < len; ++i) {
3869                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3870                     }
3871                 }
3872
3873                 this.runtimeAttributes[attr] = [start];
3874
3875                 if (control.length > 0) {
3876                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3877                 }
3878
3879                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3880             }
3881             else {
3882                 superclass.setRuntimeAttribute.call(this, attr);
3883             }
3884         };
3885
3886         var translateValues = function(val, start) {
3887             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3888             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3889
3890             return val;
3891         };
3892
3893         var isset = function(prop) {
3894             return (typeof prop !== 'undefined');
3895         };
3896     })();
3897 /*
3898  * Portions of this file are based on pieces of Yahoo User Interface Library
3899  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3900  * YUI licensed under the BSD License:
3901  * http://developer.yahoo.net/yui/license.txt
3902  * <script type="text/javascript">
3903  *
3904  */
3905     (function() {
3906         Roo.lib.Scroll = function(el, attributes, duration, method) {
3907             if (el) {
3908                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3909             }
3910         };
3911
3912         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3913
3914
3915         var Y = Roo.lib;
3916         var superclass = Y.Scroll.superclass;
3917         var proto = Y.Scroll.prototype;
3918
3919         proto.toString = function() {
3920             var el = this.getEl();
3921             var id = el.id || el.tagName;
3922             return ("Scroll " + id);
3923         };
3924
3925         proto.doMethod = function(attr, start, end) {
3926             var val = null;
3927
3928             if (attr == 'scroll') {
3929                 val = [
3930                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3931                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3932                         ];
3933
3934             } else {
3935                 val = superclass.doMethod.call(this, attr, start, end);
3936             }
3937             return val;
3938         };
3939
3940         proto.getAttribute = function(attr) {
3941             var val = null;
3942             var el = this.getEl();
3943
3944             if (attr == 'scroll') {
3945                 val = [ el.scrollLeft, el.scrollTop ];
3946             } else {
3947                 val = superclass.getAttribute.call(this, attr);
3948             }
3949
3950             return val;
3951         };
3952
3953         proto.setAttribute = function(attr, val, unit) {
3954             var el = this.getEl();
3955
3956             if (attr == 'scroll') {
3957                 el.scrollLeft = val[0];
3958                 el.scrollTop = val[1];
3959             } else {
3960                 superclass.setAttribute.call(this, attr, val, unit);
3961             }
3962         };
3963     })();
3964 /*
3965  * Based on:
3966  * Ext JS Library 1.1.1
3967  * Copyright(c) 2006-2007, Ext JS, LLC.
3968  *
3969  * Originally Released Under LGPL - original licence link has changed is not relivant.
3970  *
3971  * Fork - LGPL
3972  * <script type="text/javascript">
3973  */
3974  
3975
3976 /**
3977  * @class Roo.DomHelper
3978  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3979  * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3980  * @singleton
3981  */
3982 Roo.DomHelper = function(){
3983     var tempTableEl = null;
3984     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3985     var tableRe = /^table|tbody|tr|td$/i;
3986     var xmlns = {};
3987     // build as innerHTML where available
3988     /** @ignore */
3989     var createHtml = function(o){
3990         if(typeof o == 'string'){
3991             return o;
3992         }
3993         var b = "";
3994         if(!o.tag){
3995             o.tag = "div";
3996         }
3997         b += "<" + o.tag;
3998         for(var attr in o){
3999             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4000             if(attr == "style"){
4001                 var s = o["style"];
4002                 if(typeof s == "function"){
4003                     s = s.call();
4004                 }
4005                 if(typeof s == "string"){
4006                     b += ' style="' + s + '"';
4007                 }else if(typeof s == "object"){
4008                     b += ' style="';
4009                     for(var key in s){
4010                         if(typeof s[key] != "function"){
4011                             b += key + ":" + s[key] + ";";
4012                         }
4013                     }
4014                     b += '"';
4015                 }
4016             }else{
4017                 if(attr == "cls"){
4018                     b += ' class="' + o["cls"] + '"';
4019                 }else if(attr == "htmlFor"){
4020                     b += ' for="' + o["htmlFor"] + '"';
4021                 }else{
4022                     b += " " + attr + '="' + o[attr] + '"';
4023                 }
4024             }
4025         }
4026         if(emptyTags.test(o.tag)){
4027             b += "/>";
4028         }else{
4029             b += ">";
4030             var cn = o.children || o.cn;
4031             if(cn){
4032                 //http://bugs.kde.org/show_bug.cgi?id=71506
4033                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4034                     for(var i = 0, len = cn.length; i < len; i++) {
4035                         b += createHtml(cn[i], b);
4036                     }
4037                 }else{
4038                     b += createHtml(cn, b);
4039                 }
4040             }
4041             if(o.html){
4042                 b += o.html;
4043             }
4044             b += "</" + o.tag + ">";
4045         }
4046         return b;
4047     };
4048
4049     // build as dom
4050     /** @ignore */
4051     var createDom = function(o, parentNode){
4052          
4053         // defininition craeted..
4054         var ns = false;
4055         if (o.ns && o.ns != 'html') {
4056                
4057             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4058                 xmlns[o.ns] = o.xmlns;
4059                 ns = o.xmlns;
4060             }
4061             if (typeof(xmlns[o.ns]) == 'undefined') {
4062                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4063             }
4064             ns = xmlns[o.ns];
4065         }
4066         
4067         
4068         if (typeof(o) == 'string') {
4069             return parentNode.appendChild(document.createTextNode(o));
4070         }
4071         o.tag = o.tag || div;
4072         if (o.ns && Roo.isIE) {
4073             ns = false;
4074             o.tag = o.ns + ':' + o.tag;
4075             
4076         }
4077         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4078         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4079         for(var attr in o){
4080             
4081             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4082                     attr == "style" || typeof o[attr] == "function") continue;
4083                     
4084             if(attr=="cls" && Roo.isIE){
4085                 el.className = o["cls"];
4086             }else{
4087                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4088                 else el[attr] = o[attr];
4089             }
4090         }
4091         Roo.DomHelper.applyStyles(el, o.style);
4092         var cn = o.children || o.cn;
4093         if(cn){
4094             //http://bugs.kde.org/show_bug.cgi?id=71506
4095              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4096                 for(var i = 0, len = cn.length; i < len; i++) {
4097                     createDom(cn[i], el);
4098                 }
4099             }else{
4100                 createDom(cn, el);
4101             }
4102         }
4103         if(o.html){
4104             el.innerHTML = o.html;
4105         }
4106         if(parentNode){
4107            parentNode.appendChild(el);
4108         }
4109         return el;
4110     };
4111
4112     var ieTable = function(depth, s, h, e){
4113         tempTableEl.innerHTML = [s, h, e].join('');
4114         var i = -1, el = tempTableEl;
4115         while(++i < depth){
4116             el = el.firstChild;
4117         }
4118         return el;
4119     };
4120
4121     // kill repeat to save bytes
4122     var ts = '<table>',
4123         te = '</table>',
4124         tbs = ts+'<tbody>',
4125         tbe = '</tbody>'+te,
4126         trs = tbs + '<tr>',
4127         tre = '</tr>'+tbe;
4128
4129     /**
4130      * @ignore
4131      * Nasty code for IE's broken table implementation
4132      */
4133     var insertIntoTable = function(tag, where, el, html){
4134         if(!tempTableEl){
4135             tempTableEl = document.createElement('div');
4136         }
4137         var node;
4138         var before = null;
4139         if(tag == 'td'){
4140             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4141                 return;
4142             }
4143             if(where == 'beforebegin'){
4144                 before = el;
4145                 el = el.parentNode;
4146             } else{
4147                 before = el.nextSibling;
4148                 el = el.parentNode;
4149             }
4150             node = ieTable(4, trs, html, tre);
4151         }
4152         else if(tag == 'tr'){
4153             if(where == 'beforebegin'){
4154                 before = el;
4155                 el = el.parentNode;
4156                 node = ieTable(3, tbs, html, tbe);
4157             } else if(where == 'afterend'){
4158                 before = el.nextSibling;
4159                 el = el.parentNode;
4160                 node = ieTable(3, tbs, html, tbe);
4161             } else{ // INTO a TR
4162                 if(where == 'afterbegin'){
4163                     before = el.firstChild;
4164                 }
4165                 node = ieTable(4, trs, html, tre);
4166             }
4167         } else if(tag == 'tbody'){
4168             if(where == 'beforebegin'){
4169                 before = el;
4170                 el = el.parentNode;
4171                 node = ieTable(2, ts, html, te);
4172             } else if(where == 'afterend'){
4173                 before = el.nextSibling;
4174                 el = el.parentNode;
4175                 node = ieTable(2, ts, html, te);
4176             } else{
4177                 if(where == 'afterbegin'){
4178                     before = el.firstChild;
4179                 }
4180                 node = ieTable(3, tbs, html, tbe);
4181             }
4182         } else{ // TABLE
4183             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4184                 return;
4185             }
4186             if(where == 'afterbegin'){
4187                 before = el.firstChild;
4188             }
4189             node = ieTable(2, ts, html, te);
4190         }
4191         el.insertBefore(node, before);
4192         return node;
4193     };
4194
4195     return {
4196     /** True to force the use of DOM instead of html fragments @type Boolean */
4197     useDom : false,
4198
4199     /**
4200      * Returns the markup for the passed Element(s) config
4201      * @param {Object} o The Dom object spec (and children)
4202      * @return {String}
4203      */
4204     markup : function(o){
4205         return createHtml(o);
4206     },
4207
4208     /**
4209      * Applies a style specification to an element
4210      * @param {String/HTMLElement} el The element to apply styles to
4211      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4212      * a function which returns such a specification.
4213      */
4214     applyStyles : function(el, styles){
4215         if(styles){
4216            el = Roo.fly(el);
4217            if(typeof styles == "string"){
4218                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4219                var matches;
4220                while ((matches = re.exec(styles)) != null){
4221                    el.setStyle(matches[1], matches[2]);
4222                }
4223            }else if (typeof styles == "object"){
4224                for (var style in styles){
4225                   el.setStyle(style, styles[style]);
4226                }
4227            }else if (typeof styles == "function"){
4228                 Roo.DomHelper.applyStyles(el, styles.call());
4229            }
4230         }
4231     },
4232
4233     /**
4234      * Inserts an HTML fragment into the Dom
4235      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4236      * @param {HTMLElement} el The context element
4237      * @param {String} html The HTML fragmenet
4238      * @return {HTMLElement} The new node
4239      */
4240     insertHtml : function(where, el, html){
4241         where = where.toLowerCase();
4242         if(el.insertAdjacentHTML){
4243             if(tableRe.test(el.tagName)){
4244                 var rs;
4245                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4246                     return rs;
4247                 }
4248             }
4249             switch(where){
4250                 case "beforebegin":
4251                     el.insertAdjacentHTML('BeforeBegin', html);
4252                     return el.previousSibling;
4253                 case "afterbegin":
4254                     el.insertAdjacentHTML('AfterBegin', html);
4255                     return el.firstChild;
4256                 case "beforeend":
4257                     el.insertAdjacentHTML('BeforeEnd', html);
4258                     return el.lastChild;
4259                 case "afterend":
4260                     el.insertAdjacentHTML('AfterEnd', html);
4261                     return el.nextSibling;
4262             }
4263             throw 'Illegal insertion point -> "' + where + '"';
4264         }
4265         var range = el.ownerDocument.createRange();
4266         var frag;
4267         switch(where){
4268              case "beforebegin":
4269                 range.setStartBefore(el);
4270                 frag = range.createContextualFragment(html);
4271                 el.parentNode.insertBefore(frag, el);
4272                 return el.previousSibling;
4273              case "afterbegin":
4274                 if(el.firstChild){
4275                     range.setStartBefore(el.firstChild);
4276                     frag = range.createContextualFragment(html);
4277                     el.insertBefore(frag, el.firstChild);
4278                     return el.firstChild;
4279                 }else{
4280                     el.innerHTML = html;
4281                     return el.firstChild;
4282                 }
4283             case "beforeend":
4284                 if(el.lastChild){
4285                     range.setStartAfter(el.lastChild);
4286                     frag = range.createContextualFragment(html);
4287                     el.appendChild(frag);
4288                     return el.lastChild;
4289                 }else{
4290                     el.innerHTML = html;
4291                     return el.lastChild;
4292                 }
4293             case "afterend":
4294                 range.setStartAfter(el);
4295                 frag = range.createContextualFragment(html);
4296                 el.parentNode.insertBefore(frag, el.nextSibling);
4297                 return el.nextSibling;
4298             }
4299             throw 'Illegal insertion point -> "' + where + '"';
4300     },
4301
4302     /**
4303      * Creates new Dom element(s) and inserts them before el
4304      * @param {String/HTMLElement/Element} el The context element
4305      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4306      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4307      * @return {HTMLElement/Roo.Element} The new node
4308      */
4309     insertBefore : function(el, o, returnElement){
4310         return this.doInsert(el, o, returnElement, "beforeBegin");
4311     },
4312
4313     /**
4314      * Creates new Dom element(s) and inserts them after el
4315      * @param {String/HTMLElement/Element} el The context element
4316      * @param {Object} o The Dom object spec (and children)
4317      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4318      * @return {HTMLElement/Roo.Element} The new node
4319      */
4320     insertAfter : function(el, o, returnElement){
4321         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4322     },
4323
4324     /**
4325      * Creates new Dom element(s) and inserts them as the first child of el
4326      * @param {String/HTMLElement/Element} el The context element
4327      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4328      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4329      * @return {HTMLElement/Roo.Element} The new node
4330      */
4331     insertFirst : function(el, o, returnElement){
4332         return this.doInsert(el, o, returnElement, "afterBegin");
4333     },
4334
4335     // private
4336     doInsert : function(el, o, returnElement, pos, sibling){
4337         el = Roo.getDom(el);
4338         var newNode;
4339         if(this.useDom || o.ns){
4340             newNode = createDom(o, null);
4341             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4342         }else{
4343             var html = createHtml(o);
4344             newNode = this.insertHtml(pos, el, html);
4345         }
4346         return returnElement ? Roo.get(newNode, true) : newNode;
4347     },
4348
4349     /**
4350      * Creates new Dom element(s) and appends them to el
4351      * @param {String/HTMLElement/Element} el The context element
4352      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4353      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4354      * @return {HTMLElement/Roo.Element} The new node
4355      */
4356     append : function(el, o, returnElement){
4357         el = Roo.getDom(el);
4358         var newNode;
4359         if(this.useDom || o.ns){
4360             newNode = createDom(o, null);
4361             el.appendChild(newNode);
4362         }else{
4363             var html = createHtml(o);
4364             newNode = this.insertHtml("beforeEnd", el, html);
4365         }
4366         return returnElement ? Roo.get(newNode, true) : newNode;
4367     },
4368
4369     /**
4370      * Creates new Dom element(s) and overwrites the contents of el with them
4371      * @param {String/HTMLElement/Element} el The context element
4372      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4373      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4374      * @return {HTMLElement/Roo.Element} The new node
4375      */
4376     overwrite : function(el, o, returnElement){
4377         el = Roo.getDom(el);
4378         if (o.ns) {
4379           
4380             while (el.childNodes.length) {
4381                 el.removeChild(el.firstChild);
4382             }
4383             createDom(o, el);
4384         } else {
4385             el.innerHTML = createHtml(o);   
4386         }
4387         
4388         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4389     },
4390
4391     /**
4392      * Creates a new Roo.DomHelper.Template from the Dom object spec
4393      * @param {Object} o The Dom object spec (and children)
4394      * @return {Roo.DomHelper.Template} The new template
4395      */
4396     createTemplate : function(o){
4397         var html = createHtml(o);
4398         return new Roo.Template(html);
4399     }
4400     };
4401 }();
4402 /*
4403  * Based on:
4404  * Ext JS Library 1.1.1
4405  * Copyright(c) 2006-2007, Ext JS, LLC.
4406  *
4407  * Originally Released Under LGPL - original licence link has changed is not relivant.
4408  *
4409  * Fork - LGPL
4410  * <script type="text/javascript">
4411  */
4412  
4413 /**
4414 * @class Roo.Template
4415 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4416 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4417 * Usage:
4418 <pre><code>
4419 var t = new Roo.Template({
4420     html :  '&lt;div name="{id}"&gt;' + 
4421         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4422         '&lt;/div&gt;',
4423     myformat: function (value, allValues) {
4424         return 'XX' + value;
4425     }
4426 });
4427 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4428 </code></pre>
4429 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
4430 * @constructor
4431 * @param {Object} cfg - Configuration object.
4432 */
4433 Roo.Template = function(cfg){
4434     // BC!
4435     if(cfg instanceof Array){
4436         cfg = cfg.join("");
4437     }else if(arguments.length > 1){
4438         cfg = Array.prototype.join.call(arguments, "");
4439     }
4440     
4441     
4442     if (typeof(cfg) == 'object') {
4443         Roo.apply(this,cfg)
4444     } else {
4445         // bc
4446         this.html = cfg;
4447     }
4448     
4449     
4450 };
4451 Roo.Template.prototype = {
4452     
4453     /**
4454      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4455      */
4456     html : '',
4457     /**
4458      * Returns an HTML fragment of this template with the specified values applied.
4459      * @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'})
4460      * @return {String} The HTML fragment
4461      */
4462     applyTemplate : function(values){
4463         try {
4464             
4465             if(this.compiled){
4466                 return this.compiled(values);
4467             }
4468             var useF = this.disableFormats !== true;
4469             var fm = Roo.util.Format, tpl = this;
4470             var fn = function(m, name, format, args){
4471                 if(format && useF){
4472                     if(format.substr(0, 5) == "this."){
4473                         return tpl.call(format.substr(5), values[name], values);
4474                     }else{
4475                         if(args){
4476                             // quoted values are required for strings in compiled templates, 
4477                             // but for non compiled we need to strip them
4478                             // quoted reversed for jsmin
4479                             var re = /^\s*['"](.*)["']\s*$/;
4480                             args = args.split(',');
4481                             for(var i = 0, len = args.length; i < len; i++){
4482                                 args[i] = args[i].replace(re, "$1");
4483                             }
4484                             args = [values[name]].concat(args);
4485                         }else{
4486                             args = [values[name]];
4487                         }
4488                         return fm[format].apply(fm, args);
4489                     }
4490                 }else{
4491                     return values[name] !== undefined ? values[name] : "";
4492                 }
4493             };
4494             return this.html.replace(this.re, fn);
4495         } catch (e) {
4496             Roo.log(e);
4497             throw e;
4498         }
4499          
4500     },
4501     
4502     /**
4503      * Sets the HTML used as the template and optionally compiles it.
4504      * @param {String} html
4505      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4506      * @return {Roo.Template} this
4507      */
4508     set : function(html, compile){
4509         this.html = html;
4510         this.compiled = null;
4511         if(compile){
4512             this.compile();
4513         }
4514         return this;
4515     },
4516     
4517     /**
4518      * True to disable format functions (defaults to false)
4519      * @type Boolean
4520      */
4521     disableFormats : false,
4522     
4523     /**
4524     * The regular expression used to match template variables 
4525     * @type RegExp
4526     * @property 
4527     */
4528     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4529     
4530     /**
4531      * Compiles the template into an internal function, eliminating the RegEx overhead.
4532      * @return {Roo.Template} this
4533      */
4534     compile : function(){
4535         var fm = Roo.util.Format;
4536         var useF = this.disableFormats !== true;
4537         var sep = Roo.isGecko ? "+" : ",";
4538         var fn = function(m, name, format, args){
4539             if(format && useF){
4540                 args = args ? ',' + args : "";
4541                 if(format.substr(0, 5) != "this."){
4542                     format = "fm." + format + '(';
4543                 }else{
4544                     format = 'this.call("'+ format.substr(5) + '", ';
4545                     args = ", values";
4546                 }
4547             }else{
4548                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4549             }
4550             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4551         };
4552         var body;
4553         // branched to use + in gecko and [].join() in others
4554         if(Roo.isGecko){
4555             body = "this.compiled = function(values){ return '" +
4556                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4557                     "';};";
4558         }else{
4559             body = ["this.compiled = function(values){ return ['"];
4560             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4561             body.push("'].join('');};");
4562             body = body.join('');
4563         }
4564         /**
4565          * eval:var:values
4566          * eval:var:fm
4567          */
4568         eval(body);
4569         return this;
4570     },
4571     
4572     // private function used to call members
4573     call : function(fnName, value, allValues){
4574         return this[fnName](value, allValues);
4575     },
4576     
4577     /**
4578      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4579      * @param {String/HTMLElement/Roo.Element} el The context element
4580      * @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'})
4581      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4582      * @return {HTMLElement/Roo.Element} The new node or Element
4583      */
4584     insertFirst: function(el, values, returnElement){
4585         return this.doInsert('afterBegin', el, values, returnElement);
4586     },
4587
4588     /**
4589      * Applies the supplied values to the template and inserts the new node(s) before el.
4590      * @param {String/HTMLElement/Roo.Element} el The context element
4591      * @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'})
4592      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4593      * @return {HTMLElement/Roo.Element} The new node or Element
4594      */
4595     insertBefore: function(el, values, returnElement){
4596         return this.doInsert('beforeBegin', el, values, returnElement);
4597     },
4598
4599     /**
4600      * Applies the supplied values to the template and inserts the new node(s) after el.
4601      * @param {String/HTMLElement/Roo.Element} el The context element
4602      * @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'})
4603      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4604      * @return {HTMLElement/Roo.Element} The new node or Element
4605      */
4606     insertAfter : function(el, values, returnElement){
4607         return this.doInsert('afterEnd', el, values, returnElement);
4608     },
4609     
4610     /**
4611      * Applies the supplied values to the template and appends the new node(s) to el.
4612      * @param {String/HTMLElement/Roo.Element} el The context element
4613      * @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'})
4614      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4615      * @return {HTMLElement/Roo.Element} The new node or Element
4616      */
4617     append : function(el, values, returnElement){
4618         return this.doInsert('beforeEnd', el, values, returnElement);
4619     },
4620
4621     doInsert : function(where, el, values, returnEl){
4622         el = Roo.getDom(el);
4623         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4624         return returnEl ? Roo.get(newNode, true) : newNode;
4625     },
4626
4627     /**
4628      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4629      * @param {String/HTMLElement/Roo.Element} el The context element
4630      * @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'})
4631      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4632      * @return {HTMLElement/Roo.Element} The new node or Element
4633      */
4634     overwrite : function(el, values, returnElement){
4635         el = Roo.getDom(el);
4636         el.innerHTML = this.applyTemplate(values);
4637         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4638     }
4639 };
4640 /**
4641  * Alias for {@link #applyTemplate}
4642  * @method
4643  */
4644 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4645
4646 // backwards compat
4647 Roo.DomHelper.Template = Roo.Template;
4648
4649 /**
4650  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4651  * @param {String/HTMLElement} el A DOM element or its id
4652  * @returns {Roo.Template} The created template
4653  * @static
4654  */
4655 Roo.Template.from = function(el){
4656     el = Roo.getDom(el);
4657     return new Roo.Template(el.value || el.innerHTML);
4658 };/*
4659  * Based on:
4660  * Ext JS Library 1.1.1
4661  * Copyright(c) 2006-2007, Ext JS, LLC.
4662  *
4663  * Originally Released Under LGPL - original licence link has changed is not relivant.
4664  *
4665  * Fork - LGPL
4666  * <script type="text/javascript">
4667  */
4668  
4669
4670 /*
4671  * This is code is also distributed under MIT license for use
4672  * with jQuery and prototype JavaScript libraries.
4673  */
4674 /**
4675  * @class Roo.DomQuery
4676 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).
4677 <p>
4678 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>
4679
4680 <p>
4681 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.
4682 </p>
4683 <h4>Element Selectors:</h4>
4684 <ul class="list">
4685     <li> <b>*</b> any element</li>
4686     <li> <b>E</b> an element with the tag E</li>
4687     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4688     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4689     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4690     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4691 </ul>
4692 <h4>Attribute Selectors:</h4>
4693 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4694 <ul class="list">
4695     <li> <b>E[foo]</b> has an attribute "foo"</li>
4696     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4697     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4698     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4699     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4700     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4701     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4702 </ul>
4703 <h4>Pseudo Classes:</h4>
4704 <ul class="list">
4705     <li> <b>E:first-child</b> E is the first child of its parent</li>
4706     <li> <b>E:last-child</b> E is the last child of its parent</li>
4707     <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>
4708     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4709     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4710     <li> <b>E:only-child</b> E is the only child of its parent</li>
4711     <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>
4712     <li> <b>E:first</b> the first E in the resultset</li>
4713     <li> <b>E:last</b> the last E in the resultset</li>
4714     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4715     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4716     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4717     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4718     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4719     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4720     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4721     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4722     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4723 </ul>
4724 <h4>CSS Value Selectors:</h4>
4725 <ul class="list">
4726     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4727     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4728     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4729     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4730     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4731     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4732 </ul>
4733  * @singleton
4734  */
4735 Roo.DomQuery = function(){
4736     var cache = {}, simpleCache = {}, valueCache = {};
4737     var nonSpace = /\S/;
4738     var trimRe = /^\s+|\s+$/g;
4739     var tplRe = /\{(\d+)\}/g;
4740     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4741     var tagTokenRe = /^(#)?([\w-\*]+)/;
4742     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4743
4744     function child(p, index){
4745         var i = 0;
4746         var n = p.firstChild;
4747         while(n){
4748             if(n.nodeType == 1){
4749                if(++i == index){
4750                    return n;
4751                }
4752             }
4753             n = n.nextSibling;
4754         }
4755         return null;
4756     };
4757
4758     function next(n){
4759         while((n = n.nextSibling) && n.nodeType != 1);
4760         return n;
4761     };
4762
4763     function prev(n){
4764         while((n = n.previousSibling) && n.nodeType != 1);
4765         return n;
4766     };
4767
4768     function children(d){
4769         var n = d.firstChild, ni = -1;
4770             while(n){
4771                 var nx = n.nextSibling;
4772                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4773                     d.removeChild(n);
4774                 }else{
4775                     n.nodeIndex = ++ni;
4776                 }
4777                 n = nx;
4778             }
4779             return this;
4780         };
4781
4782     function byClassName(c, a, v){
4783         if(!v){
4784             return c;
4785         }
4786         var r = [], ri = -1, cn;
4787         for(var i = 0, ci; ci = c[i]; i++){
4788             if((' '+ci.className+' ').indexOf(v) != -1){
4789                 r[++ri] = ci;
4790             }
4791         }
4792         return r;
4793     };
4794
4795     function attrValue(n, attr){
4796         if(!n.tagName && typeof n.length != "undefined"){
4797             n = n[0];
4798         }
4799         if(!n){
4800             return null;
4801         }
4802         if(attr == "for"){
4803             return n.htmlFor;
4804         }
4805         if(attr == "class" || attr == "className"){
4806             return n.className;
4807         }
4808         return n.getAttribute(attr) || n[attr];
4809
4810     };
4811
4812     function getNodes(ns, mode, tagName){
4813         var result = [], ri = -1, cs;
4814         if(!ns){
4815             return result;
4816         }
4817         tagName = tagName || "*";
4818         if(typeof ns.getElementsByTagName != "undefined"){
4819             ns = [ns];
4820         }
4821         if(!mode){
4822             for(var i = 0, ni; ni = ns[i]; i++){
4823                 cs = ni.getElementsByTagName(tagName);
4824                 for(var j = 0, ci; ci = cs[j]; j++){
4825                     result[++ri] = ci;
4826                 }
4827             }
4828         }else if(mode == "/" || mode == ">"){
4829             var utag = tagName.toUpperCase();
4830             for(var i = 0, ni, cn; ni = ns[i]; i++){
4831                 cn = ni.children || ni.childNodes;
4832                 for(var j = 0, cj; cj = cn[j]; j++){
4833                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4834                         result[++ri] = cj;
4835                     }
4836                 }
4837             }
4838         }else if(mode == "+"){
4839             var utag = tagName.toUpperCase();
4840             for(var i = 0, n; n = ns[i]; i++){
4841                 while((n = n.nextSibling) && n.nodeType != 1);
4842                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4843                     result[++ri] = n;
4844                 }
4845             }
4846         }else if(mode == "~"){
4847             for(var i = 0, n; n = ns[i]; i++){
4848                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4849                 if(n){
4850                     result[++ri] = n;
4851                 }
4852             }
4853         }
4854         return result;
4855     };
4856
4857     function concat(a, b){
4858         if(b.slice){
4859             return a.concat(b);
4860         }
4861         for(var i = 0, l = b.length; i < l; i++){
4862             a[a.length] = b[i];
4863         }
4864         return a;
4865     }
4866
4867     function byTag(cs, tagName){
4868         if(cs.tagName || cs == document){
4869             cs = [cs];
4870         }
4871         if(!tagName){
4872             return cs;
4873         }
4874         var r = [], ri = -1;
4875         tagName = tagName.toLowerCase();
4876         for(var i = 0, ci; ci = cs[i]; i++){
4877             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4878                 r[++ri] = ci;
4879             }
4880         }
4881         return r;
4882     };
4883
4884     function byId(cs, attr, id){
4885         if(cs.tagName || cs == document){
4886             cs = [cs];
4887         }
4888         if(!id){
4889             return cs;
4890         }
4891         var r = [], ri = -1;
4892         for(var i = 0,ci; ci = cs[i]; i++){
4893             if(ci && ci.id == id){
4894                 r[++ri] = ci;
4895                 return r;
4896             }
4897         }
4898         return r;
4899     };
4900
4901     function byAttribute(cs, attr, value, op, custom){
4902         var r = [], ri = -1, st = custom=="{";
4903         var f = Roo.DomQuery.operators[op];
4904         for(var i = 0, ci; ci = cs[i]; i++){
4905             var a;
4906             if(st){
4907                 a = Roo.DomQuery.getStyle(ci, attr);
4908             }
4909             else if(attr == "class" || attr == "className"){
4910                 a = ci.className;
4911             }else if(attr == "for"){
4912                 a = ci.htmlFor;
4913             }else if(attr == "href"){
4914                 a = ci.getAttribute("href", 2);
4915             }else{
4916                 a = ci.getAttribute(attr);
4917             }
4918             if((f && f(a, value)) || (!f && a)){
4919                 r[++ri] = ci;
4920             }
4921         }
4922         return r;
4923     };
4924
4925     function byPseudo(cs, name, value){
4926         return Roo.DomQuery.pseudos[name](cs, value);
4927     };
4928
4929     // This is for IE MSXML which does not support expandos.
4930     // IE runs the same speed using setAttribute, however FF slows way down
4931     // and Safari completely fails so they need to continue to use expandos.
4932     var isIE = window.ActiveXObject ? true : false;
4933
4934     // this eval is stop the compressor from
4935     // renaming the variable to something shorter
4936     
4937     /** eval:var:batch */
4938     var batch = 30803; 
4939
4940     var key = 30803;
4941
4942     function nodupIEXml(cs){
4943         var d = ++key;
4944         cs[0].setAttribute("_nodup", d);
4945         var r = [cs[0]];
4946         for(var i = 1, len = cs.length; i < len; i++){
4947             var c = cs[i];
4948             if(!c.getAttribute("_nodup") != d){
4949                 c.setAttribute("_nodup", d);
4950                 r[r.length] = c;
4951             }
4952         }
4953         for(var i = 0, len = cs.length; i < len; i++){
4954             cs[i].removeAttribute("_nodup");
4955         }
4956         return r;
4957     }
4958
4959     function nodup(cs){
4960         if(!cs){
4961             return [];
4962         }
4963         var len = cs.length, c, i, r = cs, cj, ri = -1;
4964         if(!len || typeof cs.nodeType != "undefined" || len == 1){
4965             return cs;
4966         }
4967         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4968             return nodupIEXml(cs);
4969         }
4970         var d = ++key;
4971         cs[0]._nodup = d;
4972         for(i = 1; c = cs[i]; i++){
4973             if(c._nodup != d){
4974                 c._nodup = d;
4975             }else{
4976                 r = [];
4977                 for(var j = 0; j < i; j++){
4978                     r[++ri] = cs[j];
4979                 }
4980                 for(j = i+1; cj = cs[j]; j++){
4981                     if(cj._nodup != d){
4982                         cj._nodup = d;
4983                         r[++ri] = cj;
4984                     }
4985                 }
4986                 return r;
4987             }
4988         }
4989         return r;
4990     }
4991
4992     function quickDiffIEXml(c1, c2){
4993         var d = ++key;
4994         for(var i = 0, len = c1.length; i < len; i++){
4995             c1[i].setAttribute("_qdiff", d);
4996         }
4997         var r = [];
4998         for(var i = 0, len = c2.length; i < len; i++){
4999             if(c2[i].getAttribute("_qdiff") != d){
5000                 r[r.length] = c2[i];
5001             }
5002         }
5003         for(var i = 0, len = c1.length; i < len; i++){
5004            c1[i].removeAttribute("_qdiff");
5005         }
5006         return r;
5007     }
5008
5009     function quickDiff(c1, c2){
5010         var len1 = c1.length;
5011         if(!len1){
5012             return c2;
5013         }
5014         if(isIE && c1[0].selectSingleNode){
5015             return quickDiffIEXml(c1, c2);
5016         }
5017         var d = ++key;
5018         for(var i = 0; i < len1; i++){
5019             c1[i]._qdiff = d;
5020         }
5021         var r = [];
5022         for(var i = 0, len = c2.length; i < len; i++){
5023             if(c2[i]._qdiff != d){
5024                 r[r.length] = c2[i];
5025             }
5026         }
5027         return r;
5028     }
5029
5030     function quickId(ns, mode, root, id){
5031         if(ns == root){
5032            var d = root.ownerDocument || root;
5033            return d.getElementById(id);
5034         }
5035         ns = getNodes(ns, mode, "*");
5036         return byId(ns, null, id);
5037     }
5038
5039     return {
5040         getStyle : function(el, name){
5041             return Roo.fly(el).getStyle(name);
5042         },
5043         /**
5044          * Compiles a selector/xpath query into a reusable function. The returned function
5045          * takes one parameter "root" (optional), which is the context node from where the query should start.
5046          * @param {String} selector The selector/xpath query
5047          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5048          * @return {Function}
5049          */
5050         compile : function(path, type){
5051             type = type || "select";
5052             
5053             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5054             var q = path, mode, lq;
5055             var tk = Roo.DomQuery.matchers;
5056             var tklen = tk.length;
5057             var mm;
5058
5059             // accept leading mode switch
5060             var lmode = q.match(modeRe);
5061             if(lmode && lmode[1]){
5062                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5063                 q = q.replace(lmode[1], "");
5064             }
5065             // strip leading slashes
5066             while(path.substr(0, 1)=="/"){
5067                 path = path.substr(1);
5068             }
5069
5070             while(q && lq != q){
5071                 lq = q;
5072                 var tm = q.match(tagTokenRe);
5073                 if(type == "select"){
5074                     if(tm){
5075                         if(tm[1] == "#"){
5076                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5077                         }else{
5078                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5079                         }
5080                         q = q.replace(tm[0], "");
5081                     }else if(q.substr(0, 1) != '@'){
5082                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5083                     }
5084                 }else{
5085                     if(tm){
5086                         if(tm[1] == "#"){
5087                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5088                         }else{
5089                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5090                         }
5091                         q = q.replace(tm[0], "");
5092                     }
5093                 }
5094                 while(!(mm = q.match(modeRe))){
5095                     var matched = false;
5096                     for(var j = 0; j < tklen; j++){
5097                         var t = tk[j];
5098                         var m = q.match(t.re);
5099                         if(m){
5100                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5101                                                     return m[i];
5102                                                 });
5103                             q = q.replace(m[0], "");
5104                             matched = true;
5105                             break;
5106                         }
5107                     }
5108                     // prevent infinite loop on bad selector
5109                     if(!matched){
5110                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5111                     }
5112                 }
5113                 if(mm[1]){
5114                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5115                     q = q.replace(mm[1], "");
5116                 }
5117             }
5118             fn[fn.length] = "return nodup(n);\n}";
5119             
5120              /** 
5121               * list of variables that need from compression as they are used by eval.
5122              *  eval:var:batch 
5123              *  eval:var:nodup
5124              *  eval:var:byTag
5125              *  eval:var:ById
5126              *  eval:var:getNodes
5127              *  eval:var:quickId
5128              *  eval:var:mode
5129              *  eval:var:root
5130              *  eval:var:n
5131              *  eval:var:byClassName
5132              *  eval:var:byPseudo
5133              *  eval:var:byAttribute
5134              *  eval:var:attrValue
5135              * 
5136              **/ 
5137             eval(fn.join(""));
5138             return f;
5139         },
5140
5141         /**
5142          * Selects a group of elements.
5143          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5144          * @param {Node} root (optional) The start of the query (defaults to document).
5145          * @return {Array}
5146          */
5147         select : function(path, root, type){
5148             if(!root || root == document){
5149                 root = document;
5150             }
5151             if(typeof root == "string"){
5152                 root = document.getElementById(root);
5153             }
5154             var paths = path.split(",");
5155             var results = [];
5156             for(var i = 0, len = paths.length; i < len; i++){
5157                 var p = paths[i].replace(trimRe, "");
5158                 if(!cache[p]){
5159                     cache[p] = Roo.DomQuery.compile(p);
5160                     if(!cache[p]){
5161                         throw p + " is not a valid selector";
5162                     }
5163                 }
5164                 var result = cache[p](root);
5165                 if(result && result != document){
5166                     results = results.concat(result);
5167                 }
5168             }
5169             if(paths.length > 1){
5170                 return nodup(results);
5171             }
5172             return results;
5173         },
5174
5175         /**
5176          * Selects a single element.
5177          * @param {String} selector The selector/xpath query
5178          * @param {Node} root (optional) The start of the query (defaults to document).
5179          * @return {Element}
5180          */
5181         selectNode : function(path, root){
5182             return Roo.DomQuery.select(path, root)[0];
5183         },
5184
5185         /**
5186          * Selects the value of a node, optionally replacing null with the defaultValue.
5187          * @param {String} selector The selector/xpath query
5188          * @param {Node} root (optional) The start of the query (defaults to document).
5189          * @param {String} defaultValue
5190          */
5191         selectValue : function(path, root, defaultValue){
5192             path = path.replace(trimRe, "");
5193             if(!valueCache[path]){
5194                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5195             }
5196             var n = valueCache[path](root);
5197             n = n[0] ? n[0] : n;
5198             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5199             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5200         },
5201
5202         /**
5203          * Selects the value of a node, parsing integers and floats.
5204          * @param {String} selector The selector/xpath query
5205          * @param {Node} root (optional) The start of the query (defaults to document).
5206          * @param {Number} defaultValue
5207          * @return {Number}
5208          */
5209         selectNumber : function(path, root, defaultValue){
5210             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5211             return parseFloat(v);
5212         },
5213
5214         /**
5215          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5216          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5217          * @param {String} selector The simple selector to test
5218          * @return {Boolean}
5219          */
5220         is : function(el, ss){
5221             if(typeof el == "string"){
5222                 el = document.getElementById(el);
5223             }
5224             var isArray = (el instanceof Array);
5225             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5226             return isArray ? (result.length == el.length) : (result.length > 0);
5227         },
5228
5229         /**
5230          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5231          * @param {Array} el An array of elements to filter
5232          * @param {String} selector The simple selector to test
5233          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5234          * the selector instead of the ones that match
5235          * @return {Array}
5236          */
5237         filter : function(els, ss, nonMatches){
5238             ss = ss.replace(trimRe, "");
5239             if(!simpleCache[ss]){
5240                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5241             }
5242             var result = simpleCache[ss](els);
5243             return nonMatches ? quickDiff(result, els) : result;
5244         },
5245
5246         /**
5247          * Collection of matching regular expressions and code snippets.
5248          */
5249         matchers : [{
5250                 re: /^\.([\w-]+)/,
5251                 select: 'n = byClassName(n, null, " {1} ");'
5252             }, {
5253                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5254                 select: 'n = byPseudo(n, "{1}", "{2}");'
5255             },{
5256                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5257                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5258             }, {
5259                 re: /^#([\w-]+)/,
5260                 select: 'n = byId(n, null, "{1}");'
5261             },{
5262                 re: /^@([\w-]+)/,
5263                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5264             }
5265         ],
5266
5267         /**
5268          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5269          * 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;.
5270          */
5271         operators : {
5272             "=" : function(a, v){
5273                 return a == v;
5274             },
5275             "!=" : function(a, v){
5276                 return a != v;
5277             },
5278             "^=" : function(a, v){
5279                 return a && a.substr(0, v.length) == v;
5280             },
5281             "$=" : function(a, v){
5282                 return a && a.substr(a.length-v.length) == v;
5283             },
5284             "*=" : function(a, v){
5285                 return a && a.indexOf(v) !== -1;
5286             },
5287             "%=" : function(a, v){
5288                 return (a % v) == 0;
5289             },
5290             "|=" : function(a, v){
5291                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5292             },
5293             "~=" : function(a, v){
5294                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5295             }
5296         },
5297
5298         /**
5299          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5300          * and the argument (if any) supplied in the selector.
5301          */
5302         pseudos : {
5303             "first-child" : function(c){
5304                 var r = [], ri = -1, n;
5305                 for(var i = 0, ci; ci = n = c[i]; i++){
5306                     while((n = n.previousSibling) && n.nodeType != 1);
5307                     if(!n){
5308                         r[++ri] = ci;
5309                     }
5310                 }
5311                 return r;
5312             },
5313
5314             "last-child" : function(c){
5315                 var r = [], ri = -1, n;
5316                 for(var i = 0, ci; ci = n = c[i]; i++){
5317                     while((n = n.nextSibling) && n.nodeType != 1);
5318                     if(!n){
5319                         r[++ri] = ci;
5320                     }
5321                 }
5322                 return r;
5323             },
5324
5325             "nth-child" : function(c, a) {
5326                 var r = [], ri = -1;
5327                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5328                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5329                 for(var i = 0, n; n = c[i]; i++){
5330                     var pn = n.parentNode;
5331                     if (batch != pn._batch) {
5332                         var j = 0;
5333                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5334                             if(cn.nodeType == 1){
5335                                cn.nodeIndex = ++j;
5336                             }
5337                         }
5338                         pn._batch = batch;
5339                     }
5340                     if (f == 1) {
5341                         if (l == 0 || n.nodeIndex == l){
5342                             r[++ri] = n;
5343                         }
5344                     } else if ((n.nodeIndex + l) % f == 0){
5345                         r[++ri] = n;
5346                     }
5347                 }
5348
5349                 return r;
5350             },
5351
5352             "only-child" : function(c){
5353                 var r = [], ri = -1;;
5354                 for(var i = 0, ci; ci = c[i]; i++){
5355                     if(!prev(ci) && !next(ci)){
5356                         r[++ri] = ci;
5357                     }
5358                 }
5359                 return r;
5360             },
5361
5362             "empty" : function(c){
5363                 var r = [], ri = -1;
5364                 for(var i = 0, ci; ci = c[i]; i++){
5365                     var cns = ci.childNodes, j = 0, cn, empty = true;
5366                     while(cn = cns[j]){
5367                         ++j;
5368                         if(cn.nodeType == 1 || cn.nodeType == 3){
5369                             empty = false;
5370                             break;
5371                         }
5372                     }
5373                     if(empty){
5374                         r[++ri] = ci;
5375                     }
5376                 }
5377                 return r;
5378             },
5379
5380             "contains" : function(c, v){
5381                 var r = [], ri = -1;
5382                 for(var i = 0, ci; ci = c[i]; i++){
5383                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5384                         r[++ri] = ci;
5385                     }
5386                 }
5387                 return r;
5388             },
5389
5390             "nodeValue" : function(c, v){
5391                 var r = [], ri = -1;
5392                 for(var i = 0, ci; ci = c[i]; i++){
5393                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5394                         r[++ri] = ci;
5395                     }
5396                 }
5397                 return r;
5398             },
5399
5400             "checked" : function(c){
5401                 var r = [], ri = -1;
5402                 for(var i = 0, ci; ci = c[i]; i++){
5403                     if(ci.checked == true){
5404                         r[++ri] = ci;
5405                     }
5406                 }
5407                 return r;
5408             },
5409
5410             "not" : function(c, ss){
5411                 return Roo.DomQuery.filter(c, ss, true);
5412             },
5413
5414             "odd" : function(c){
5415                 return this["nth-child"](c, "odd");
5416             },
5417
5418             "even" : function(c){
5419                 return this["nth-child"](c, "even");
5420             },
5421
5422             "nth" : function(c, a){
5423                 return c[a-1] || [];
5424             },
5425
5426             "first" : function(c){
5427                 return c[0] || [];
5428             },
5429
5430             "last" : function(c){
5431                 return c[c.length-1] || [];
5432             },
5433
5434             "has" : function(c, ss){
5435                 var s = Roo.DomQuery.select;
5436                 var r = [], ri = -1;
5437                 for(var i = 0, ci; ci = c[i]; i++){
5438                     if(s(ss, ci).length > 0){
5439                         r[++ri] = ci;
5440                     }
5441                 }
5442                 return r;
5443             },
5444
5445             "next" : function(c, ss){
5446                 var is = Roo.DomQuery.is;
5447                 var r = [], ri = -1;
5448                 for(var i = 0, ci; ci = c[i]; i++){
5449                     var n = next(ci);
5450                     if(n && is(n, ss)){
5451                         r[++ri] = ci;
5452                     }
5453                 }
5454                 return r;
5455             },
5456
5457             "prev" : function(c, ss){
5458                 var is = Roo.DomQuery.is;
5459                 var r = [], ri = -1;
5460                 for(var i = 0, ci; ci = c[i]; i++){
5461                     var n = prev(ci);
5462                     if(n && is(n, ss)){
5463                         r[++ri] = ci;
5464                     }
5465                 }
5466                 return r;
5467             }
5468         }
5469     };
5470 }();
5471
5472 /**
5473  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5474  * @param {String} path The selector/xpath query
5475  * @param {Node} root (optional) The start of the query (defaults to document).
5476  * @return {Array}
5477  * @member Roo
5478  * @method query
5479  */
5480 Roo.query = Roo.DomQuery.select;
5481 /*
5482  * Based on:
5483  * Ext JS Library 1.1.1
5484  * Copyright(c) 2006-2007, Ext JS, LLC.
5485  *
5486  * Originally Released Under LGPL - original licence link has changed is not relivant.
5487  *
5488  * Fork - LGPL
5489  * <script type="text/javascript">
5490  */
5491
5492 /**
5493  * @class Roo.util.Observable
5494  * Base class that provides a common interface for publishing events. Subclasses are expected to
5495  * to have a property "events" with all the events defined.<br>
5496  * For example:
5497  * <pre><code>
5498  Employee = function(name){
5499     this.name = name;
5500     this.addEvents({
5501         "fired" : true,
5502         "quit" : true
5503     });
5504  }
5505  Roo.extend(Employee, Roo.util.Observable);
5506 </code></pre>
5507  * @param {Object} config properties to use (incuding events / listeners)
5508  */
5509
5510 Roo.util.Observable = function(cfg){
5511     
5512     cfg = cfg|| {};
5513     this.addEvents(cfg.events || {});
5514     if (cfg.events) {
5515         delete cfg.events; // make sure
5516     }
5517      
5518     Roo.apply(this, cfg);
5519     
5520     if(this.listeners){
5521         this.on(this.listeners);
5522         delete this.listeners;
5523     }
5524 };
5525 Roo.util.Observable.prototype = {
5526     /** 
5527  * @cfg {Object} listeners  list of events and functions to call for this object, 
5528  * For example :
5529  * <pre><code>
5530     listeners :  { 
5531        'click' : function(e) {
5532            ..... 
5533         } ,
5534         .... 
5535     } 
5536   </code></pre>
5537  */
5538     
5539     
5540     /**
5541      * Fires the specified event with the passed parameters (minus the event name).
5542      * @param {String} eventName
5543      * @param {Object...} args Variable number of parameters are passed to handlers
5544      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5545      */
5546     fireEvent : function(){
5547         var ce = this.events[arguments[0].toLowerCase()];
5548         if(typeof ce == "object"){
5549             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5550         }else{
5551             return true;
5552         }
5553     },
5554
5555     // private
5556     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5557
5558     /**
5559      * Appends an event handler to this component
5560      * @param {String}   eventName The type of event to listen for
5561      * @param {Function} handler The method the event invokes
5562      * @param {Object}   scope (optional) The scope in which to execute the handler
5563      * function. The handler function's "this" context.
5564      * @param {Object}   options (optional) An object containing handler configuration
5565      * properties. This may contain any of the following properties:<ul>
5566      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5567      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5568      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5569      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5570      * by the specified number of milliseconds. If the event fires again within that time, the original
5571      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5572      * </ul><br>
5573      * <p>
5574      * <b>Combining Options</b><br>
5575      * Using the options argument, it is possible to combine different types of listeners:<br>
5576      * <br>
5577      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5578                 <pre><code>
5579                 el.on('click', this.onClick, this, {
5580                         single: true,
5581                 delay: 100,
5582                 forumId: 4
5583                 });
5584                 </code></pre>
5585      * <p>
5586      * <b>Attaching multiple handlers in 1 call</b><br>
5587      * The method also allows for a single argument to be passed which is a config object containing properties
5588      * which specify multiple handlers.
5589      * <pre><code>
5590                 el.on({
5591                         'click': {
5592                         fn: this.onClick,
5593                         scope: this,
5594                         delay: 100
5595                 }, 
5596                 'mouseover': {
5597                         fn: this.onMouseOver,
5598                         scope: this
5599                 },
5600                 'mouseout': {
5601                         fn: this.onMouseOut,
5602                         scope: this
5603                 }
5604                 });
5605                 </code></pre>
5606      * <p>
5607      * Or a shorthand syntax which passes the same scope object to all handlers:
5608         <pre><code>
5609                 el.on({
5610                         'click': this.onClick,
5611                 'mouseover': this.onMouseOver,
5612                 'mouseout': this.onMouseOut,
5613                 scope: this
5614                 });
5615                 </code></pre>
5616      */
5617     addListener : function(eventName, fn, scope, o){
5618         if(typeof eventName == "object"){
5619             o = eventName;
5620             for(var e in o){
5621                 if(this.filterOptRe.test(e)){
5622                     continue;
5623                 }
5624                 if(typeof o[e] == "function"){
5625                     // shared options
5626                     this.addListener(e, o[e], o.scope,  o);
5627                 }else{
5628                     // individual options
5629                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5630                 }
5631             }
5632             return;
5633         }
5634         o = (!o || typeof o == "boolean") ? {} : o;
5635         eventName = eventName.toLowerCase();
5636         var ce = this.events[eventName] || true;
5637         if(typeof ce == "boolean"){
5638             ce = new Roo.util.Event(this, eventName);
5639             this.events[eventName] = ce;
5640         }
5641         ce.addListener(fn, scope, o);
5642     },
5643
5644     /**
5645      * Removes a listener
5646      * @param {String}   eventName     The type of event to listen for
5647      * @param {Function} handler        The handler to remove
5648      * @param {Object}   scope  (optional) The scope (this object) for the handler
5649      */
5650     removeListener : function(eventName, fn, scope){
5651         var ce = this.events[eventName.toLowerCase()];
5652         if(typeof ce == "object"){
5653             ce.removeListener(fn, scope);
5654         }
5655     },
5656
5657     /**
5658      * Removes all listeners for this object
5659      */
5660     purgeListeners : function(){
5661         for(var evt in this.events){
5662             if(typeof this.events[evt] == "object"){
5663                  this.events[evt].clearListeners();
5664             }
5665         }
5666     },
5667
5668     relayEvents : function(o, events){
5669         var createHandler = function(ename){
5670             return function(){
5671                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5672             };
5673         };
5674         for(var i = 0, len = events.length; i < len; i++){
5675             var ename = events[i];
5676             if(!this.events[ename]){ this.events[ename] = true; };
5677             o.on(ename, createHandler(ename), this);
5678         }
5679     },
5680
5681     /**
5682      * Used to define events on this Observable
5683      * @param {Object} object The object with the events defined
5684      */
5685     addEvents : function(o){
5686         if(!this.events){
5687             this.events = {};
5688         }
5689         Roo.applyIf(this.events, o);
5690     },
5691
5692     /**
5693      * Checks to see if this object has any listeners for a specified event
5694      * @param {String} eventName The name of the event to check for
5695      * @return {Boolean} True if the event is being listened for, else false
5696      */
5697     hasListener : function(eventName){
5698         var e = this.events[eventName];
5699         return typeof e == "object" && e.listeners.length > 0;
5700     }
5701 };
5702 /**
5703  * Appends an event handler to this element (shorthand for addListener)
5704  * @param {String}   eventName     The type of event to listen for
5705  * @param {Function} handler        The method the event invokes
5706  * @param {Object}   scope (optional) The scope in which to execute the handler
5707  * function. The handler function's "this" context.
5708  * @param {Object}   options  (optional)
5709  * @method
5710  */
5711 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5712 /**
5713  * Removes a listener (shorthand for removeListener)
5714  * @param {String}   eventName     The type of event to listen for
5715  * @param {Function} handler        The handler to remove
5716  * @param {Object}   scope  (optional) The scope (this object) for the handler
5717  * @method
5718  */
5719 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5720
5721 /**
5722  * Starts capture on the specified Observable. All events will be passed
5723  * to the supplied function with the event name + standard signature of the event
5724  * <b>before</b> the event is fired. If the supplied function returns false,
5725  * the event will not fire.
5726  * @param {Observable} o The Observable to capture
5727  * @param {Function} fn The function to call
5728  * @param {Object} scope (optional) The scope (this object) for the fn
5729  * @static
5730  */
5731 Roo.util.Observable.capture = function(o, fn, scope){
5732     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5733 };
5734
5735 /**
5736  * Removes <b>all</b> added captures from the Observable.
5737  * @param {Observable} o The Observable to release
5738  * @static
5739  */
5740 Roo.util.Observable.releaseCapture = function(o){
5741     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5742 };
5743
5744 (function(){
5745
5746     var createBuffered = function(h, o, scope){
5747         var task = new Roo.util.DelayedTask();
5748         return function(){
5749             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5750         };
5751     };
5752
5753     var createSingle = function(h, e, fn, scope){
5754         return function(){
5755             e.removeListener(fn, scope);
5756             return h.apply(scope, arguments);
5757         };
5758     };
5759
5760     var createDelayed = function(h, o, scope){
5761         return function(){
5762             var args = Array.prototype.slice.call(arguments, 0);
5763             setTimeout(function(){
5764                 h.apply(scope, args);
5765             }, o.delay || 10);
5766         };
5767     };
5768
5769     Roo.util.Event = function(obj, name){
5770         this.name = name;
5771         this.obj = obj;
5772         this.listeners = [];
5773     };
5774
5775     Roo.util.Event.prototype = {
5776         addListener : function(fn, scope, options){
5777             var o = options || {};
5778             scope = scope || this.obj;
5779             if(!this.isListening(fn, scope)){
5780                 var l = {fn: fn, scope: scope, options: o};
5781                 var h = fn;
5782                 if(o.delay){
5783                     h = createDelayed(h, o, scope);
5784                 }
5785                 if(o.single){
5786                     h = createSingle(h, this, fn, scope);
5787                 }
5788                 if(o.buffer){
5789                     h = createBuffered(h, o, scope);
5790                 }
5791                 l.fireFn = h;
5792                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5793                     this.listeners.push(l);
5794                 }else{
5795                     this.listeners = this.listeners.slice(0);
5796                     this.listeners.push(l);
5797                 }
5798             }
5799         },
5800
5801         findListener : function(fn, scope){
5802             scope = scope || this.obj;
5803             var ls = this.listeners;
5804             for(var i = 0, len = ls.length; i < len; i++){
5805                 var l = ls[i];
5806                 if(l.fn == fn && l.scope == scope){
5807                     return i;
5808                 }
5809             }
5810             return -1;
5811         },
5812
5813         isListening : function(fn, scope){
5814             return this.findListener(fn, scope) != -1;
5815         },
5816
5817         removeListener : function(fn, scope){
5818             var index;
5819             if((index = this.findListener(fn, scope)) != -1){
5820                 if(!this.firing){
5821                     this.listeners.splice(index, 1);
5822                 }else{
5823                     this.listeners = this.listeners.slice(0);
5824                     this.listeners.splice(index, 1);
5825                 }
5826                 return true;
5827             }
5828             return false;
5829         },
5830
5831         clearListeners : function(){
5832             this.listeners = [];
5833         },
5834
5835         fire : function(){
5836             var ls = this.listeners, scope, len = ls.length;
5837             if(len > 0){
5838                 this.firing = true;
5839                 var args = Array.prototype.slice.call(arguments, 0);
5840                 for(var i = 0; i < len; i++){
5841                     var l = ls[i];
5842                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5843                         this.firing = false;
5844                         return false;
5845                     }
5846                 }
5847                 this.firing = false;
5848             }
5849             return true;
5850         }
5851     };
5852 })();/*
5853  * Based on:
5854  * Ext JS Library 1.1.1
5855  * Copyright(c) 2006-2007, Ext JS, LLC.
5856  *
5857  * Originally Released Under LGPL - original licence link has changed is not relivant.
5858  *
5859  * Fork - LGPL
5860  * <script type="text/javascript">
5861  */
5862
5863 /**
5864  * @class Roo.EventManager
5865  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5866  * several useful events directly.
5867  * See {@link Roo.EventObject} for more details on normalized event objects.
5868  * @singleton
5869  */
5870 Roo.EventManager = function(){
5871     var docReadyEvent, docReadyProcId, docReadyState = false;
5872     var resizeEvent, resizeTask, textEvent, textSize;
5873     var E = Roo.lib.Event;
5874     var D = Roo.lib.Dom;
5875
5876
5877     var fireDocReady = function(){
5878         if(!docReadyState){
5879             docReadyState = true;
5880             Roo.isReady = true;
5881             if(docReadyProcId){
5882                 clearInterval(docReadyProcId);
5883             }
5884             if(Roo.isGecko || Roo.isOpera) {
5885                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5886             }
5887             if(Roo.isIE){
5888                 var defer = document.getElementById("ie-deferred-loader");
5889                 if(defer){
5890                     defer.onreadystatechange = null;
5891                     defer.parentNode.removeChild(defer);
5892                 }
5893             }
5894             if(docReadyEvent){
5895                 docReadyEvent.fire();
5896                 docReadyEvent.clearListeners();
5897             }
5898         }
5899     };
5900     
5901     var initDocReady = function(){
5902         docReadyEvent = new Roo.util.Event();
5903         if(Roo.isGecko || Roo.isOpera) {
5904             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5905         }else if(Roo.isIE){
5906             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5907             var defer = document.getElementById("ie-deferred-loader");
5908             defer.onreadystatechange = function(){
5909                 if(this.readyState == "complete"){
5910                     fireDocReady();
5911                 }
5912             };
5913         }else if(Roo.isSafari){ 
5914             docReadyProcId = setInterval(function(){
5915                 var rs = document.readyState;
5916                 if(rs == "complete") {
5917                     fireDocReady();     
5918                  }
5919             }, 10);
5920         }
5921         // no matter what, make sure it fires on load
5922         E.on(window, "load", fireDocReady);
5923     };
5924
5925     var createBuffered = function(h, o){
5926         var task = new Roo.util.DelayedTask(h);
5927         return function(e){
5928             // create new event object impl so new events don't wipe out properties
5929             e = new Roo.EventObjectImpl(e);
5930             task.delay(o.buffer, h, null, [e]);
5931         };
5932     };
5933
5934     var createSingle = function(h, el, ename, fn){
5935         return function(e){
5936             Roo.EventManager.removeListener(el, ename, fn);
5937             h(e);
5938         };
5939     };
5940
5941     var createDelayed = function(h, o){
5942         return function(e){
5943             // create new event object impl so new events don't wipe out properties
5944             e = new Roo.EventObjectImpl(e);
5945             setTimeout(function(){
5946                 h(e);
5947             }, o.delay || 10);
5948         };
5949     };
5950
5951     var listen = function(element, ename, opt, fn, scope){
5952         var o = (!opt || typeof opt == "boolean") ? {} : opt;
5953         fn = fn || o.fn; scope = scope || o.scope;
5954         var el = Roo.getDom(element);
5955         if(!el){
5956             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5957         }
5958         var h = function(e){
5959             e = Roo.EventObject.setEvent(e);
5960             var t;
5961             if(o.delegate){
5962                 t = e.getTarget(o.delegate, el);
5963                 if(!t){
5964                     return;
5965                 }
5966             }else{
5967                 t = e.target;
5968             }
5969             if(o.stopEvent === true){
5970                 e.stopEvent();
5971             }
5972             if(o.preventDefault === true){
5973                e.preventDefault();
5974             }
5975             if(o.stopPropagation === true){
5976                 e.stopPropagation();
5977             }
5978
5979             if(o.normalized === false){
5980                 e = e.browserEvent;
5981             }
5982
5983             fn.call(scope || el, e, t, o);
5984         };
5985         if(o.delay){
5986             h = createDelayed(h, o);
5987         }
5988         if(o.single){
5989             h = createSingle(h, el, ename, fn);
5990         }
5991         if(o.buffer){
5992             h = createBuffered(h, o);
5993         }
5994         fn._handlers = fn._handlers || [];
5995         fn._handlers.push([Roo.id(el), ename, h]);
5996
5997         E.on(el, ename, h);
5998         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5999             el.addEventListener("DOMMouseScroll", h, false);
6000             E.on(window, 'unload', function(){
6001                 el.removeEventListener("DOMMouseScroll", h, false);
6002             });
6003         }
6004         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6005             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6006         }
6007         return h;
6008     };
6009
6010     var stopListening = function(el, ename, fn){
6011         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6012         if(hds){
6013             for(var i = 0, len = hds.length; i < len; i++){
6014                 var h = hds[i];
6015                 if(h[0] == id && h[1] == ename){
6016                     hd = h[2];
6017                     hds.splice(i, 1);
6018                     break;
6019                 }
6020             }
6021         }
6022         E.un(el, ename, hd);
6023         el = Roo.getDom(el);
6024         if(ename == "mousewheel" && el.addEventListener){
6025             el.removeEventListener("DOMMouseScroll", hd, false);
6026         }
6027         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6028             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6029         }
6030     };
6031
6032     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6033     
6034     var pub = {
6035         
6036         
6037         /** 
6038          * Fix for doc tools
6039          * @scope Roo.EventManager
6040          */
6041         
6042         
6043         /** 
6044          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6045          * object with a Roo.EventObject
6046          * @param {Function} fn        The method the event invokes
6047          * @param {Object}   scope    An object that becomes the scope of the handler
6048          * @param {boolean}  override If true, the obj passed in becomes
6049          *                             the execution scope of the listener
6050          * @return {Function} The wrapped function
6051          * @deprecated
6052          */
6053         wrap : function(fn, scope, override){
6054             return function(e){
6055                 Roo.EventObject.setEvent(e);
6056                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6057             };
6058         },
6059         
6060         /**
6061      * Appends an event handler to an element (shorthand for addListener)
6062      * @param {String/HTMLElement}   element        The html element or id to assign the
6063      * @param {String}   eventName The type of event to listen for
6064      * @param {Function} handler The method the event invokes
6065      * @param {Object}   scope (optional) The scope in which to execute the handler
6066      * function. The handler function's "this" context.
6067      * @param {Object}   options (optional) An object containing handler configuration
6068      * properties. This may contain any of the following properties:<ul>
6069      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6070      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6071      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6072      * <li>preventDefault {Boolean} True to prevent the default action</li>
6073      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6074      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6075      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6076      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6077      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6078      * by the specified number of milliseconds. If the event fires again within that time, the original
6079      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6080      * </ul><br>
6081      * <p>
6082      * <b>Combining Options</b><br>
6083      * Using the options argument, it is possible to combine different types of listeners:<br>
6084      * <br>
6085      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6086      * Code:<pre><code>
6087 el.on('click', this.onClick, this, {
6088     single: true,
6089     delay: 100,
6090     stopEvent : true,
6091     forumId: 4
6092 });</code></pre>
6093      * <p>
6094      * <b>Attaching multiple handlers in 1 call</b><br>
6095       * The method also allows for a single argument to be passed which is a config object containing properties
6096      * which specify multiple handlers.
6097      * <p>
6098      * Code:<pre><code>
6099 el.on({
6100     'click' : {
6101         fn: this.onClick
6102         scope: this,
6103         delay: 100
6104     },
6105     'mouseover' : {
6106         fn: this.onMouseOver
6107         scope: this
6108     },
6109     'mouseout' : {
6110         fn: this.onMouseOut
6111         scope: this
6112     }
6113 });</code></pre>
6114      * <p>
6115      * Or a shorthand syntax:<br>
6116      * Code:<pre><code>
6117 el.on({
6118     'click' : this.onClick,
6119     'mouseover' : this.onMouseOver,
6120     'mouseout' : this.onMouseOut
6121     scope: this
6122 });</code></pre>
6123      */
6124         addListener : function(element, eventName, fn, scope, options){
6125             if(typeof eventName == "object"){
6126                 var o = eventName;
6127                 for(var e in o){
6128                     if(propRe.test(e)){
6129                         continue;
6130                     }
6131                     if(typeof o[e] == "function"){
6132                         // shared options
6133                         listen(element, e, o, o[e], o.scope);
6134                     }else{
6135                         // individual options
6136                         listen(element, e, o[e]);
6137                     }
6138                 }
6139                 return;
6140             }
6141             return listen(element, eventName, options, fn, scope);
6142         },
6143         
6144         /**
6145          * Removes an event handler
6146          *
6147          * @param {String/HTMLElement}   element        The id or html element to remove the 
6148          *                             event from
6149          * @param {String}   eventName     The type of event
6150          * @param {Function} fn
6151          * @return {Boolean} True if a listener was actually removed
6152          */
6153         removeListener : function(element, eventName, fn){
6154             return stopListening(element, eventName, fn);
6155         },
6156         
6157         /**
6158          * Fires when the document is ready (before onload and before images are loaded). Can be 
6159          * accessed shorthanded Roo.onReady().
6160          * @param {Function} fn        The method the event invokes
6161          * @param {Object}   scope    An  object that becomes the scope of the handler
6162          * @param {boolean}  options
6163          */
6164         onDocumentReady : function(fn, scope, options){
6165             if(docReadyState){ // if it already fired
6166                 docReadyEvent.addListener(fn, scope, options);
6167                 docReadyEvent.fire();
6168                 docReadyEvent.clearListeners();
6169                 return;
6170             }
6171             if(!docReadyEvent){
6172                 initDocReady();
6173             }
6174             docReadyEvent.addListener(fn, scope, options);
6175         },
6176         
6177         /**
6178          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6179          * @param {Function} fn        The method the event invokes
6180          * @param {Object}   scope    An object that becomes the scope of the handler
6181          * @param {boolean}  options
6182          */
6183         onWindowResize : function(fn, scope, options){
6184             if(!resizeEvent){
6185                 resizeEvent = new Roo.util.Event();
6186                 resizeTask = new Roo.util.DelayedTask(function(){
6187                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6188                 });
6189                 E.on(window, "resize", function(){
6190                     if(Roo.isIE){
6191                         resizeTask.delay(50);
6192                     }else{
6193                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6194                     }
6195                 });
6196             }
6197             resizeEvent.addListener(fn, scope, options);
6198         },
6199
6200         /**
6201          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6202          * @param {Function} fn        The method the event invokes
6203          * @param {Object}   scope    An object that becomes the scope of the handler
6204          * @param {boolean}  options
6205          */
6206         onTextResize : function(fn, scope, options){
6207             if(!textEvent){
6208                 textEvent = new Roo.util.Event();
6209                 var textEl = new Roo.Element(document.createElement('div'));
6210                 textEl.dom.className = 'x-text-resize';
6211                 textEl.dom.innerHTML = 'X';
6212                 textEl.appendTo(document.body);
6213                 textSize = textEl.dom.offsetHeight;
6214                 setInterval(function(){
6215                     if(textEl.dom.offsetHeight != textSize){
6216                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6217                     }
6218                 }, this.textResizeInterval);
6219             }
6220             textEvent.addListener(fn, scope, options);
6221         },
6222
6223         /**
6224          * Removes the passed window resize listener.
6225          * @param {Function} fn        The method the event invokes
6226          * @param {Object}   scope    The scope of handler
6227          */
6228         removeResizeListener : function(fn, scope){
6229             if(resizeEvent){
6230                 resizeEvent.removeListener(fn, scope);
6231             }
6232         },
6233
6234         // private
6235         fireResize : function(){
6236             if(resizeEvent){
6237                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6238             }   
6239         },
6240         /**
6241          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6242          */
6243         ieDeferSrc : false,
6244         /**
6245          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6246          */
6247         textResizeInterval : 50
6248     };
6249     
6250     /**
6251      * Fix for doc tools
6252      * @scopeAlias pub=Roo.EventManager
6253      */
6254     
6255      /**
6256      * Appends an event handler to an element (shorthand for addListener)
6257      * @param {String/HTMLElement}   element        The html element or id to assign the
6258      * @param {String}   eventName The type of event to listen for
6259      * @param {Function} handler The method the event invokes
6260      * @param {Object}   scope (optional) The scope in which to execute the handler
6261      * function. The handler function's "this" context.
6262      * @param {Object}   options (optional) An object containing handler configuration
6263      * properties. This may contain any of the following properties:<ul>
6264      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6265      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6266      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6267      * <li>preventDefault {Boolean} True to prevent the default action</li>
6268      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6269      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6270      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6271      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6272      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6273      * by the specified number of milliseconds. If the event fires again within that time, the original
6274      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6275      * </ul><br>
6276      * <p>
6277      * <b>Combining Options</b><br>
6278      * Using the options argument, it is possible to combine different types of listeners:<br>
6279      * <br>
6280      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6281      * Code:<pre><code>
6282 el.on('click', this.onClick, this, {
6283     single: true,
6284     delay: 100,
6285     stopEvent : true,
6286     forumId: 4
6287 });</code></pre>
6288      * <p>
6289      * <b>Attaching multiple handlers in 1 call</b><br>
6290       * The method also allows for a single argument to be passed which is a config object containing properties
6291      * which specify multiple handlers.
6292      * <p>
6293      * Code:<pre><code>
6294 el.on({
6295     'click' : {
6296         fn: this.onClick
6297         scope: this,
6298         delay: 100
6299     },
6300     'mouseover' : {
6301         fn: this.onMouseOver
6302         scope: this
6303     },
6304     'mouseout' : {
6305         fn: this.onMouseOut
6306         scope: this
6307     }
6308 });</code></pre>
6309      * <p>
6310      * Or a shorthand syntax:<br>
6311      * Code:<pre><code>
6312 el.on({
6313     'click' : this.onClick,
6314     'mouseover' : this.onMouseOver,
6315     'mouseout' : this.onMouseOut
6316     scope: this
6317 });</code></pre>
6318      */
6319     pub.on = pub.addListener;
6320     pub.un = pub.removeListener;
6321
6322     pub.stoppedMouseDownEvent = new Roo.util.Event();
6323     return pub;
6324 }();
6325 /**
6326   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6327   * @param {Function} fn        The method the event invokes
6328   * @param {Object}   scope    An  object that becomes the scope of the handler
6329   * @param {boolean}  override If true, the obj passed in becomes
6330   *                             the execution scope of the listener
6331   * @member Roo
6332   * @method onReady
6333  */
6334 Roo.onReady = Roo.EventManager.onDocumentReady;
6335
6336 Roo.onReady(function(){
6337     var bd = Roo.get(document.body);
6338     if(!bd){ return; }
6339
6340     var cls = [
6341             Roo.isIE ? "roo-ie"
6342             : Roo.isGecko ? "roo-gecko"
6343             : Roo.isOpera ? "roo-opera"
6344             : Roo.isSafari ? "roo-safari" : ""];
6345
6346     if(Roo.isMac){
6347         cls.push("roo-mac");
6348     }
6349     if(Roo.isLinux){
6350         cls.push("roo-linux");
6351     }
6352     if(Roo.isBorderBox){
6353         cls.push('roo-border-box');
6354     }
6355     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6356         var p = bd.dom.parentNode;
6357         if(p){
6358             p.className += ' roo-strict';
6359         }
6360     }
6361     bd.addClass(cls.join(' '));
6362 });
6363
6364 /**
6365  * @class Roo.EventObject
6366  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6367  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6368  * Example:
6369  * <pre><code>
6370  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6371     e.preventDefault();
6372     var target = e.getTarget();
6373     ...
6374  }
6375  var myDiv = Roo.get("myDiv");
6376  myDiv.on("click", handleClick);
6377  //or
6378  Roo.EventManager.on("myDiv", 'click', handleClick);
6379  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6380  </code></pre>
6381  * @singleton
6382  */
6383 Roo.EventObject = function(){
6384     
6385     var E = Roo.lib.Event;
6386     
6387     // safari keypress events for special keys return bad keycodes
6388     var safariKeys = {
6389         63234 : 37, // left
6390         63235 : 39, // right
6391         63232 : 38, // up
6392         63233 : 40, // down
6393         63276 : 33, // page up
6394         63277 : 34, // page down
6395         63272 : 46, // delete
6396         63273 : 36, // home
6397         63275 : 35  // end
6398     };
6399
6400     // normalize button clicks
6401     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6402                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6403
6404     Roo.EventObjectImpl = function(e){
6405         if(e){
6406             this.setEvent(e.browserEvent || e);
6407         }
6408     };
6409     Roo.EventObjectImpl.prototype = {
6410         /**
6411          * Used to fix doc tools.
6412          * @scope Roo.EventObject.prototype
6413          */
6414             
6415
6416         
6417         
6418         /** The normal browser event */
6419         browserEvent : null,
6420         /** The button pressed in a mouse event */
6421         button : -1,
6422         /** True if the shift key was down during the event */
6423         shiftKey : false,
6424         /** True if the control key was down during the event */
6425         ctrlKey : false,
6426         /** True if the alt key was down during the event */
6427         altKey : false,
6428
6429         /** Key constant 
6430         * @type Number */
6431         BACKSPACE : 8,
6432         /** Key constant 
6433         * @type Number */
6434         TAB : 9,
6435         /** Key constant 
6436         * @type Number */
6437         RETURN : 13,
6438         /** Key constant 
6439         * @type Number */
6440         ENTER : 13,
6441         /** Key constant 
6442         * @type Number */
6443         SHIFT : 16,
6444         /** Key constant 
6445         * @type Number */
6446         CONTROL : 17,
6447         /** Key constant 
6448         * @type Number */
6449         ESC : 27,
6450         /** Key constant 
6451         * @type Number */
6452         SPACE : 32,
6453         /** Key constant 
6454         * @type Number */
6455         PAGEUP : 33,
6456         /** Key constant 
6457         * @type Number */
6458         PAGEDOWN : 34,
6459         /** Key constant 
6460         * @type Number */
6461         END : 35,
6462         /** Key constant 
6463         * @type Number */
6464         HOME : 36,
6465         /** Key constant 
6466         * @type Number */
6467         LEFT : 37,
6468         /** Key constant 
6469         * @type Number */
6470         UP : 38,
6471         /** Key constant 
6472         * @type Number */
6473         RIGHT : 39,
6474         /** Key constant 
6475         * @type Number */
6476         DOWN : 40,
6477         /** Key constant 
6478         * @type Number */
6479         DELETE : 46,
6480         /** Key constant 
6481         * @type Number */
6482         F5 : 116,
6483
6484            /** @private */
6485         setEvent : function(e){
6486             if(e == this || (e && e.browserEvent)){ // already wrapped
6487                 return e;
6488             }
6489             this.browserEvent = e;
6490             if(e){
6491                 // normalize buttons
6492                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6493                 if(e.type == 'click' && this.button == -1){
6494                     this.button = 0;
6495                 }
6496                 this.type = e.type;
6497                 this.shiftKey = e.shiftKey;
6498                 // mac metaKey behaves like ctrlKey
6499                 this.ctrlKey = e.ctrlKey || e.metaKey;
6500                 this.altKey = e.altKey;
6501                 // in getKey these will be normalized for the mac
6502                 this.keyCode = e.keyCode;
6503                 // keyup warnings on firefox.
6504                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6505                 // cache the target for the delayed and or buffered events
6506                 this.target = E.getTarget(e);
6507                 // same for XY
6508                 this.xy = E.getXY(e);
6509             }else{
6510                 this.button = -1;
6511                 this.shiftKey = false;
6512                 this.ctrlKey = false;
6513                 this.altKey = false;
6514                 this.keyCode = 0;
6515                 this.charCode =0;
6516                 this.target = null;
6517                 this.xy = [0, 0];
6518             }
6519             return this;
6520         },
6521
6522         /**
6523          * Stop the event (preventDefault and stopPropagation)
6524          */
6525         stopEvent : function(){
6526             if(this.browserEvent){
6527                 if(this.browserEvent.type == 'mousedown'){
6528                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6529                 }
6530                 E.stopEvent(this.browserEvent);
6531             }
6532         },
6533
6534         /**
6535          * Prevents the browsers default handling of the event.
6536          */
6537         preventDefault : function(){
6538             if(this.browserEvent){
6539                 E.preventDefault(this.browserEvent);
6540             }
6541         },
6542
6543         /** @private */
6544         isNavKeyPress : function(){
6545             var k = this.keyCode;
6546             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6547             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6548         },
6549
6550         isSpecialKey : function(){
6551             var k = this.keyCode;
6552             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6553             (k == 16) || (k == 17) ||
6554             (k >= 18 && k <= 20) ||
6555             (k >= 33 && k <= 35) ||
6556             (k >= 36 && k <= 39) ||
6557             (k >= 44 && k <= 45);
6558         },
6559         /**
6560          * Cancels bubbling of the event.
6561          */
6562         stopPropagation : function(){
6563             if(this.browserEvent){
6564                 if(this.type == 'mousedown'){
6565                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6566                 }
6567                 E.stopPropagation(this.browserEvent);
6568             }
6569         },
6570
6571         /**
6572          * Gets the key code for the event.
6573          * @return {Number}
6574          */
6575         getCharCode : function(){
6576             return this.charCode || this.keyCode;
6577         },
6578
6579         /**
6580          * Returns a normalized keyCode for the event.
6581          * @return {Number} The key code
6582          */
6583         getKey : function(){
6584             var k = this.keyCode || this.charCode;
6585             return Roo.isSafari ? (safariKeys[k] || k) : k;
6586         },
6587
6588         /**
6589          * Gets the x coordinate of the event.
6590          * @return {Number}
6591          */
6592         getPageX : function(){
6593             return this.xy[0];
6594         },
6595
6596         /**
6597          * Gets the y coordinate of the event.
6598          * @return {Number}
6599          */
6600         getPageY : function(){
6601             return this.xy[1];
6602         },
6603
6604         /**
6605          * Gets the time of the event.
6606          * @return {Number}
6607          */
6608         getTime : function(){
6609             if(this.browserEvent){
6610                 return E.getTime(this.browserEvent);
6611             }
6612             return null;
6613         },
6614
6615         /**
6616          * Gets the page coordinates of the event.
6617          * @return {Array} The xy values like [x, y]
6618          */
6619         getXY : function(){
6620             return this.xy;
6621         },
6622
6623         /**
6624          * Gets the target for the event.
6625          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6626          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6627                 search as a number or element (defaults to 10 || document.body)
6628          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6629          * @return {HTMLelement}
6630          */
6631         getTarget : function(selector, maxDepth, returnEl){
6632             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6633         },
6634         /**
6635          * Gets the related target.
6636          * @return {HTMLElement}
6637          */
6638         getRelatedTarget : function(){
6639             if(this.browserEvent){
6640                 return E.getRelatedTarget(this.browserEvent);
6641             }
6642             return null;
6643         },
6644
6645         /**
6646          * Normalizes mouse wheel delta across browsers
6647          * @return {Number} The delta
6648          */
6649         getWheelDelta : function(){
6650             var e = this.browserEvent;
6651             var delta = 0;
6652             if(e.wheelDelta){ /* IE/Opera. */
6653                 delta = e.wheelDelta/120;
6654             }else if(e.detail){ /* Mozilla case. */
6655                 delta = -e.detail/3;
6656             }
6657             return delta;
6658         },
6659
6660         /**
6661          * Returns true if the control, meta, shift or alt key was pressed during this event.
6662          * @return {Boolean}
6663          */
6664         hasModifier : function(){
6665             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6666         },
6667
6668         /**
6669          * Returns true if the target of this event equals el or is a child of el
6670          * @param {String/HTMLElement/Element} el
6671          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6672          * @return {Boolean}
6673          */
6674         within : function(el, related){
6675             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6676             return t && Roo.fly(el).contains(t);
6677         },
6678
6679         getPoint : function(){
6680             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6681         }
6682     };
6683
6684     return new Roo.EventObjectImpl();
6685 }();
6686             
6687     /*
6688  * Based on:
6689  * Ext JS Library 1.1.1
6690  * Copyright(c) 2006-2007, Ext JS, LLC.
6691  *
6692  * Originally Released Under LGPL - original licence link has changed is not relivant.
6693  *
6694  * Fork - LGPL
6695  * <script type="text/javascript">
6696  */
6697
6698  
6699 // was in Composite Element!??!?!
6700  
6701 (function(){
6702     var D = Roo.lib.Dom;
6703     var E = Roo.lib.Event;
6704     var A = Roo.lib.Anim;
6705
6706     // local style camelizing for speed
6707     var propCache = {};
6708     var camelRe = /(-[a-z])/gi;
6709     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6710     var view = document.defaultView;
6711
6712 /**
6713  * @class Roo.Element
6714  * Represents an Element in the DOM.<br><br>
6715  * Usage:<br>
6716 <pre><code>
6717 var el = Roo.get("my-div");
6718
6719 // or with getEl
6720 var el = getEl("my-div");
6721
6722 // or with a DOM element
6723 var el = Roo.get(myDivElement);
6724 </code></pre>
6725  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6726  * each call instead of constructing a new one.<br><br>
6727  * <b>Animations</b><br />
6728  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6729  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6730 <pre>
6731 Option    Default   Description
6732 --------- --------  ---------------------------------------------
6733 duration  .35       The duration of the animation in seconds
6734 easing    easeOut   The YUI easing method
6735 callback  none      A function to execute when the anim completes
6736 scope     this      The scope (this) of the callback function
6737 </pre>
6738 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6739 * manipulate the animation. Here's an example:
6740 <pre><code>
6741 var el = Roo.get("my-div");
6742
6743 // no animation
6744 el.setWidth(100);
6745
6746 // default animation
6747 el.setWidth(100, true);
6748
6749 // animation with some options set
6750 el.setWidth(100, {
6751     duration: 1,
6752     callback: this.foo,
6753     scope: this
6754 });
6755
6756 // using the "anim" property to get the Anim object
6757 var opt = {
6758     duration: 1,
6759     callback: this.foo,
6760     scope: this
6761 };
6762 el.setWidth(100, opt);
6763 ...
6764 if(opt.anim.isAnimated()){
6765     opt.anim.stop();
6766 }
6767 </code></pre>
6768 * <b> Composite (Collections of) Elements</b><br />
6769  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6770  * @constructor Create a new Element directly.
6771  * @param {String/HTMLElement} element
6772  * @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).
6773  */
6774     Roo.Element = function(element, forceNew){
6775         var dom = typeof element == "string" ?
6776                 document.getElementById(element) : element;
6777         if(!dom){ // invalid id/element
6778             return null;
6779         }
6780         var id = dom.id;
6781         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6782             return Roo.Element.cache[id];
6783         }
6784
6785         /**
6786          * The DOM element
6787          * @type HTMLElement
6788          */
6789         this.dom = dom;
6790
6791         /**
6792          * The DOM element ID
6793          * @type String
6794          */
6795         this.id = id || Roo.id(dom);
6796     };
6797
6798     var El = Roo.Element;
6799
6800     El.prototype = {
6801         /**
6802          * The element's default display mode  (defaults to "")
6803          * @type String
6804          */
6805         originalDisplay : "",
6806
6807         visibilityMode : 1,
6808         /**
6809          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6810          * @type String
6811          */
6812         defaultUnit : "px",
6813         /**
6814          * Sets the element's visibility mode. When setVisible() is called it
6815          * will use this to determine whether to set the visibility or the display property.
6816          * @param visMode Element.VISIBILITY or Element.DISPLAY
6817          * @return {Roo.Element} this
6818          */
6819         setVisibilityMode : function(visMode){
6820             this.visibilityMode = visMode;
6821             return this;
6822         },
6823         /**
6824          * Convenience method for setVisibilityMode(Element.DISPLAY)
6825          * @param {String} display (optional) What to set display to when visible
6826          * @return {Roo.Element} this
6827          */
6828         enableDisplayMode : function(display){
6829             this.setVisibilityMode(El.DISPLAY);
6830             if(typeof display != "undefined") this.originalDisplay = display;
6831             return this;
6832         },
6833
6834         /**
6835          * 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)
6836          * @param {String} selector The simple selector to test
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} The matching DOM node (or null if no match was found)
6841          */
6842         findParent : function(simpleSelector, maxDepth, returnEl){
6843             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6844             maxDepth = maxDepth || 50;
6845             if(typeof maxDepth != "number"){
6846                 stopEl = Roo.getDom(maxDepth);
6847                 maxDepth = 10;
6848             }
6849             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6850                 if(dq.is(p, simpleSelector)){
6851                     return returnEl ? Roo.get(p) : p;
6852                 }
6853                 depth++;
6854                 p = p.parentNode;
6855             }
6856             return null;
6857         },
6858
6859
6860         /**
6861          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6862          * @param {String} selector The simple selector to test
6863          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6864                 search as a number or element (defaults to 10 || document.body)
6865          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6866          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6867          */
6868         findParentNode : function(simpleSelector, maxDepth, returnEl){
6869             var p = Roo.fly(this.dom.parentNode, '_internal');
6870             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6871         },
6872
6873         /**
6874          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6875          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6876          * @param {String} selector The simple selector to test
6877          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6878                 search as a number or element (defaults to 10 || document.body)
6879          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6880          */
6881         up : function(simpleSelector, maxDepth){
6882             return this.findParentNode(simpleSelector, maxDepth, true);
6883         },
6884
6885
6886
6887         /**
6888          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6889          * @param {String} selector The simple selector to test
6890          * @return {Boolean} True if this element matches the selector, else false
6891          */
6892         is : function(simpleSelector){
6893             return Roo.DomQuery.is(this.dom, simpleSelector);
6894         },
6895
6896         /**
6897          * Perform animation on this element.
6898          * @param {Object} args The YUI animation control args
6899          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6900          * @param {Function} onComplete (optional) Function to call when animation completes
6901          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6902          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6903          * @return {Roo.Element} this
6904          */
6905         animate : function(args, duration, onComplete, easing, animType){
6906             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6907             return this;
6908         },
6909
6910         /*
6911          * @private Internal animation call
6912          */
6913         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6914             animType = animType || 'run';
6915             opt = opt || {};
6916             var anim = Roo.lib.Anim[animType](
6917                 this.dom, args,
6918                 (opt.duration || defaultDur) || .35,
6919                 (opt.easing || defaultEase) || 'easeOut',
6920                 function(){
6921                     Roo.callback(cb, this);
6922                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6923                 },
6924                 this
6925             );
6926             opt.anim = anim;
6927             return anim;
6928         },
6929
6930         // private legacy anim prep
6931         preanim : function(a, i){
6932             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6933         },
6934
6935         /**
6936          * Removes worthless text nodes
6937          * @param {Boolean} forceReclean (optional) By default the element
6938          * keeps track if it has been cleaned already so
6939          * you can call this over and over. However, if you update the element and
6940          * need to force a reclean, you can pass true.
6941          */
6942         clean : function(forceReclean){
6943             if(this.isCleaned && forceReclean !== true){
6944                 return this;
6945             }
6946             var ns = /\S/;
6947             var d = this.dom, n = d.firstChild, ni = -1;
6948             while(n){
6949                 var nx = n.nextSibling;
6950                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6951                     d.removeChild(n);
6952                 }else{
6953                     n.nodeIndex = ++ni;
6954                 }
6955                 n = nx;
6956             }
6957             this.isCleaned = true;
6958             return this;
6959         },
6960
6961         // private
6962         calcOffsetsTo : function(el){
6963             el = Roo.get(el);
6964             var d = el.dom;
6965             var restorePos = false;
6966             if(el.getStyle('position') == 'static'){
6967                 el.position('relative');
6968                 restorePos = true;
6969             }
6970             var x = 0, y =0;
6971             var op = this.dom;
6972             while(op && op != d && op.tagName != 'HTML'){
6973                 x+= op.offsetLeft;
6974                 y+= op.offsetTop;
6975                 op = op.offsetParent;
6976             }
6977             if(restorePos){
6978                 el.position('static');
6979             }
6980             return [x, y];
6981         },
6982
6983         /**
6984          * Scrolls this element into view within the passed container.
6985          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6986          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6987          * @return {Roo.Element} this
6988          */
6989         scrollIntoView : function(container, hscroll){
6990             var c = Roo.getDom(container) || document.body;
6991             var el = this.dom;
6992
6993             var o = this.calcOffsetsTo(c),
6994                 l = o[0],
6995                 t = o[1],
6996                 b = t+el.offsetHeight,
6997                 r = l+el.offsetWidth;
6998
6999             var ch = c.clientHeight;
7000             var ct = parseInt(c.scrollTop, 10);
7001             var cl = parseInt(c.scrollLeft, 10);
7002             var cb = ct + ch;
7003             var cr = cl + c.clientWidth;
7004
7005             if(t < ct){
7006                 c.scrollTop = t;
7007             }else if(b > cb){
7008                 c.scrollTop = b-ch;
7009             }
7010
7011             if(hscroll !== false){
7012                 if(l < cl){
7013                     c.scrollLeft = l;
7014                 }else if(r > cr){
7015                     c.scrollLeft = r-c.clientWidth;
7016                 }
7017             }
7018             return this;
7019         },
7020
7021         // private
7022         scrollChildIntoView : function(child, hscroll){
7023             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7024         },
7025
7026         /**
7027          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7028          * the new height may not be available immediately.
7029          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7030          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7031          * @param {Function} onComplete (optional) Function to call when animation completes
7032          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7033          * @return {Roo.Element} this
7034          */
7035         autoHeight : function(animate, duration, onComplete, easing){
7036             var oldHeight = this.getHeight();
7037             this.clip();
7038             this.setHeight(1); // force clipping
7039             setTimeout(function(){
7040                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7041                 if(!animate){
7042                     this.setHeight(height);
7043                     this.unclip();
7044                     if(typeof onComplete == "function"){
7045                         onComplete();
7046                     }
7047                 }else{
7048                     this.setHeight(oldHeight); // restore original height
7049                     this.setHeight(height, animate, duration, function(){
7050                         this.unclip();
7051                         if(typeof onComplete == "function") onComplete();
7052                     }.createDelegate(this), easing);
7053                 }
7054             }.createDelegate(this), 0);
7055             return this;
7056         },
7057
7058         /**
7059          * Returns true if this element is an ancestor of the passed element
7060          * @param {HTMLElement/String} el The element to check
7061          * @return {Boolean} True if this element is an ancestor of el, else false
7062          */
7063         contains : function(el){
7064             if(!el){return false;}
7065             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7066         },
7067
7068         /**
7069          * Checks whether the element is currently visible using both visibility and display properties.
7070          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7071          * @return {Boolean} True if the element is currently visible, else false
7072          */
7073         isVisible : function(deep) {
7074             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7075             if(deep !== true || !vis){
7076                 return vis;
7077             }
7078             var p = this.dom.parentNode;
7079             while(p && p.tagName.toLowerCase() != "body"){
7080                 if(!Roo.fly(p, '_isVisible').isVisible()){
7081                     return false;
7082                 }
7083                 p = p.parentNode;
7084             }
7085             return true;
7086         },
7087
7088         /**
7089          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7090          * @param {String} selector The CSS selector
7091          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7092          * @return {CompositeElement/CompositeElementLite} The composite element
7093          */
7094         select : function(selector, unique){
7095             return El.select(selector, unique, this.dom);
7096         },
7097
7098         /**
7099          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7100          * @param {String} selector The CSS selector
7101          * @return {Array} An array of the matched nodes
7102          */
7103         query : function(selector, unique){
7104             return Roo.DomQuery.select(selector, this.dom);
7105         },
7106
7107         /**
7108          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7109          * @param {String} selector The CSS selector
7110          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7111          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7112          */
7113         child : function(selector, returnDom){
7114             var n = Roo.DomQuery.selectNode(selector, this.dom);
7115             return returnDom ? n : Roo.get(n);
7116         },
7117
7118         /**
7119          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7120          * @param {String} selector The CSS selector
7121          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7122          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7123          */
7124         down : function(selector, returnDom){
7125             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7126             return returnDom ? n : Roo.get(n);
7127         },
7128
7129         /**
7130          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7131          * @param {String} group The group the DD object is member of
7132          * @param {Object} config The DD config object
7133          * @param {Object} overrides An object containing methods to override/implement on the DD object
7134          * @return {Roo.dd.DD} The DD object
7135          */
7136         initDD : function(group, config, overrides){
7137             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7138             return Roo.apply(dd, overrides);
7139         },
7140
7141         /**
7142          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7143          * @param {String} group The group the DDProxy object is member of
7144          * @param {Object} config The DDProxy config object
7145          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7146          * @return {Roo.dd.DDProxy} The DDProxy object
7147          */
7148         initDDProxy : function(group, config, overrides){
7149             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7150             return Roo.apply(dd, overrides);
7151         },
7152
7153         /**
7154          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7155          * @param {String} group The group the DDTarget object is member of
7156          * @param {Object} config The DDTarget config object
7157          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7158          * @return {Roo.dd.DDTarget} The DDTarget object
7159          */
7160         initDDTarget : function(group, config, overrides){
7161             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7162             return Roo.apply(dd, overrides);
7163         },
7164
7165         /**
7166          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7167          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7168          * @param {Boolean} visible Whether the element is visible
7169          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7170          * @return {Roo.Element} this
7171          */
7172          setVisible : function(visible, animate){
7173             if(!animate || !A){
7174                 if(this.visibilityMode == El.DISPLAY){
7175                     this.setDisplayed(visible);
7176                 }else{
7177                     this.fixDisplay();
7178                     this.dom.style.visibility = visible ? "visible" : "hidden";
7179                 }
7180             }else{
7181                 // closure for composites
7182                 var dom = this.dom;
7183                 var visMode = this.visibilityMode;
7184                 if(visible){
7185                     this.setOpacity(.01);
7186                     this.setVisible(true);
7187                 }
7188                 this.anim({opacity: { to: (visible?1:0) }},
7189                       this.preanim(arguments, 1),
7190                       null, .35, 'easeIn', function(){
7191                          if(!visible){
7192                              if(visMode == El.DISPLAY){
7193                                  dom.style.display = "none";
7194                              }else{
7195                                  dom.style.visibility = "hidden";
7196                              }
7197                              Roo.get(dom).setOpacity(1);
7198                          }
7199                      });
7200             }
7201             return this;
7202         },
7203
7204         /**
7205          * Returns true if display is not "none"
7206          * @return {Boolean}
7207          */
7208         isDisplayed : function() {
7209             return this.getStyle("display") != "none";
7210         },
7211
7212         /**
7213          * Toggles the element's visibility or display, depending on visibility mode.
7214          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7215          * @return {Roo.Element} this
7216          */
7217         toggle : function(animate){
7218             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7219             return this;
7220         },
7221
7222         /**
7223          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7224          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7225          * @return {Roo.Element} this
7226          */
7227         setDisplayed : function(value) {
7228             if(typeof value == "boolean"){
7229                value = value ? this.originalDisplay : "none";
7230             }
7231             this.setStyle("display", value);
7232             return this;
7233         },
7234
7235         /**
7236          * Tries to focus the element. Any exceptions are caught and ignored.
7237          * @return {Roo.Element} this
7238          */
7239         focus : function() {
7240             try{
7241                 this.dom.focus();
7242             }catch(e){}
7243             return this;
7244         },
7245
7246         /**
7247          * Tries to blur the element. Any exceptions are caught and ignored.
7248          * @return {Roo.Element} this
7249          */
7250         blur : function() {
7251             try{
7252                 this.dom.blur();
7253             }catch(e){}
7254             return this;
7255         },
7256
7257         /**
7258          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7259          * @param {String/Array} className The CSS class to add, or an array of classes
7260          * @return {Roo.Element} this
7261          */
7262         addClass : function(className){
7263             if(className instanceof Array){
7264                 for(var i = 0, len = className.length; i < len; i++) {
7265                     this.addClass(className[i]);
7266                 }
7267             }else{
7268                 if(className && !this.hasClass(className)){
7269                     this.dom.className = this.dom.className + " " + className;
7270                 }
7271             }
7272             return this;
7273         },
7274
7275         /**
7276          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7277          * @param {String/Array} className The CSS class to add, or an array of classes
7278          * @return {Roo.Element} this
7279          */
7280         radioClass : function(className){
7281             var siblings = this.dom.parentNode.childNodes;
7282             for(var i = 0; i < siblings.length; i++) {
7283                 var s = siblings[i];
7284                 if(s.nodeType == 1){
7285                     Roo.get(s).removeClass(className);
7286                 }
7287             }
7288             this.addClass(className);
7289             return this;
7290         },
7291
7292         /**
7293          * Removes one or more CSS classes from the element.
7294          * @param {String/Array} className The CSS class to remove, or an array of classes
7295          * @return {Roo.Element} this
7296          */
7297         removeClass : function(className){
7298             if(!className || !this.dom.className){
7299                 return this;
7300             }
7301             if(className instanceof Array){
7302                 for(var i = 0, len = className.length; i < len; i++) {
7303                     this.removeClass(className[i]);
7304                 }
7305             }else{
7306                 if(this.hasClass(className)){
7307                     var re = this.classReCache[className];
7308                     if (!re) {
7309                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7310                        this.classReCache[className] = re;
7311                     }
7312                     this.dom.className =
7313                         this.dom.className.replace(re, " ");
7314                 }
7315             }
7316             return this;
7317         },
7318
7319         // private
7320         classReCache: {},
7321
7322         /**
7323          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7324          * @param {String} className The CSS class to toggle
7325          * @return {Roo.Element} this
7326          */
7327         toggleClass : function(className){
7328             if(this.hasClass(className)){
7329                 this.removeClass(className);
7330             }else{
7331                 this.addClass(className);
7332             }
7333             return this;
7334         },
7335
7336         /**
7337          * Checks if the specified CSS class exists on this element's DOM node.
7338          * @param {String} className The CSS class to check for
7339          * @return {Boolean} True if the class exists, else false
7340          */
7341         hasClass : function(className){
7342             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7343         },
7344
7345         /**
7346          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7347          * @param {String} oldClassName The CSS class to replace
7348          * @param {String} newClassName The replacement CSS class
7349          * @return {Roo.Element} this
7350          */
7351         replaceClass : function(oldClassName, newClassName){
7352             this.removeClass(oldClassName);
7353             this.addClass(newClassName);
7354             return this;
7355         },
7356
7357         /**
7358          * Returns an object with properties matching the styles requested.
7359          * For example, el.getStyles('color', 'font-size', 'width') might return
7360          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7361          * @param {String} style1 A style name
7362          * @param {String} style2 A style name
7363          * @param {String} etc.
7364          * @return {Object} The style object
7365          */
7366         getStyles : function(){
7367             var a = arguments, len = a.length, r = {};
7368             for(var i = 0; i < len; i++){
7369                 r[a[i]] = this.getStyle(a[i]);
7370             }
7371             return r;
7372         },
7373
7374         /**
7375          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7376          * @param {String} property The style property whose value is returned.
7377          * @return {String} The current value of the style property for this element.
7378          */
7379         getStyle : function(){
7380             return view && view.getComputedStyle ?
7381                 function(prop){
7382                     var el = this.dom, v, cs, camel;
7383                     if(prop == 'float'){
7384                         prop = "cssFloat";
7385                     }
7386                     if(el.style && (v = el.style[prop])){
7387                         return v;
7388                     }
7389                     if(cs = view.getComputedStyle(el, "")){
7390                         if(!(camel = propCache[prop])){
7391                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7392                         }
7393                         return cs[camel];
7394                     }
7395                     return null;
7396                 } :
7397                 function(prop){
7398                     var el = this.dom, v, cs, camel;
7399                     if(prop == 'opacity'){
7400                         if(typeof el.style.filter == 'string'){
7401                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7402                             if(m){
7403                                 var fv = parseFloat(m[1]);
7404                                 if(!isNaN(fv)){
7405                                     return fv ? fv / 100 : 0;
7406                                 }
7407                             }
7408                         }
7409                         return 1;
7410                     }else if(prop == 'float'){
7411                         prop = "styleFloat";
7412                     }
7413                     if(!(camel = propCache[prop])){
7414                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7415                     }
7416                     if(v = el.style[camel]){
7417                         return v;
7418                     }
7419                     if(cs = el.currentStyle){
7420                         return cs[camel];
7421                     }
7422                     return null;
7423                 };
7424         }(),
7425
7426         /**
7427          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7428          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7429          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7430          * @return {Roo.Element} this
7431          */
7432         setStyle : function(prop, value){
7433             if(typeof prop == "string"){
7434                 
7435                 if (prop == 'float') {
7436                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7437                     return this;
7438                 }
7439                 
7440                 var camel;
7441                 if(!(camel = propCache[prop])){
7442                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7443                 }
7444                 
7445                 if(camel == 'opacity') {
7446                     this.setOpacity(value);
7447                 }else{
7448                     this.dom.style[camel] = value;
7449                 }
7450             }else{
7451                 for(var style in prop){
7452                     if(typeof prop[style] != "function"){
7453                        this.setStyle(style, prop[style]);
7454                     }
7455                 }
7456             }
7457             return this;
7458         },
7459
7460         /**
7461          * More flexible version of {@link #setStyle} for setting style properties.
7462          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7463          * a function which returns such a specification.
7464          * @return {Roo.Element} this
7465          */
7466         applyStyles : function(style){
7467             Roo.DomHelper.applyStyles(this.dom, style);
7468             return this;
7469         },
7470
7471         /**
7472           * 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).
7473           * @return {Number} The X position of the element
7474           */
7475         getX : function(){
7476             return D.getX(this.dom);
7477         },
7478
7479         /**
7480           * 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).
7481           * @return {Number} The Y position of the element
7482           */
7483         getY : function(){
7484             return D.getY(this.dom);
7485         },
7486
7487         /**
7488           * 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).
7489           * @return {Array} The XY position of the element
7490           */
7491         getXY : function(){
7492             return D.getXY(this.dom);
7493         },
7494
7495         /**
7496          * 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).
7497          * @param {Number} The X position of the element
7498          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7499          * @return {Roo.Element} this
7500          */
7501         setX : function(x, animate){
7502             if(!animate || !A){
7503                 D.setX(this.dom, x);
7504             }else{
7505                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7506             }
7507             return this;
7508         },
7509
7510         /**
7511          * 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).
7512          * @param {Number} The Y position of the element
7513          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7514          * @return {Roo.Element} this
7515          */
7516         setY : function(y, animate){
7517             if(!animate || !A){
7518                 D.setY(this.dom, y);
7519             }else{
7520                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7521             }
7522             return this;
7523         },
7524
7525         /**
7526          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7527          * @param {String} left The left CSS property value
7528          * @return {Roo.Element} this
7529          */
7530         setLeft : function(left){
7531             this.setStyle("left", this.addUnits(left));
7532             return this;
7533         },
7534
7535         /**
7536          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7537          * @param {String} top The top CSS property value
7538          * @return {Roo.Element} this
7539          */
7540         setTop : function(top){
7541             this.setStyle("top", this.addUnits(top));
7542             return this;
7543         },
7544
7545         /**
7546          * Sets the element's CSS right style.
7547          * @param {String} right The right CSS property value
7548          * @return {Roo.Element} this
7549          */
7550         setRight : function(right){
7551             this.setStyle("right", this.addUnits(right));
7552             return this;
7553         },
7554
7555         /**
7556          * Sets the element's CSS bottom style.
7557          * @param {String} bottom The bottom CSS property value
7558          * @return {Roo.Element} this
7559          */
7560         setBottom : function(bottom){
7561             this.setStyle("bottom", this.addUnits(bottom));
7562             return this;
7563         },
7564
7565         /**
7566          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7567          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7568          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7569          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7570          * @return {Roo.Element} this
7571          */
7572         setXY : function(pos, animate){
7573             if(!animate || !A){
7574                 D.setXY(this.dom, pos);
7575             }else{
7576                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7577             }
7578             return this;
7579         },
7580
7581         /**
7582          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7583          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7584          * @param {Number} x X value for new position (coordinates are page-based)
7585          * @param {Number} y Y value for new position (coordinates are page-based)
7586          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7587          * @return {Roo.Element} this
7588          */
7589         setLocation : function(x, y, animate){
7590             this.setXY([x, y], this.preanim(arguments, 2));
7591             return this;
7592         },
7593
7594         /**
7595          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7596          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7597          * @param {Number} x X value for new position (coordinates are page-based)
7598          * @param {Number} y Y value for new position (coordinates are page-based)
7599          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7600          * @return {Roo.Element} this
7601          */
7602         moveTo : function(x, y, animate){
7603             this.setXY([x, y], this.preanim(arguments, 2));
7604             return this;
7605         },
7606
7607         /**
7608          * Returns the region of the given element.
7609          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7610          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7611          */
7612         getRegion : function(){
7613             return D.getRegion(this.dom);
7614         },
7615
7616         /**
7617          * Returns the offset height of the element
7618          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7619          * @return {Number} The element's height
7620          */
7621         getHeight : function(contentHeight){
7622             var h = this.dom.offsetHeight || 0;
7623             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7624         },
7625
7626         /**
7627          * Returns the offset width of the element
7628          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7629          * @return {Number} The element's width
7630          */
7631         getWidth : function(contentWidth){
7632             var w = this.dom.offsetWidth || 0;
7633             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7634         },
7635
7636         /**
7637          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7638          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7639          * if a height has not been set using CSS.
7640          * @return {Number}
7641          */
7642         getComputedHeight : function(){
7643             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7644             if(!h){
7645                 h = parseInt(this.getStyle('height'), 10) || 0;
7646                 if(!this.isBorderBox()){
7647                     h += this.getFrameWidth('tb');
7648                 }
7649             }
7650             return h;
7651         },
7652
7653         /**
7654          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7655          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7656          * if a width has not been set using CSS.
7657          * @return {Number}
7658          */
7659         getComputedWidth : function(){
7660             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7661             if(!w){
7662                 w = parseInt(this.getStyle('width'), 10) || 0;
7663                 if(!this.isBorderBox()){
7664                     w += this.getFrameWidth('lr');
7665                 }
7666             }
7667             return w;
7668         },
7669
7670         /**
7671          * Returns the size of the element.
7672          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7673          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7674          */
7675         getSize : function(contentSize){
7676             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7677         },
7678
7679         /**
7680          * Returns the width and height of the viewport.
7681          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7682          */
7683         getViewSize : function(){
7684             var d = this.dom, doc = document, aw = 0, ah = 0;
7685             if(d == doc || d == doc.body){
7686                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7687             }else{
7688                 return {
7689                     width : d.clientWidth,
7690                     height: d.clientHeight
7691                 };
7692             }
7693         },
7694
7695         /**
7696          * Returns the value of the "value" attribute
7697          * @param {Boolean} asNumber true to parse the value as a number
7698          * @return {String/Number}
7699          */
7700         getValue : function(asNumber){
7701             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7702         },
7703
7704         // private
7705         adjustWidth : function(width){
7706             if(typeof width == "number"){
7707                 if(this.autoBoxAdjust && !this.isBorderBox()){
7708                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7709                 }
7710                 if(width < 0){
7711                     width = 0;
7712                 }
7713             }
7714             return width;
7715         },
7716
7717         // private
7718         adjustHeight : function(height){
7719             if(typeof height == "number"){
7720                if(this.autoBoxAdjust && !this.isBorderBox()){
7721                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7722                }
7723                if(height < 0){
7724                    height = 0;
7725                }
7726             }
7727             return height;
7728         },
7729
7730         /**
7731          * Set the width of the element
7732          * @param {Number} width The new width
7733          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7734          * @return {Roo.Element} this
7735          */
7736         setWidth : function(width, animate){
7737             width = this.adjustWidth(width);
7738             if(!animate || !A){
7739                 this.dom.style.width = this.addUnits(width);
7740             }else{
7741                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7742             }
7743             return this;
7744         },
7745
7746         /**
7747          * Set the height of the element
7748          * @param {Number} height The new height
7749          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7750          * @return {Roo.Element} this
7751          */
7752          setHeight : function(height, animate){
7753             height = this.adjustHeight(height);
7754             if(!animate || !A){
7755                 this.dom.style.height = this.addUnits(height);
7756             }else{
7757                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7758             }
7759             return this;
7760         },
7761
7762         /**
7763          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7764          * @param {Number} width The new width
7765          * @param {Number} height The new height
7766          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7767          * @return {Roo.Element} this
7768          */
7769          setSize : function(width, height, animate){
7770             if(typeof width == "object"){ // in case of object from getSize()
7771                 height = width.height; width = width.width;
7772             }
7773             width = this.adjustWidth(width); height = this.adjustHeight(height);
7774             if(!animate || !A){
7775                 this.dom.style.width = this.addUnits(width);
7776                 this.dom.style.height = this.addUnits(height);
7777             }else{
7778                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7779             }
7780             return this;
7781         },
7782
7783         /**
7784          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7785          * @param {Number} x X value for new position (coordinates are page-based)
7786          * @param {Number} y Y value for new position (coordinates are page-based)
7787          * @param {Number} width The new width
7788          * @param {Number} height The new height
7789          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7790          * @return {Roo.Element} this
7791          */
7792         setBounds : function(x, y, width, height, animate){
7793             if(!animate || !A){
7794                 this.setSize(width, height);
7795                 this.setLocation(x, y);
7796             }else{
7797                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7798                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7799                               this.preanim(arguments, 4), 'motion');
7800             }
7801             return this;
7802         },
7803
7804         /**
7805          * 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.
7806          * @param {Roo.lib.Region} region The region to fill
7807          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7808          * @return {Roo.Element} this
7809          */
7810         setRegion : function(region, animate){
7811             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7812             return this;
7813         },
7814
7815         /**
7816          * Appends an event handler
7817          *
7818          * @param {String}   eventName     The type of event to append
7819          * @param {Function} fn        The method the event invokes
7820          * @param {Object} scope       (optional) The scope (this object) of the fn
7821          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7822          */
7823         addListener : function(eventName, fn, scope, options){
7824             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7825         },
7826
7827         /**
7828          * Removes an event handler from this element
7829          * @param {String} eventName the type of event to remove
7830          * @param {Function} fn the method the event invokes
7831          * @return {Roo.Element} this
7832          */
7833         removeListener : function(eventName, fn){
7834             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7835             return this;
7836         },
7837
7838         /**
7839          * Removes all previous added listeners from this element
7840          * @return {Roo.Element} this
7841          */
7842         removeAllListeners : function(){
7843             E.purgeElement(this.dom);
7844             return this;
7845         },
7846
7847         relayEvent : function(eventName, observable){
7848             this.on(eventName, function(e){
7849                 observable.fireEvent(eventName, e);
7850             });
7851         },
7852
7853         /**
7854          * Set the opacity of the element
7855          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7856          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7857          * @return {Roo.Element} this
7858          */
7859          setOpacity : function(opacity, animate){
7860             if(!animate || !A){
7861                 var s = this.dom.style;
7862                 if(Roo.isIE){
7863                     s.zoom = 1;
7864                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7865                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7866                 }else{
7867                     s.opacity = opacity;
7868                 }
7869             }else{
7870                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7871             }
7872             return this;
7873         },
7874
7875         /**
7876          * Gets the left X coordinate
7877          * @param {Boolean} local True to get the local css position instead of page coordinate
7878          * @return {Number}
7879          */
7880         getLeft : function(local){
7881             if(!local){
7882                 return this.getX();
7883             }else{
7884                 return parseInt(this.getStyle("left"), 10) || 0;
7885             }
7886         },
7887
7888         /**
7889          * Gets the right X coordinate of the element (element X position + element width)
7890          * @param {Boolean} local True to get the local css position instead of page coordinate
7891          * @return {Number}
7892          */
7893         getRight : function(local){
7894             if(!local){
7895                 return this.getX() + this.getWidth();
7896             }else{
7897                 return (this.getLeft(true) + this.getWidth()) || 0;
7898             }
7899         },
7900
7901         /**
7902          * Gets the top Y coordinate
7903          * @param {Boolean} local True to get the local css position instead of page coordinate
7904          * @return {Number}
7905          */
7906         getTop : function(local) {
7907             if(!local){
7908                 return this.getY();
7909             }else{
7910                 return parseInt(this.getStyle("top"), 10) || 0;
7911             }
7912         },
7913
7914         /**
7915          * Gets the bottom Y coordinate of the element (element Y position + element height)
7916          * @param {Boolean} local True to get the local css position instead of page coordinate
7917          * @return {Number}
7918          */
7919         getBottom : function(local){
7920             if(!local){
7921                 return this.getY() + this.getHeight();
7922             }else{
7923                 return (this.getTop(true) + this.getHeight()) || 0;
7924             }
7925         },
7926
7927         /**
7928         * Initializes positioning on this element. If a desired position is not passed, it will make the
7929         * the element positioned relative IF it is not already positioned.
7930         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7931         * @param {Number} zIndex (optional) The zIndex to apply
7932         * @param {Number} x (optional) Set the page X position
7933         * @param {Number} y (optional) Set the page Y position
7934         */
7935         position : function(pos, zIndex, x, y){
7936             if(!pos){
7937                if(this.getStyle('position') == 'static'){
7938                    this.setStyle('position', 'relative');
7939                }
7940             }else{
7941                 this.setStyle("position", pos);
7942             }
7943             if(zIndex){
7944                 this.setStyle("z-index", zIndex);
7945             }
7946             if(x !== undefined && y !== undefined){
7947                 this.setXY([x, y]);
7948             }else if(x !== undefined){
7949                 this.setX(x);
7950             }else if(y !== undefined){
7951                 this.setY(y);
7952             }
7953         },
7954
7955         /**
7956         * Clear positioning back to the default when the document was loaded
7957         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7958         * @return {Roo.Element} this
7959          */
7960         clearPositioning : function(value){
7961             value = value ||'';
7962             this.setStyle({
7963                 "left": value,
7964                 "right": value,
7965                 "top": value,
7966                 "bottom": value,
7967                 "z-index": "",
7968                 "position" : "static"
7969             });
7970             return this;
7971         },
7972
7973         /**
7974         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7975         * snapshot before performing an update and then restoring the element.
7976         * @return {Object}
7977         */
7978         getPositioning : function(){
7979             var l = this.getStyle("left");
7980             var t = this.getStyle("top");
7981             return {
7982                 "position" : this.getStyle("position"),
7983                 "left" : l,
7984                 "right" : l ? "" : this.getStyle("right"),
7985                 "top" : t,
7986                 "bottom" : t ? "" : this.getStyle("bottom"),
7987                 "z-index" : this.getStyle("z-index")
7988             };
7989         },
7990
7991         /**
7992          * Gets the width of the border(s) for the specified side(s)
7993          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7994          * passing lr would get the border (l)eft width + the border (r)ight width.
7995          * @return {Number} The width of the sides passed added together
7996          */
7997         getBorderWidth : function(side){
7998             return this.addStyles(side, El.borders);
7999         },
8000
8001         /**
8002          * Gets the width of the padding(s) for the specified side(s)
8003          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8004          * passing lr would get the padding (l)eft + the padding (r)ight.
8005          * @return {Number} The padding of the sides passed added together
8006          */
8007         getPadding : function(side){
8008             return this.addStyles(side, El.paddings);
8009         },
8010
8011         /**
8012         * Set positioning with an object returned by getPositioning().
8013         * @param {Object} posCfg
8014         * @return {Roo.Element} this
8015          */
8016         setPositioning : function(pc){
8017             this.applyStyles(pc);
8018             if(pc.right == "auto"){
8019                 this.dom.style.right = "";
8020             }
8021             if(pc.bottom == "auto"){
8022                 this.dom.style.bottom = "";
8023             }
8024             return this;
8025         },
8026
8027         // private
8028         fixDisplay : function(){
8029             if(this.getStyle("display") == "none"){
8030                 this.setStyle("visibility", "hidden");
8031                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8032                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8033                     this.setStyle("display", "block");
8034                 }
8035             }
8036         },
8037
8038         /**
8039          * Quick set left and top adding default units
8040          * @param {String} left The left CSS property value
8041          * @param {String} top The top CSS property value
8042          * @return {Roo.Element} this
8043          */
8044          setLeftTop : function(left, top){
8045             this.dom.style.left = this.addUnits(left);
8046             this.dom.style.top = this.addUnits(top);
8047             return this;
8048         },
8049
8050         /**
8051          * Move this element relative to its current position.
8052          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8053          * @param {Number} distance How far to move the element in pixels
8054          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8055          * @return {Roo.Element} this
8056          */
8057          move : function(direction, distance, animate){
8058             var xy = this.getXY();
8059             direction = direction.toLowerCase();
8060             switch(direction){
8061                 case "l":
8062                 case "left":
8063                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8064                     break;
8065                case "r":
8066                case "right":
8067                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8068                     break;
8069                case "t":
8070                case "top":
8071                case "up":
8072                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8073                     break;
8074                case "b":
8075                case "bottom":
8076                case "down":
8077                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8078                     break;
8079             }
8080             return this;
8081         },
8082
8083         /**
8084          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8085          * @return {Roo.Element} this
8086          */
8087         clip : function(){
8088             if(!this.isClipped){
8089                this.isClipped = true;
8090                this.originalClip = {
8091                    "o": this.getStyle("overflow"),
8092                    "x": this.getStyle("overflow-x"),
8093                    "y": this.getStyle("overflow-y")
8094                };
8095                this.setStyle("overflow", "hidden");
8096                this.setStyle("overflow-x", "hidden");
8097                this.setStyle("overflow-y", "hidden");
8098             }
8099             return this;
8100         },
8101
8102         /**
8103          *  Return clipping (overflow) to original clipping before clip() was called
8104          * @return {Roo.Element} this
8105          */
8106         unclip : function(){
8107             if(this.isClipped){
8108                 this.isClipped = false;
8109                 var o = this.originalClip;
8110                 if(o.o){this.setStyle("overflow", o.o);}
8111                 if(o.x){this.setStyle("overflow-x", o.x);}
8112                 if(o.y){this.setStyle("overflow-y", o.y);}
8113             }
8114             return this;
8115         },
8116
8117
8118         /**
8119          * Gets the x,y coordinates specified by the anchor position on the element.
8120          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8121          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8122          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8123          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8124          * @return {Array} [x, y] An array containing the element's x and y coordinates
8125          */
8126         getAnchorXY : function(anchor, local, s){
8127             //Passing a different size is useful for pre-calculating anchors,
8128             //especially for anchored animations that change the el size.
8129
8130             var w, h, vp = false;
8131             if(!s){
8132                 var d = this.dom;
8133                 if(d == document.body || d == document){
8134                     vp = true;
8135                     w = D.getViewWidth(); h = D.getViewHeight();
8136                 }else{
8137                     w = this.getWidth(); h = this.getHeight();
8138                 }
8139             }else{
8140                 w = s.width;  h = s.height;
8141             }
8142             var x = 0, y = 0, r = Math.round;
8143             switch((anchor || "tl").toLowerCase()){
8144                 case "c":
8145                     x = r(w*.5);
8146                     y = r(h*.5);
8147                 break;
8148                 case "t":
8149                     x = r(w*.5);
8150                     y = 0;
8151                 break;
8152                 case "l":
8153                     x = 0;
8154                     y = r(h*.5);
8155                 break;
8156                 case "r":
8157                     x = w;
8158                     y = r(h*.5);
8159                 break;
8160                 case "b":
8161                     x = r(w*.5);
8162                     y = h;
8163                 break;
8164                 case "tl":
8165                     x = 0;
8166                     y = 0;
8167                 break;
8168                 case "bl":
8169                     x = 0;
8170                     y = h;
8171                 break;
8172                 case "br":
8173                     x = w;
8174                     y = h;
8175                 break;
8176                 case "tr":
8177                     x = w;
8178                     y = 0;
8179                 break;
8180             }
8181             if(local === true){
8182                 return [x, y];
8183             }
8184             if(vp){
8185                 var sc = this.getScroll();
8186                 return [x + sc.left, y + sc.top];
8187             }
8188             //Add the element's offset xy
8189             var o = this.getXY();
8190             return [x+o[0], y+o[1]];
8191         },
8192
8193         /**
8194          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8195          * supported position values.
8196          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8197          * @param {String} position The position to align to.
8198          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8199          * @return {Array} [x, y]
8200          */
8201         getAlignToXY : function(el, p, o){
8202             el = Roo.get(el);
8203             var d = this.dom;
8204             if(!el.dom){
8205                 throw "Element.alignTo with an element that doesn't exist";
8206             }
8207             var c = false; //constrain to viewport
8208             var p1 = "", p2 = "";
8209             o = o || [0,0];
8210
8211             if(!p){
8212                 p = "tl-bl";
8213             }else if(p == "?"){
8214                 p = "tl-bl?";
8215             }else if(p.indexOf("-") == -1){
8216                 p = "tl-" + p;
8217             }
8218             p = p.toLowerCase();
8219             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8220             if(!m){
8221                throw "Element.alignTo with an invalid alignment " + p;
8222             }
8223             p1 = m[1]; p2 = m[2]; c = !!m[3];
8224
8225             //Subtract the aligned el's internal xy from the target's offset xy
8226             //plus custom offset to get the aligned el's new offset xy
8227             var a1 = this.getAnchorXY(p1, true);
8228             var a2 = el.getAnchorXY(p2, false);
8229             var x = a2[0] - a1[0] + o[0];
8230             var y = a2[1] - a1[1] + o[1];
8231             if(c){
8232                 //constrain the aligned el to viewport if necessary
8233                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8234                 // 5px of margin for ie
8235                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8236
8237                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8238                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8239                 //otherwise swap the aligned el to the opposite border of the target.
8240                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8241                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8242                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8243                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8244
8245                var doc = document;
8246                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8247                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8248
8249                if((x+w) > dw + scrollX){
8250                     x = swapX ? r.left-w : dw+scrollX-w;
8251                 }
8252                if(x < scrollX){
8253                    x = swapX ? r.right : scrollX;
8254                }
8255                if((y+h) > dh + scrollY){
8256                     y = swapY ? r.top-h : dh+scrollY-h;
8257                 }
8258                if (y < scrollY){
8259                    y = swapY ? r.bottom : scrollY;
8260                }
8261             }
8262             return [x,y];
8263         },
8264
8265         // private
8266         getConstrainToXY : function(){
8267             var os = {top:0, left:0, bottom:0, right: 0};
8268
8269             return function(el, local, offsets, proposedXY){
8270                 el = Roo.get(el);
8271                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8272
8273                 var vw, vh, vx = 0, vy = 0;
8274                 if(el.dom == document.body || el.dom == document){
8275                     vw = Roo.lib.Dom.getViewWidth();
8276                     vh = Roo.lib.Dom.getViewHeight();
8277                 }else{
8278                     vw = el.dom.clientWidth;
8279                     vh = el.dom.clientHeight;
8280                     if(!local){
8281                         var vxy = el.getXY();
8282                         vx = vxy[0];
8283                         vy = vxy[1];
8284                     }
8285                 }
8286
8287                 var s = el.getScroll();
8288
8289                 vx += offsets.left + s.left;
8290                 vy += offsets.top + s.top;
8291
8292                 vw -= offsets.right;
8293                 vh -= offsets.bottom;
8294
8295                 var vr = vx+vw;
8296                 var vb = vy+vh;
8297
8298                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8299                 var x = xy[0], y = xy[1];
8300                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8301
8302                 // only move it if it needs it
8303                 var moved = false;
8304
8305                 // first validate right/bottom
8306                 if((x + w) > vr){
8307                     x = vr - w;
8308                     moved = true;
8309                 }
8310                 if((y + h) > vb){
8311                     y = vb - h;
8312                     moved = true;
8313                 }
8314                 // then make sure top/left isn't negative
8315                 if(x < vx){
8316                     x = vx;
8317                     moved = true;
8318                 }
8319                 if(y < vy){
8320                     y = vy;
8321                     moved = true;
8322                 }
8323                 return moved ? [x, y] : false;
8324             };
8325         }(),
8326
8327         // private
8328         adjustForConstraints : function(xy, parent, offsets){
8329             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8330         },
8331
8332         /**
8333          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8334          * document it aligns it to the viewport.
8335          * The position parameter is optional, and can be specified in any one of the following formats:
8336          * <ul>
8337          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8338          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8339          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8340          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8341          *   <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
8342          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8343          * </ul>
8344          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8345          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8346          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8347          * that specified in order to enforce the viewport constraints.
8348          * Following are all of the supported anchor positions:
8349     <pre>
8350     Value  Description
8351     -----  -----------------------------
8352     tl     The top left corner (default)
8353     t      The center of the top edge
8354     tr     The top right corner
8355     l      The center of the left edge
8356     c      In the center of the element
8357     r      The center of the right edge
8358     bl     The bottom left corner
8359     b      The center of the bottom edge
8360     br     The bottom right corner
8361     </pre>
8362     Example Usage:
8363     <pre><code>
8364     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8365     el.alignTo("other-el");
8366
8367     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8368     el.alignTo("other-el", "tr?");
8369
8370     // align the bottom right corner of el with the center left edge of other-el
8371     el.alignTo("other-el", "br-l?");
8372
8373     // align the center of el with the bottom left corner of other-el and
8374     // adjust the x position by -6 pixels (and the y position by 0)
8375     el.alignTo("other-el", "c-bl", [-6, 0]);
8376     </code></pre>
8377          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8378          * @param {String} position The position to align to.
8379          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8380          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8381          * @return {Roo.Element} this
8382          */
8383         alignTo : function(element, position, offsets, animate){
8384             var xy = this.getAlignToXY(element, position, offsets);
8385             this.setXY(xy, this.preanim(arguments, 3));
8386             return this;
8387         },
8388
8389         /**
8390          * Anchors an element to another element and realigns it when the window is resized.
8391          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8392          * @param {String} position The position to align to.
8393          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8394          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8395          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8396          * is a number, it is used as the buffer delay (defaults to 50ms).
8397          * @param {Function} callback The function to call after the animation finishes
8398          * @return {Roo.Element} this
8399          */
8400         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8401             var action = function(){
8402                 this.alignTo(el, alignment, offsets, animate);
8403                 Roo.callback(callback, this);
8404             };
8405             Roo.EventManager.onWindowResize(action, this);
8406             var tm = typeof monitorScroll;
8407             if(tm != 'undefined'){
8408                 Roo.EventManager.on(window, 'scroll', action, this,
8409                     {buffer: tm == 'number' ? monitorScroll : 50});
8410             }
8411             action.call(this); // align immediately
8412             return this;
8413         },
8414         /**
8415          * Clears any opacity settings from this element. Required in some cases for IE.
8416          * @return {Roo.Element} this
8417          */
8418         clearOpacity : function(){
8419             if (window.ActiveXObject) {
8420                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8421                     this.dom.style.filter = "";
8422                 }
8423             } else {
8424                 this.dom.style.opacity = "";
8425                 this.dom.style["-moz-opacity"] = "";
8426                 this.dom.style["-khtml-opacity"] = "";
8427             }
8428             return this;
8429         },
8430
8431         /**
8432          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8433          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8434          * @return {Roo.Element} this
8435          */
8436         hide : function(animate){
8437             this.setVisible(false, this.preanim(arguments, 0));
8438             return this;
8439         },
8440
8441         /**
8442         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8443         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8444          * @return {Roo.Element} this
8445          */
8446         show : function(animate){
8447             this.setVisible(true, this.preanim(arguments, 0));
8448             return this;
8449         },
8450
8451         /**
8452          * @private Test if size has a unit, otherwise appends the default
8453          */
8454         addUnits : function(size){
8455             return Roo.Element.addUnits(size, this.defaultUnit);
8456         },
8457
8458         /**
8459          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8460          * @return {Roo.Element} this
8461          */
8462         beginMeasure : function(){
8463             var el = this.dom;
8464             if(el.offsetWidth || el.offsetHeight){
8465                 return this; // offsets work already
8466             }
8467             var changed = [];
8468             var p = this.dom, b = document.body; // start with this element
8469             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8470                 var pe = Roo.get(p);
8471                 if(pe.getStyle('display') == 'none'){
8472                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8473                     p.style.visibility = "hidden";
8474                     p.style.display = "block";
8475                 }
8476                 p = p.parentNode;
8477             }
8478             this._measureChanged = changed;
8479             return this;
8480
8481         },
8482
8483         /**
8484          * Restores displays to before beginMeasure was called
8485          * @return {Roo.Element} this
8486          */
8487         endMeasure : function(){
8488             var changed = this._measureChanged;
8489             if(changed){
8490                 for(var i = 0, len = changed.length; i < len; i++) {
8491                     var r = changed[i];
8492                     r.el.style.visibility = r.visibility;
8493                     r.el.style.display = "none";
8494                 }
8495                 this._measureChanged = null;
8496             }
8497             return this;
8498         },
8499
8500         /**
8501         * Update the innerHTML of this element, optionally searching for and processing scripts
8502         * @param {String} html The new HTML
8503         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8504         * @param {Function} callback For async script loading you can be noticed when the update completes
8505         * @return {Roo.Element} this
8506          */
8507         update : function(html, loadScripts, callback){
8508             if(typeof html == "undefined"){
8509                 html = "";
8510             }
8511             if(loadScripts !== true){
8512                 this.dom.innerHTML = html;
8513                 if(typeof callback == "function"){
8514                     callback();
8515                 }
8516                 return this;
8517             }
8518             var id = Roo.id();
8519             var dom = this.dom;
8520
8521             html += '<span id="' + id + '"></span>';
8522
8523             E.onAvailable(id, function(){
8524                 var hd = document.getElementsByTagName("head")[0];
8525                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8526                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8527                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8528
8529                 var match;
8530                 while(match = re.exec(html)){
8531                     var attrs = match[1];
8532                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8533                     if(srcMatch && srcMatch[2]){
8534                        var s = document.createElement("script");
8535                        s.src = srcMatch[2];
8536                        var typeMatch = attrs.match(typeRe);
8537                        if(typeMatch && typeMatch[2]){
8538                            s.type = typeMatch[2];
8539                        }
8540                        hd.appendChild(s);
8541                     }else if(match[2] && match[2].length > 0){
8542                         if(window.execScript) {
8543                            window.execScript(match[2]);
8544                         } else {
8545                             /**
8546                              * eval:var:id
8547                              * eval:var:dom
8548                              * eval:var:html
8549                              * 
8550                              */
8551                            window.eval(match[2]);
8552                         }
8553                     }
8554                 }
8555                 var el = document.getElementById(id);
8556                 if(el){el.parentNode.removeChild(el);}
8557                 if(typeof callback == "function"){
8558                     callback();
8559                 }
8560             });
8561             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8562             return this;
8563         },
8564
8565         /**
8566          * Direct access to the UpdateManager update() method (takes the same parameters).
8567          * @param {String/Function} url The url for this request or a function to call to get the url
8568          * @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}
8569          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8570          * @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.
8571          * @return {Roo.Element} this
8572          */
8573         load : function(){
8574             var um = this.getUpdateManager();
8575             um.update.apply(um, arguments);
8576             return this;
8577         },
8578
8579         /**
8580         * Gets this element's UpdateManager
8581         * @return {Roo.UpdateManager} The UpdateManager
8582         */
8583         getUpdateManager : function(){
8584             if(!this.updateManager){
8585                 this.updateManager = new Roo.UpdateManager(this);
8586             }
8587             return this.updateManager;
8588         },
8589
8590         /**
8591          * Disables text selection for this element (normalized across browsers)
8592          * @return {Roo.Element} this
8593          */
8594         unselectable : function(){
8595             this.dom.unselectable = "on";
8596             this.swallowEvent("selectstart", true);
8597             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8598             this.addClass("x-unselectable");
8599             return this;
8600         },
8601
8602         /**
8603         * Calculates the x, y to center this element on the screen
8604         * @return {Array} The x, y values [x, y]
8605         */
8606         getCenterXY : function(){
8607             return this.getAlignToXY(document, 'c-c');
8608         },
8609
8610         /**
8611         * Centers the Element in either the viewport, or another Element.
8612         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8613         */
8614         center : function(centerIn){
8615             this.alignTo(centerIn || document, 'c-c');
8616             return this;
8617         },
8618
8619         /**
8620          * Tests various css rules/browsers to determine if this element uses a border box
8621          * @return {Boolean}
8622          */
8623         isBorderBox : function(){
8624             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8625         },
8626
8627         /**
8628          * Return a box {x, y, width, height} that can be used to set another elements
8629          * size/location to match this element.
8630          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8631          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8632          * @return {Object} box An object in the format {x, y, width, height}
8633          */
8634         getBox : function(contentBox, local){
8635             var xy;
8636             if(!local){
8637                 xy = this.getXY();
8638             }else{
8639                 var left = parseInt(this.getStyle("left"), 10) || 0;
8640                 var top = parseInt(this.getStyle("top"), 10) || 0;
8641                 xy = [left, top];
8642             }
8643             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8644             if(!contentBox){
8645                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8646             }else{
8647                 var l = this.getBorderWidth("l")+this.getPadding("l");
8648                 var r = this.getBorderWidth("r")+this.getPadding("r");
8649                 var t = this.getBorderWidth("t")+this.getPadding("t");
8650                 var b = this.getBorderWidth("b")+this.getPadding("b");
8651                 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)};
8652             }
8653             bx.right = bx.x + bx.width;
8654             bx.bottom = bx.y + bx.height;
8655             return bx;
8656         },
8657
8658         /**
8659          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8660          for more information about the sides.
8661          * @param {String} sides
8662          * @return {Number}
8663          */
8664         getFrameWidth : function(sides, onlyContentBox){
8665             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8666         },
8667
8668         /**
8669          * 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.
8670          * @param {Object} box The box to fill {x, y, width, height}
8671          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8672          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8673          * @return {Roo.Element} this
8674          */
8675         setBox : function(box, adjust, animate){
8676             var w = box.width, h = box.height;
8677             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8678                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8679                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8680             }
8681             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8682             return this;
8683         },
8684
8685         /**
8686          * Forces the browser to repaint this element
8687          * @return {Roo.Element} this
8688          */
8689          repaint : function(){
8690             var dom = this.dom;
8691             this.addClass("x-repaint");
8692             setTimeout(function(){
8693                 Roo.get(dom).removeClass("x-repaint");
8694             }, 1);
8695             return this;
8696         },
8697
8698         /**
8699          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8700          * then it returns the calculated width of the sides (see getPadding)
8701          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8702          * @return {Object/Number}
8703          */
8704         getMargins : function(side){
8705             if(!side){
8706                 return {
8707                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8708                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8709                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8710                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8711                 };
8712             }else{
8713                 return this.addStyles(side, El.margins);
8714              }
8715         },
8716
8717         // private
8718         addStyles : function(sides, styles){
8719             var val = 0, v, w;
8720             for(var i = 0, len = sides.length; i < len; i++){
8721                 v = this.getStyle(styles[sides.charAt(i)]);
8722                 if(v){
8723                      w = parseInt(v, 10);
8724                      if(w){ val += w; }
8725                 }
8726             }
8727             return val;
8728         },
8729
8730         /**
8731          * Creates a proxy element of this element
8732          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8733          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8734          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8735          * @return {Roo.Element} The new proxy element
8736          */
8737         createProxy : function(config, renderTo, matchBox){
8738             if(renderTo){
8739                 renderTo = Roo.getDom(renderTo);
8740             }else{
8741                 renderTo = document.body;
8742             }
8743             config = typeof config == "object" ?
8744                 config : {tag : "div", cls: config};
8745             var proxy = Roo.DomHelper.append(renderTo, config, true);
8746             if(matchBox){
8747                proxy.setBox(this.getBox());
8748             }
8749             return proxy;
8750         },
8751
8752         /**
8753          * Puts a mask over this element to disable user interaction. Requires core.css.
8754          * This method can only be applied to elements which accept child nodes.
8755          * @param {String} msg (optional) A message to display in the mask
8756          * @param {String} msgCls (optional) A css class to apply to the msg element
8757          * @return {Element} The mask  element
8758          */
8759         mask : function(msg, msgCls){
8760             if(this.getStyle("position") == "static"){
8761                 this.setStyle("position", "relative");
8762             }
8763             if(!this._mask){
8764                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8765             }
8766             this.addClass("x-masked");
8767             this._mask.setDisplayed(true);
8768             if(typeof msg == 'string'){
8769                 if(!this._maskMsg){
8770                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8771                 }
8772                 var mm = this._maskMsg;
8773                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8774                 mm.dom.firstChild.innerHTML = msg;
8775                 mm.setDisplayed(true);
8776                 mm.center(this);
8777             }
8778             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8779                 this._mask.setHeight(this.getHeight());
8780             }
8781             return this._mask;
8782         },
8783
8784         /**
8785          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8786          * it is cached for reuse.
8787          */
8788         unmask : function(removeEl){
8789             if(this._mask){
8790                 if(removeEl === true){
8791                     this._mask.remove();
8792                     delete this._mask;
8793                     if(this._maskMsg){
8794                         this._maskMsg.remove();
8795                         delete this._maskMsg;
8796                     }
8797                 }else{
8798                     this._mask.setDisplayed(false);
8799                     if(this._maskMsg){
8800                         this._maskMsg.setDisplayed(false);
8801                     }
8802                 }
8803             }
8804             this.removeClass("x-masked");
8805         },
8806
8807         /**
8808          * Returns true if this element is masked
8809          * @return {Boolean}
8810          */
8811         isMasked : function(){
8812             return this._mask && this._mask.isVisible();
8813         },
8814
8815         /**
8816          * Creates an iframe shim for this element to keep selects and other windowed objects from
8817          * showing through.
8818          * @return {Roo.Element} The new shim element
8819          */
8820         createShim : function(){
8821             var el = document.createElement('iframe');
8822             el.frameBorder = 'no';
8823             el.className = 'roo-shim';
8824             if(Roo.isIE && Roo.isSecure){
8825                 el.src = Roo.SSL_SECURE_URL;
8826             }
8827             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8828             shim.autoBoxAdjust = false;
8829             return shim;
8830         },
8831
8832         /**
8833          * Removes this element from the DOM and deletes it from the cache
8834          */
8835         remove : function(){
8836             if(this.dom.parentNode){
8837                 this.dom.parentNode.removeChild(this.dom);
8838             }
8839             delete El.cache[this.dom.id];
8840         },
8841
8842         /**
8843          * Sets up event handlers to add and remove a css class when the mouse is over this element
8844          * @param {String} className
8845          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8846          * mouseout events for children elements
8847          * @return {Roo.Element} this
8848          */
8849         addClassOnOver : function(className, preventFlicker){
8850             this.on("mouseover", function(){
8851                 Roo.fly(this, '_internal').addClass(className);
8852             }, this.dom);
8853             var removeFn = function(e){
8854                 if(preventFlicker !== true || !e.within(this, true)){
8855                     Roo.fly(this, '_internal').removeClass(className);
8856                 }
8857             };
8858             this.on("mouseout", removeFn, this.dom);
8859             return this;
8860         },
8861
8862         /**
8863          * Sets up event handlers to add and remove a css class when this element has the focus
8864          * @param {String} className
8865          * @return {Roo.Element} this
8866          */
8867         addClassOnFocus : function(className){
8868             this.on("focus", function(){
8869                 Roo.fly(this, '_internal').addClass(className);
8870             }, this.dom);
8871             this.on("blur", function(){
8872                 Roo.fly(this, '_internal').removeClass(className);
8873             }, this.dom);
8874             return this;
8875         },
8876         /**
8877          * 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)
8878          * @param {String} className
8879          * @return {Roo.Element} this
8880          */
8881         addClassOnClick : function(className){
8882             var dom = this.dom;
8883             this.on("mousedown", function(){
8884                 Roo.fly(dom, '_internal').addClass(className);
8885                 var d = Roo.get(document);
8886                 var fn = function(){
8887                     Roo.fly(dom, '_internal').removeClass(className);
8888                     d.removeListener("mouseup", fn);
8889                 };
8890                 d.on("mouseup", fn);
8891             });
8892             return this;
8893         },
8894
8895         /**
8896          * Stops the specified event from bubbling and optionally prevents the default action
8897          * @param {String} eventName
8898          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8899          * @return {Roo.Element} this
8900          */
8901         swallowEvent : function(eventName, preventDefault){
8902             var fn = function(e){
8903                 e.stopPropagation();
8904                 if(preventDefault){
8905                     e.preventDefault();
8906                 }
8907             };
8908             if(eventName instanceof Array){
8909                 for(var i = 0, len = eventName.length; i < len; i++){
8910                      this.on(eventName[i], fn);
8911                 }
8912                 return this;
8913             }
8914             this.on(eventName, fn);
8915             return this;
8916         },
8917
8918         /**
8919          * @private
8920          */
8921       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8922
8923         /**
8924          * Sizes this element to its parent element's dimensions performing
8925          * neccessary box adjustments.
8926          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8927          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8928          * @return {Roo.Element} this
8929          */
8930         fitToParent : function(monitorResize, targetParent) {
8931           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8932           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8933           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8934             return;
8935           }
8936           var p = Roo.get(targetParent || this.dom.parentNode);
8937           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8938           if (monitorResize === true) {
8939             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8940             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8941           }
8942           return this;
8943         },
8944
8945         /**
8946          * Gets the next sibling, skipping text nodes
8947          * @return {HTMLElement} The next sibling or null
8948          */
8949         getNextSibling : function(){
8950             var n = this.dom.nextSibling;
8951             while(n && n.nodeType != 1){
8952                 n = n.nextSibling;
8953             }
8954             return n;
8955         },
8956
8957         /**
8958          * Gets the previous sibling, skipping text nodes
8959          * @return {HTMLElement} The previous sibling or null
8960          */
8961         getPrevSibling : function(){
8962             var n = this.dom.previousSibling;
8963             while(n && n.nodeType != 1){
8964                 n = n.previousSibling;
8965             }
8966             return n;
8967         },
8968
8969
8970         /**
8971          * Appends the passed element(s) to this element
8972          * @param {String/HTMLElement/Array/Element/CompositeElement} el
8973          * @return {Roo.Element} this
8974          */
8975         appendChild: function(el){
8976             el = Roo.get(el);
8977             el.appendTo(this);
8978             return this;
8979         },
8980
8981         /**
8982          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8983          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
8984          * automatically generated with the specified attributes.
8985          * @param {HTMLElement} insertBefore (optional) a child element of this element
8986          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8987          * @return {Roo.Element} The new child element
8988          */
8989         createChild: function(config, insertBefore, returnDom){
8990             config = config || {tag:'div'};
8991             if(insertBefore){
8992                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8993             }
8994             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
8995         },
8996
8997         /**
8998          * Appends this element to the passed element
8999          * @param {String/HTMLElement/Element} el The new parent element
9000          * @return {Roo.Element} this
9001          */
9002         appendTo: function(el){
9003             el = Roo.getDom(el);
9004             el.appendChild(this.dom);
9005             return this;
9006         },
9007
9008         /**
9009          * Inserts this element before the passed element in the DOM
9010          * @param {String/HTMLElement/Element} el The element to insert before
9011          * @return {Roo.Element} this
9012          */
9013         insertBefore: function(el){
9014             el = Roo.getDom(el);
9015             el.parentNode.insertBefore(this.dom, el);
9016             return this;
9017         },
9018
9019         /**
9020          * Inserts this element after the passed element in the DOM
9021          * @param {String/HTMLElement/Element} el The element to insert after
9022          * @return {Roo.Element} this
9023          */
9024         insertAfter: function(el){
9025             el = Roo.getDom(el);
9026             el.parentNode.insertBefore(this.dom, el.nextSibling);
9027             return this;
9028         },
9029
9030         /**
9031          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9032          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9033          * @return {Roo.Element} The new child
9034          */
9035         insertFirst: function(el, returnDom){
9036             el = el || {};
9037             if(typeof el == 'object' && !el.nodeType){ // dh config
9038                 return this.createChild(el, this.dom.firstChild, returnDom);
9039             }else{
9040                 el = Roo.getDom(el);
9041                 this.dom.insertBefore(el, this.dom.firstChild);
9042                 return !returnDom ? Roo.get(el) : el;
9043             }
9044         },
9045
9046         /**
9047          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9048          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9049          * @param {String} where (optional) 'before' or 'after' defaults to before
9050          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9051          * @return {Roo.Element} the inserted Element
9052          */
9053         insertSibling: function(el, where, returnDom){
9054             where = where ? where.toLowerCase() : 'before';
9055             el = el || {};
9056             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9057
9058             if(typeof el == 'object' && !el.nodeType){ // dh config
9059                 if(where == 'after' && !this.dom.nextSibling){
9060                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9061                 }else{
9062                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9063                 }
9064
9065             }else{
9066                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9067                             where == 'before' ? this.dom : this.dom.nextSibling);
9068                 if(!returnDom){
9069                     rt = Roo.get(rt);
9070                 }
9071             }
9072             return rt;
9073         },
9074
9075         /**
9076          * Creates and wraps this element with another element
9077          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9078          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9079          * @return {HTMLElement/Element} The newly created wrapper element
9080          */
9081         wrap: function(config, returnDom){
9082             if(!config){
9083                 config = {tag: "div"};
9084             }
9085             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9086             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9087             return newEl;
9088         },
9089
9090         /**
9091          * Replaces the passed element with this element
9092          * @param {String/HTMLElement/Element} el The element to replace
9093          * @return {Roo.Element} this
9094          */
9095         replace: function(el){
9096             el = Roo.get(el);
9097             this.insertBefore(el);
9098             el.remove();
9099             return this;
9100         },
9101
9102         /**
9103          * Inserts an html fragment into this element
9104          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9105          * @param {String} html The HTML fragment
9106          * @param {Boolean} returnEl True to return an Roo.Element
9107          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9108          */
9109         insertHtml : function(where, html, returnEl){
9110             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9111             return returnEl ? Roo.get(el) : el;
9112         },
9113
9114         /**
9115          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9116          * @param {Object} o The object with the attributes
9117          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9118          * @return {Roo.Element} this
9119          */
9120         set : function(o, useSet){
9121             var el = this.dom;
9122             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9123             for(var attr in o){
9124                 if(attr == "style" || typeof o[attr] == "function") continue;
9125                 if(attr=="cls"){
9126                     el.className = o["cls"];
9127                 }else{
9128                     if(useSet) el.setAttribute(attr, o[attr]);
9129                     else el[attr] = o[attr];
9130                 }
9131             }
9132             if(o.style){
9133                 Roo.DomHelper.applyStyles(el, o.style);
9134             }
9135             return this;
9136         },
9137
9138         /**
9139          * Convenience method for constructing a KeyMap
9140          * @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:
9141          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9142          * @param {Function} fn The function to call
9143          * @param {Object} scope (optional) The scope of the function
9144          * @return {Roo.KeyMap} The KeyMap created
9145          */
9146         addKeyListener : function(key, fn, scope){
9147             var config;
9148             if(typeof key != "object" || key instanceof Array){
9149                 config = {
9150                     key: key,
9151                     fn: fn,
9152                     scope: scope
9153                 };
9154             }else{
9155                 config = {
9156                     key : key.key,
9157                     shift : key.shift,
9158                     ctrl : key.ctrl,
9159                     alt : key.alt,
9160                     fn: fn,
9161                     scope: scope
9162                 };
9163             }
9164             return new Roo.KeyMap(this, config);
9165         },
9166
9167         /**
9168          * Creates a KeyMap for this element
9169          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9170          * @return {Roo.KeyMap} The KeyMap created
9171          */
9172         addKeyMap : function(config){
9173             return new Roo.KeyMap(this, config);
9174         },
9175
9176         /**
9177          * Returns true if this element is scrollable.
9178          * @return {Boolean}
9179          */
9180          isScrollable : function(){
9181             var dom = this.dom;
9182             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9183         },
9184
9185         /**
9186          * 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().
9187          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9188          * @param {Number} value The new scroll value
9189          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9190          * @return {Element} this
9191          */
9192
9193         scrollTo : function(side, value, animate){
9194             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9195             if(!animate || !A){
9196                 this.dom[prop] = value;
9197             }else{
9198                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9199                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9200             }
9201             return this;
9202         },
9203
9204         /**
9205          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9206          * within this element's scrollable range.
9207          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9208          * @param {Number} distance How far to scroll the element in pixels
9209          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9210          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9211          * was scrolled as far as it could go.
9212          */
9213          scroll : function(direction, distance, animate){
9214              if(!this.isScrollable()){
9215                  return;
9216              }
9217              var el = this.dom;
9218              var l = el.scrollLeft, t = el.scrollTop;
9219              var w = el.scrollWidth, h = el.scrollHeight;
9220              var cw = el.clientWidth, ch = el.clientHeight;
9221              direction = direction.toLowerCase();
9222              var scrolled = false;
9223              var a = this.preanim(arguments, 2);
9224              switch(direction){
9225                  case "l":
9226                  case "left":
9227                      if(w - l > cw){
9228                          var v = Math.min(l + distance, w-cw);
9229                          this.scrollTo("left", v, a);
9230                          scrolled = true;
9231                      }
9232                      break;
9233                 case "r":
9234                 case "right":
9235                      if(l > 0){
9236                          var v = Math.max(l - distance, 0);
9237                          this.scrollTo("left", v, a);
9238                          scrolled = true;
9239                      }
9240                      break;
9241                 case "t":
9242                 case "top":
9243                 case "up":
9244                      if(t > 0){
9245                          var v = Math.max(t - distance, 0);
9246                          this.scrollTo("top", v, a);
9247                          scrolled = true;
9248                      }
9249                      break;
9250                 case "b":
9251                 case "bottom":
9252                 case "down":
9253                      if(h - t > ch){
9254                          var v = Math.min(t + distance, h-ch);
9255                          this.scrollTo("top", v, a);
9256                          scrolled = true;
9257                      }
9258                      break;
9259              }
9260              return scrolled;
9261         },
9262
9263         /**
9264          * Translates the passed page coordinates into left/top css values for this element
9265          * @param {Number/Array} x The page x or an array containing [x, y]
9266          * @param {Number} y The page y
9267          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9268          */
9269         translatePoints : function(x, y){
9270             if(typeof x == 'object' || x instanceof Array){
9271                 y = x[1]; x = x[0];
9272             }
9273             var p = this.getStyle('position');
9274             var o = this.getXY();
9275
9276             var l = parseInt(this.getStyle('left'), 10);
9277             var t = parseInt(this.getStyle('top'), 10);
9278
9279             if(isNaN(l)){
9280                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9281             }
9282             if(isNaN(t)){
9283                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9284             }
9285
9286             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9287         },
9288
9289         /**
9290          * Returns the current scroll position of the element.
9291          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9292          */
9293         getScroll : function(){
9294             var d = this.dom, doc = document;
9295             if(d == doc || d == doc.body){
9296                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9297                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9298                 return {left: l, top: t};
9299             }else{
9300                 return {left: d.scrollLeft, top: d.scrollTop};
9301             }
9302         },
9303
9304         /**
9305          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9306          * are convert to standard 6 digit hex color.
9307          * @param {String} attr The css attribute
9308          * @param {String} defaultValue The default value to use when a valid color isn't found
9309          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9310          * YUI color anims.
9311          */
9312         getColor : function(attr, defaultValue, prefix){
9313             var v = this.getStyle(attr);
9314             if(!v || v == "transparent" || v == "inherit") {
9315                 return defaultValue;
9316             }
9317             var color = typeof prefix == "undefined" ? "#" : prefix;
9318             if(v.substr(0, 4) == "rgb("){
9319                 var rvs = v.slice(4, v.length -1).split(",");
9320                 for(var i = 0; i < 3; i++){
9321                     var h = parseInt(rvs[i]).toString(16);
9322                     if(h < 16){
9323                         h = "0" + h;
9324                     }
9325                     color += h;
9326                 }
9327             } else {
9328                 if(v.substr(0, 1) == "#"){
9329                     if(v.length == 4) {
9330                         for(var i = 1; i < 4; i++){
9331                             var c = v.charAt(i);
9332                             color +=  c + c;
9333                         }
9334                     }else if(v.length == 7){
9335                         color += v.substr(1);
9336                     }
9337                 }
9338             }
9339             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9340         },
9341
9342         /**
9343          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9344          * gradient background, rounded corners and a 4-way shadow.
9345          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9346          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9347          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9348          * @return {Roo.Element} this
9349          */
9350         boxWrap : function(cls){
9351             cls = cls || 'x-box';
9352             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9353             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9354             return el;
9355         },
9356
9357         /**
9358          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9359          * @param {String} namespace The namespace in which to look for the attribute
9360          * @param {String} name The attribute name
9361          * @return {String} The attribute value
9362          */
9363         getAttributeNS : Roo.isIE ? function(ns, name){
9364             var d = this.dom;
9365             var type = typeof d[ns+":"+name];
9366             if(type != 'undefined' && type != 'unknown'){
9367                 return d[ns+":"+name];
9368             }
9369             return d[name];
9370         } : function(ns, name){
9371             var d = this.dom;
9372             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9373         }
9374     };
9375
9376     var ep = El.prototype;
9377
9378     /**
9379      * Appends an event handler (Shorthand for addListener)
9380      * @param {String}   eventName     The type of event to append
9381      * @param {Function} fn        The method the event invokes
9382      * @param {Object} scope       (optional) The scope (this object) of the fn
9383      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9384      * @method
9385      */
9386     ep.on = ep.addListener;
9387         // backwards compat
9388     ep.mon = ep.addListener;
9389
9390     /**
9391      * Removes an event handler from this element (shorthand for removeListener)
9392      * @param {String} eventName the type of event to remove
9393      * @param {Function} fn the method the event invokes
9394      * @return {Roo.Element} this
9395      * @method
9396      */
9397     ep.un = ep.removeListener;
9398
9399     /**
9400      * true to automatically adjust width and height settings for box-model issues (default to true)
9401      */
9402     ep.autoBoxAdjust = true;
9403
9404     // private
9405     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9406
9407     // private
9408     El.addUnits = function(v, defaultUnit){
9409         if(v === "" || v == "auto"){
9410             return v;
9411         }
9412         if(v === undefined){
9413             return '';
9414         }
9415         if(typeof v == "number" || !El.unitPattern.test(v)){
9416             return v + (defaultUnit || 'px');
9417         }
9418         return v;
9419     };
9420
9421     // special markup used throughout Roo when box wrapping elements
9422     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>';
9423     /**
9424      * Visibility mode constant - Use visibility to hide element
9425      * @static
9426      * @type Number
9427      */
9428     El.VISIBILITY = 1;
9429     /**
9430      * Visibility mode constant - Use display to hide element
9431      * @static
9432      * @type Number
9433      */
9434     El.DISPLAY = 2;
9435
9436     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9437     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9438     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9439
9440
9441
9442     /**
9443      * @private
9444      */
9445     El.cache = {};
9446
9447     var docEl;
9448
9449     /**
9450      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9451      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9452      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9453      * @return {Element} The Element object
9454      * @static
9455      */
9456     El.get = function(el){
9457         var ex, elm, id;
9458         if(!el){ return null; }
9459         if(typeof el == "string"){ // element id
9460             if(!(elm = document.getElementById(el))){
9461                 return null;
9462             }
9463             if(ex = El.cache[el]){
9464                 ex.dom = elm;
9465             }else{
9466                 ex = El.cache[el] = new El(elm);
9467             }
9468             return ex;
9469         }else if(el.tagName){ // dom element
9470             if(!(id = el.id)){
9471                 id = Roo.id(el);
9472             }
9473             if(ex = El.cache[id]){
9474                 ex.dom = el;
9475             }else{
9476                 ex = El.cache[id] = new El(el);
9477             }
9478             return ex;
9479         }else if(el instanceof El){
9480             if(el != docEl){
9481                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9482                                                               // catch case where it hasn't been appended
9483                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9484             }
9485             return el;
9486         }else if(el.isComposite){
9487             return el;
9488         }else if(el instanceof Array){
9489             return El.select(el);
9490         }else if(el == document){
9491             // create a bogus element object representing the document object
9492             if(!docEl){
9493                 var f = function(){};
9494                 f.prototype = El.prototype;
9495                 docEl = new f();
9496                 docEl.dom = document;
9497             }
9498             return docEl;
9499         }
9500         return null;
9501     };
9502
9503     // private
9504     El.uncache = function(el){
9505         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9506             if(a[i]){
9507                 delete El.cache[a[i].id || a[i]];
9508             }
9509         }
9510     };
9511
9512     // private
9513     // Garbage collection - uncache elements/purge listeners on orphaned elements
9514     // so we don't hold a reference and cause the browser to retain them
9515     El.garbageCollect = function(){
9516         if(!Roo.enableGarbageCollector){
9517             clearInterval(El.collectorThread);
9518             return;
9519         }
9520         for(var eid in El.cache){
9521             var el = El.cache[eid], d = el.dom;
9522             // -------------------------------------------------------
9523             // Determining what is garbage:
9524             // -------------------------------------------------------
9525             // !d
9526             // dom node is null, definitely garbage
9527             // -------------------------------------------------------
9528             // !d.parentNode
9529             // no parentNode == direct orphan, definitely garbage
9530             // -------------------------------------------------------
9531             // !d.offsetParent && !document.getElementById(eid)
9532             // display none elements have no offsetParent so we will
9533             // also try to look it up by it's id. However, check
9534             // offsetParent first so we don't do unneeded lookups.
9535             // This enables collection of elements that are not orphans
9536             // directly, but somewhere up the line they have an orphan
9537             // parent.
9538             // -------------------------------------------------------
9539             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9540                 delete El.cache[eid];
9541                 if(d && Roo.enableListenerCollection){
9542                     E.purgeElement(d);
9543                 }
9544             }
9545         }
9546     }
9547     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9548
9549
9550     // dom is optional
9551     El.Flyweight = function(dom){
9552         this.dom = dom;
9553     };
9554     El.Flyweight.prototype = El.prototype;
9555
9556     El._flyweights = {};
9557     /**
9558      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9559      * the dom node can be overwritten by other code.
9560      * @param {String/HTMLElement} el The dom node or id
9561      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9562      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9563      * @static
9564      * @return {Element} The shared Element object
9565      */
9566     El.fly = function(el, named){
9567         named = named || '_global';
9568         el = Roo.getDom(el);
9569         if(!el){
9570             return null;
9571         }
9572         if(!El._flyweights[named]){
9573             El._flyweights[named] = new El.Flyweight();
9574         }
9575         El._flyweights[named].dom = el;
9576         return El._flyweights[named];
9577     };
9578
9579     /**
9580      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9581      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9582      * Shorthand of {@link Roo.Element#get}
9583      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9584      * @return {Element} The Element object
9585      * @member Roo
9586      * @method get
9587      */
9588     Roo.get = El.get;
9589     /**
9590      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9591      * the dom node can be overwritten by other code.
9592      * Shorthand of {@link Roo.Element#fly}
9593      * @param {String/HTMLElement} el The dom node or id
9594      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9595      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9596      * @static
9597      * @return {Element} The shared Element object
9598      * @member Roo
9599      * @method fly
9600      */
9601     Roo.fly = El.fly;
9602
9603     // speedy lookup for elements never to box adjust
9604     var noBoxAdjust = Roo.isStrict ? {
9605         select:1
9606     } : {
9607         input:1, select:1, textarea:1
9608     };
9609     if(Roo.isIE || Roo.isGecko){
9610         noBoxAdjust['button'] = 1;
9611     }
9612
9613
9614     Roo.EventManager.on(window, 'unload', function(){
9615         delete El.cache;
9616         delete El._flyweights;
9617     });
9618 })();
9619
9620
9621
9622
9623 if(Roo.DomQuery){
9624     Roo.Element.selectorFunction = Roo.DomQuery.select;
9625 }
9626
9627 Roo.Element.select = function(selector, unique, root){
9628     var els;
9629     if(typeof selector == "string"){
9630         els = Roo.Element.selectorFunction(selector, root);
9631     }else if(selector.length !== undefined){
9632         els = selector;
9633     }else{
9634         throw "Invalid selector";
9635     }
9636     if(unique === true){
9637         return new Roo.CompositeElement(els);
9638     }else{
9639         return new Roo.CompositeElementLite(els);
9640     }
9641 };
9642 /**
9643  * Selects elements based on the passed CSS selector to enable working on them as 1.
9644  * @param {String/Array} selector The CSS selector or an array of elements
9645  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9646  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9647  * @return {CompositeElementLite/CompositeElement}
9648  * @member Roo
9649  * @method select
9650  */
9651 Roo.select = Roo.Element.select;
9652
9653
9654
9655
9656
9657
9658
9659
9660
9661
9662
9663
9664
9665
9666 /*
9667  * Based on:
9668  * Ext JS Library 1.1.1
9669  * Copyright(c) 2006-2007, Ext JS, LLC.
9670  *
9671  * Originally Released Under LGPL - original licence link has changed is not relivant.
9672  *
9673  * Fork - LGPL
9674  * <script type="text/javascript">
9675  */
9676
9677
9678
9679 //Notifies Element that fx methods are available
9680 Roo.enableFx = true;
9681
9682 /**
9683  * @class Roo.Fx
9684  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9685  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9686  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9687  * Element effects to work.</p><br/>
9688  *
9689  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9690  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9691  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9692  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9693  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9694  * expected results and should be done with care.</p><br/>
9695  *
9696  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9697  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9698 <pre>
9699 Value  Description
9700 -----  -----------------------------
9701 tl     The top left corner
9702 t      The center of the top edge
9703 tr     The top right corner
9704 l      The center of the left edge
9705 r      The center of the right edge
9706 bl     The bottom left corner
9707 b      The center of the bottom edge
9708 br     The bottom right corner
9709 </pre>
9710  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9711  * below are common options that can be passed to any Fx method.</b>
9712  * @cfg {Function} callback A function called when the effect is finished
9713  * @cfg {Object} scope The scope of the effect function
9714  * @cfg {String} easing A valid Easing value for the effect
9715  * @cfg {String} afterCls A css class to apply after the effect
9716  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9717  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9718  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9719  * effects that end with the element being visually hidden, ignored otherwise)
9720  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9721  * a function which returns such a specification that will be applied to the Element after the effect finishes
9722  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9723  * @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
9724  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9725  */
9726 Roo.Fx = {
9727         /**
9728          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9729          * origin for the slide effect.  This function automatically handles wrapping the element with
9730          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9731          * Usage:
9732          *<pre><code>
9733 // default: slide the element in from the top
9734 el.slideIn();
9735
9736 // custom: slide the element in from the right with a 2-second duration
9737 el.slideIn('r', { duration: 2 });
9738
9739 // common config options shown with default values
9740 el.slideIn('t', {
9741     easing: 'easeOut',
9742     duration: .5
9743 });
9744 </code></pre>
9745          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9746          * @param {Object} options (optional) Object literal with any of the Fx config options
9747          * @return {Roo.Element} The Element
9748          */
9749     slideIn : function(anchor, o){
9750         var el = this.getFxEl();
9751         o = o || {};
9752
9753         el.queueFx(o, function(){
9754
9755             anchor = anchor || "t";
9756
9757             // fix display to visibility
9758             this.fixDisplay();
9759
9760             // restore values after effect
9761             var r = this.getFxRestore();
9762             var b = this.getBox();
9763             // fixed size for slide
9764             this.setSize(b);
9765
9766             // wrap if needed
9767             var wrap = this.fxWrap(r.pos, o, "hidden");
9768
9769             var st = this.dom.style;
9770             st.visibility = "visible";
9771             st.position = "absolute";
9772
9773             // clear out temp styles after slide and unwrap
9774             var after = function(){
9775                 el.fxUnwrap(wrap, r.pos, o);
9776                 st.width = r.width;
9777                 st.height = r.height;
9778                 el.afterFx(o);
9779             };
9780             // time to calc the positions
9781             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9782
9783             switch(anchor.toLowerCase()){
9784                 case "t":
9785                     wrap.setSize(b.width, 0);
9786                     st.left = st.bottom = "0";
9787                     a = {height: bh};
9788                 break;
9789                 case "l":
9790                     wrap.setSize(0, b.height);
9791                     st.right = st.top = "0";
9792                     a = {width: bw};
9793                 break;
9794                 case "r":
9795                     wrap.setSize(0, b.height);
9796                     wrap.setX(b.right);
9797                     st.left = st.top = "0";
9798                     a = {width: bw, points: pt};
9799                 break;
9800                 case "b":
9801                     wrap.setSize(b.width, 0);
9802                     wrap.setY(b.bottom);
9803                     st.left = st.top = "0";
9804                     a = {height: bh, points: pt};
9805                 break;
9806                 case "tl":
9807                     wrap.setSize(0, 0);
9808                     st.right = st.bottom = "0";
9809                     a = {width: bw, height: bh};
9810                 break;
9811                 case "bl":
9812                     wrap.setSize(0, 0);
9813                     wrap.setY(b.y+b.height);
9814                     st.right = st.top = "0";
9815                     a = {width: bw, height: bh, points: pt};
9816                 break;
9817                 case "br":
9818                     wrap.setSize(0, 0);
9819                     wrap.setXY([b.right, b.bottom]);
9820                     st.left = st.top = "0";
9821                     a = {width: bw, height: bh, points: pt};
9822                 break;
9823                 case "tr":
9824                     wrap.setSize(0, 0);
9825                     wrap.setX(b.x+b.width);
9826                     st.left = st.bottom = "0";
9827                     a = {width: bw, height: bh, points: pt};
9828                 break;
9829             }
9830             this.dom.style.visibility = "visible";
9831             wrap.show();
9832
9833             arguments.callee.anim = wrap.fxanim(a,
9834                 o,
9835                 'motion',
9836                 .5,
9837                 'easeOut', after);
9838         });
9839         return this;
9840     },
9841     
9842         /**
9843          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9844          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9845          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9846          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9847          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9848          * Usage:
9849          *<pre><code>
9850 // default: slide the element out to the top
9851 el.slideOut();
9852
9853 // custom: slide the element out to the right with a 2-second duration
9854 el.slideOut('r', { duration: 2 });
9855
9856 // common config options shown with default values
9857 el.slideOut('t', {
9858     easing: 'easeOut',
9859     duration: .5,
9860     remove: false,
9861     useDisplay: false
9862 });
9863 </code></pre>
9864          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9865          * @param {Object} options (optional) Object literal with any of the Fx config options
9866          * @return {Roo.Element} The Element
9867          */
9868     slideOut : function(anchor, o){
9869         var el = this.getFxEl();
9870         o = o || {};
9871
9872         el.queueFx(o, function(){
9873
9874             anchor = anchor || "t";
9875
9876             // restore values after effect
9877             var r = this.getFxRestore();
9878             
9879             var b = this.getBox();
9880             // fixed size for slide
9881             this.setSize(b);
9882
9883             // wrap if needed
9884             var wrap = this.fxWrap(r.pos, o, "visible");
9885
9886             var st = this.dom.style;
9887             st.visibility = "visible";
9888             st.position = "absolute";
9889
9890             wrap.setSize(b);
9891
9892             var after = function(){
9893                 if(o.useDisplay){
9894                     el.setDisplayed(false);
9895                 }else{
9896                     el.hide();
9897                 }
9898
9899                 el.fxUnwrap(wrap, r.pos, o);
9900
9901                 st.width = r.width;
9902                 st.height = r.height;
9903
9904                 el.afterFx(o);
9905             };
9906
9907             var a, zero = {to: 0};
9908             switch(anchor.toLowerCase()){
9909                 case "t":
9910                     st.left = st.bottom = "0";
9911                     a = {height: zero};
9912                 break;
9913                 case "l":
9914                     st.right = st.top = "0";
9915                     a = {width: zero};
9916                 break;
9917                 case "r":
9918                     st.left = st.top = "0";
9919                     a = {width: zero, points: {to:[b.right, b.y]}};
9920                 break;
9921                 case "b":
9922                     st.left = st.top = "0";
9923                     a = {height: zero, points: {to:[b.x, b.bottom]}};
9924                 break;
9925                 case "tl":
9926                     st.right = st.bottom = "0";
9927                     a = {width: zero, height: zero};
9928                 break;
9929                 case "bl":
9930                     st.right = st.top = "0";
9931                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9932                 break;
9933                 case "br":
9934                     st.left = st.top = "0";
9935                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9936                 break;
9937                 case "tr":
9938                     st.left = st.bottom = "0";
9939                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9940                 break;
9941             }
9942
9943             arguments.callee.anim = wrap.fxanim(a,
9944                 o,
9945                 'motion',
9946                 .5,
9947                 "easeOut", after);
9948         });
9949         return this;
9950     },
9951
9952         /**
9953          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
9954          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
9955          * The element must be removed from the DOM using the 'remove' config option if desired.
9956          * Usage:
9957          *<pre><code>
9958 // default
9959 el.puff();
9960
9961 // common config options shown with default values
9962 el.puff({
9963     easing: 'easeOut',
9964     duration: .5,
9965     remove: false,
9966     useDisplay: false
9967 });
9968 </code></pre>
9969          * @param {Object} options (optional) Object literal with any of the Fx config options
9970          * @return {Roo.Element} The Element
9971          */
9972     puff : function(o){
9973         var el = this.getFxEl();
9974         o = o || {};
9975
9976         el.queueFx(o, function(){
9977             this.clearOpacity();
9978             this.show();
9979
9980             // restore values after effect
9981             var r = this.getFxRestore();
9982             var st = this.dom.style;
9983
9984             var after = function(){
9985                 if(o.useDisplay){
9986                     el.setDisplayed(false);
9987                 }else{
9988                     el.hide();
9989                 }
9990
9991                 el.clearOpacity();
9992
9993                 el.setPositioning(r.pos);
9994                 st.width = r.width;
9995                 st.height = r.height;
9996                 st.fontSize = '';
9997                 el.afterFx(o);
9998             };
9999
10000             var width = this.getWidth();
10001             var height = this.getHeight();
10002
10003             arguments.callee.anim = this.fxanim({
10004                     width : {to: this.adjustWidth(width * 2)},
10005                     height : {to: this.adjustHeight(height * 2)},
10006                     points : {by: [-(width * .5), -(height * .5)]},
10007                     opacity : {to: 0},
10008                     fontSize: {to:200, unit: "%"}
10009                 },
10010                 o,
10011                 'motion',
10012                 .5,
10013                 "easeOut", after);
10014         });
10015         return this;
10016     },
10017
10018         /**
10019          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10020          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10021          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10022          * Usage:
10023          *<pre><code>
10024 // default
10025 el.switchOff();
10026
10027 // all config options shown with default values
10028 el.switchOff({
10029     easing: 'easeIn',
10030     duration: .3,
10031     remove: false,
10032     useDisplay: false
10033 });
10034 </code></pre>
10035          * @param {Object} options (optional) Object literal with any of the Fx config options
10036          * @return {Roo.Element} The Element
10037          */
10038     switchOff : function(o){
10039         var el = this.getFxEl();
10040         o = o || {};
10041
10042         el.queueFx(o, function(){
10043             this.clearOpacity();
10044             this.clip();
10045
10046             // restore values after effect
10047             var r = this.getFxRestore();
10048             var st = this.dom.style;
10049
10050             var after = function(){
10051                 if(o.useDisplay){
10052                     el.setDisplayed(false);
10053                 }else{
10054                     el.hide();
10055                 }
10056
10057                 el.clearOpacity();
10058                 el.setPositioning(r.pos);
10059                 st.width = r.width;
10060                 st.height = r.height;
10061
10062                 el.afterFx(o);
10063             };
10064
10065             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10066                 this.clearOpacity();
10067                 (function(){
10068                     this.fxanim({
10069                         height:{to:1},
10070                         points:{by:[0, this.getHeight() * .5]}
10071                     }, o, 'motion', 0.3, 'easeIn', after);
10072                 }).defer(100, this);
10073             });
10074         });
10075         return this;
10076     },
10077
10078     /**
10079      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10080      * changed using the "attr" config option) and then fading back to the original color. If no original
10081      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10082      * Usage:
10083 <pre><code>
10084 // default: highlight background to yellow
10085 el.highlight();
10086
10087 // custom: highlight foreground text to blue for 2 seconds
10088 el.highlight("0000ff", { attr: 'color', duration: 2 });
10089
10090 // common config options shown with default values
10091 el.highlight("ffff9c", {
10092     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10093     endColor: (current color) or "ffffff",
10094     easing: 'easeIn',
10095     duration: 1
10096 });
10097 </code></pre>
10098      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10099      * @param {Object} options (optional) Object literal with any of the Fx config options
10100      * @return {Roo.Element} The Element
10101      */ 
10102     highlight : function(color, o){
10103         var el = this.getFxEl();
10104         o = o || {};
10105
10106         el.queueFx(o, function(){
10107             color = color || "ffff9c";
10108             attr = o.attr || "backgroundColor";
10109
10110             this.clearOpacity();
10111             this.show();
10112
10113             var origColor = this.getColor(attr);
10114             var restoreColor = this.dom.style[attr];
10115             endColor = (o.endColor || origColor) || "ffffff";
10116
10117             var after = function(){
10118                 el.dom.style[attr] = restoreColor;
10119                 el.afterFx(o);
10120             };
10121
10122             var a = {};
10123             a[attr] = {from: color, to: endColor};
10124             arguments.callee.anim = this.fxanim(a,
10125                 o,
10126                 'color',
10127                 1,
10128                 'easeIn', after);
10129         });
10130         return this;
10131     },
10132
10133    /**
10134     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10135     * Usage:
10136 <pre><code>
10137 // default: a single light blue ripple
10138 el.frame();
10139
10140 // custom: 3 red ripples lasting 3 seconds total
10141 el.frame("ff0000", 3, { duration: 3 });
10142
10143 // common config options shown with default values
10144 el.frame("C3DAF9", 1, {
10145     duration: 1 //duration of entire animation (not each individual ripple)
10146     // Note: Easing is not configurable and will be ignored if included
10147 });
10148 </code></pre>
10149     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10150     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10151     * @param {Object} options (optional) Object literal with any of the Fx config options
10152     * @return {Roo.Element} The Element
10153     */
10154     frame : function(color, count, o){
10155         var el = this.getFxEl();
10156         o = o || {};
10157
10158         el.queueFx(o, function(){
10159             color = color || "#C3DAF9";
10160             if(color.length == 6){
10161                 color = "#" + color;
10162             }
10163             count = count || 1;
10164             duration = o.duration || 1;
10165             this.show();
10166
10167             var b = this.getBox();
10168             var animFn = function(){
10169                 var proxy = this.createProxy({
10170
10171                      style:{
10172                         visbility:"hidden",
10173                         position:"absolute",
10174                         "z-index":"35000", // yee haw
10175                         border:"0px solid " + color
10176                      }
10177                   });
10178                 var scale = Roo.isBorderBox ? 2 : 1;
10179                 proxy.animate({
10180                     top:{from:b.y, to:b.y - 20},
10181                     left:{from:b.x, to:b.x - 20},
10182                     borderWidth:{from:0, to:10},
10183                     opacity:{from:1, to:0},
10184                     height:{from:b.height, to:(b.height + (20*scale))},
10185                     width:{from:b.width, to:(b.width + (20*scale))}
10186                 }, duration, function(){
10187                     proxy.remove();
10188                 });
10189                 if(--count > 0){
10190                      animFn.defer((duration/2)*1000, this);
10191                 }else{
10192                     el.afterFx(o);
10193                 }
10194             };
10195             animFn.call(this);
10196         });
10197         return this;
10198     },
10199
10200    /**
10201     * Creates a pause before any subsequent queued effects begin.  If there are
10202     * no effects queued after the pause it will have no effect.
10203     * Usage:
10204 <pre><code>
10205 el.pause(1);
10206 </code></pre>
10207     * @param {Number} seconds The length of time to pause (in seconds)
10208     * @return {Roo.Element} The Element
10209     */
10210     pause : function(seconds){
10211         var el = this.getFxEl();
10212         var o = {};
10213
10214         el.queueFx(o, function(){
10215             setTimeout(function(){
10216                 el.afterFx(o);
10217             }, seconds * 1000);
10218         });
10219         return this;
10220     },
10221
10222    /**
10223     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10224     * using the "endOpacity" config option.
10225     * Usage:
10226 <pre><code>
10227 // default: fade in from opacity 0 to 100%
10228 el.fadeIn();
10229
10230 // custom: fade in from opacity 0 to 75% over 2 seconds
10231 el.fadeIn({ endOpacity: .75, duration: 2});
10232
10233 // common config options shown with default values
10234 el.fadeIn({
10235     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10236     easing: 'easeOut',
10237     duration: .5
10238 });
10239 </code></pre>
10240     * @param {Object} options (optional) Object literal with any of the Fx config options
10241     * @return {Roo.Element} The Element
10242     */
10243     fadeIn : function(o){
10244         var el = this.getFxEl();
10245         o = o || {};
10246         el.queueFx(o, function(){
10247             this.setOpacity(0);
10248             this.fixDisplay();
10249             this.dom.style.visibility = 'visible';
10250             var to = o.endOpacity || 1;
10251             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10252                 o, null, .5, "easeOut", function(){
10253                 if(to == 1){
10254                     this.clearOpacity();
10255                 }
10256                 el.afterFx(o);
10257             });
10258         });
10259         return this;
10260     },
10261
10262    /**
10263     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10264     * using the "endOpacity" config option.
10265     * Usage:
10266 <pre><code>
10267 // default: fade out from the element's current opacity to 0
10268 el.fadeOut();
10269
10270 // custom: fade out from the element's current opacity to 25% over 2 seconds
10271 el.fadeOut({ endOpacity: .25, duration: 2});
10272
10273 // common config options shown with default values
10274 el.fadeOut({
10275     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10276     easing: 'easeOut',
10277     duration: .5
10278     remove: false,
10279     useDisplay: false
10280 });
10281 </code></pre>
10282     * @param {Object} options (optional) Object literal with any of the Fx config options
10283     * @return {Roo.Element} The Element
10284     */
10285     fadeOut : function(o){
10286         var el = this.getFxEl();
10287         o = o || {};
10288         el.queueFx(o, function(){
10289             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10290                 o, null, .5, "easeOut", function(){
10291                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10292                      this.dom.style.display = "none";
10293                 }else{
10294                      this.dom.style.visibility = "hidden";
10295                 }
10296                 this.clearOpacity();
10297                 el.afterFx(o);
10298             });
10299         });
10300         return this;
10301     },
10302
10303    /**
10304     * Animates the transition of an element's dimensions from a starting height/width
10305     * to an ending height/width.
10306     * Usage:
10307 <pre><code>
10308 // change height and width to 100x100 pixels
10309 el.scale(100, 100);
10310
10311 // common config options shown with default values.  The height and width will default to
10312 // the element's existing values if passed as null.
10313 el.scale(
10314     [element's width],
10315     [element's height], {
10316     easing: 'easeOut',
10317     duration: .35
10318 });
10319 </code></pre>
10320     * @param {Number} width  The new width (pass undefined to keep the original width)
10321     * @param {Number} height  The new height (pass undefined to keep the original height)
10322     * @param {Object} options (optional) Object literal with any of the Fx config options
10323     * @return {Roo.Element} The Element
10324     */
10325     scale : function(w, h, o){
10326         this.shift(Roo.apply({}, o, {
10327             width: w,
10328             height: h
10329         }));
10330         return this;
10331     },
10332
10333    /**
10334     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10335     * Any of these properties not specified in the config object will not be changed.  This effect 
10336     * requires that at least one new dimension, position or opacity setting must be passed in on
10337     * the config object in order for the function to have any effect.
10338     * Usage:
10339 <pre><code>
10340 // slide the element horizontally to x position 200 while changing the height and opacity
10341 el.shift({ x: 200, height: 50, opacity: .8 });
10342
10343 // common config options shown with default values.
10344 el.shift({
10345     width: [element's width],
10346     height: [element's height],
10347     x: [element's x position],
10348     y: [element's y position],
10349     opacity: [element's opacity],
10350     easing: 'easeOut',
10351     duration: .35
10352 });
10353 </code></pre>
10354     * @param {Object} options  Object literal with any of the Fx config options
10355     * @return {Roo.Element} The Element
10356     */
10357     shift : function(o){
10358         var el = this.getFxEl();
10359         o = o || {};
10360         el.queueFx(o, function(){
10361             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10362             if(w !== undefined){
10363                 a.width = {to: this.adjustWidth(w)};
10364             }
10365             if(h !== undefined){
10366                 a.height = {to: this.adjustHeight(h)};
10367             }
10368             if(x !== undefined || y !== undefined){
10369                 a.points = {to: [
10370                     x !== undefined ? x : this.getX(),
10371                     y !== undefined ? y : this.getY()
10372                 ]};
10373             }
10374             if(op !== undefined){
10375                 a.opacity = {to: op};
10376             }
10377             if(o.xy !== undefined){
10378                 a.points = {to: o.xy};
10379             }
10380             arguments.callee.anim = this.fxanim(a,
10381                 o, 'motion', .35, "easeOut", function(){
10382                 el.afterFx(o);
10383             });
10384         });
10385         return this;
10386     },
10387
10388         /**
10389          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10390          * ending point of the effect.
10391          * Usage:
10392          *<pre><code>
10393 // default: slide the element downward while fading out
10394 el.ghost();
10395
10396 // custom: slide the element out to the right with a 2-second duration
10397 el.ghost('r', { duration: 2 });
10398
10399 // common config options shown with default values
10400 el.ghost('b', {
10401     easing: 'easeOut',
10402     duration: .5
10403     remove: false,
10404     useDisplay: false
10405 });
10406 </code></pre>
10407          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10408          * @param {Object} options (optional) Object literal with any of the Fx config options
10409          * @return {Roo.Element} The Element
10410          */
10411     ghost : function(anchor, o){
10412         var el = this.getFxEl();
10413         o = o || {};
10414
10415         el.queueFx(o, function(){
10416             anchor = anchor || "b";
10417
10418             // restore values after effect
10419             var r = this.getFxRestore();
10420             var w = this.getWidth(),
10421                 h = this.getHeight();
10422
10423             var st = this.dom.style;
10424
10425             var after = function(){
10426                 if(o.useDisplay){
10427                     el.setDisplayed(false);
10428                 }else{
10429                     el.hide();
10430                 }
10431
10432                 el.clearOpacity();
10433                 el.setPositioning(r.pos);
10434                 st.width = r.width;
10435                 st.height = r.height;
10436
10437                 el.afterFx(o);
10438             };
10439
10440             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10441             switch(anchor.toLowerCase()){
10442                 case "t":
10443                     pt.by = [0, -h];
10444                 break;
10445                 case "l":
10446                     pt.by = [-w, 0];
10447                 break;
10448                 case "r":
10449                     pt.by = [w, 0];
10450                 break;
10451                 case "b":
10452                     pt.by = [0, h];
10453                 break;
10454                 case "tl":
10455                     pt.by = [-w, -h];
10456                 break;
10457                 case "bl":
10458                     pt.by = [-w, h];
10459                 break;
10460                 case "br":
10461                     pt.by = [w, h];
10462                 break;
10463                 case "tr":
10464                     pt.by = [w, -h];
10465                 break;
10466             }
10467
10468             arguments.callee.anim = this.fxanim(a,
10469                 o,
10470                 'motion',
10471                 .5,
10472                 "easeOut", after);
10473         });
10474         return this;
10475     },
10476
10477         /**
10478          * Ensures that all effects queued after syncFx is called on the element are
10479          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10480          * @return {Roo.Element} The Element
10481          */
10482     syncFx : function(){
10483         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10484             block : false,
10485             concurrent : true,
10486             stopFx : false
10487         });
10488         return this;
10489     },
10490
10491         /**
10492          * Ensures that all effects queued after sequenceFx is called on the element are
10493          * run in sequence.  This is the opposite of {@link #syncFx}.
10494          * @return {Roo.Element} The Element
10495          */
10496     sequenceFx : function(){
10497         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10498             block : false,
10499             concurrent : false,
10500             stopFx : false
10501         });
10502         return this;
10503     },
10504
10505         /* @private */
10506     nextFx : function(){
10507         var ef = this.fxQueue[0];
10508         if(ef){
10509             ef.call(this);
10510         }
10511     },
10512
10513         /**
10514          * Returns true if the element has any effects actively running or queued, else returns false.
10515          * @return {Boolean} True if element has active effects, else false
10516          */
10517     hasActiveFx : function(){
10518         return this.fxQueue && this.fxQueue[0];
10519     },
10520
10521         /**
10522          * Stops any running effects and clears the element's internal effects queue if it contains
10523          * any additional effects that haven't started yet.
10524          * @return {Roo.Element} The Element
10525          */
10526     stopFx : function(){
10527         if(this.hasActiveFx()){
10528             var cur = this.fxQueue[0];
10529             if(cur && cur.anim && cur.anim.isAnimated()){
10530                 this.fxQueue = [cur]; // clear out others
10531                 cur.anim.stop(true);
10532             }
10533         }
10534         return this;
10535     },
10536
10537         /* @private */
10538     beforeFx : function(o){
10539         if(this.hasActiveFx() && !o.concurrent){
10540            if(o.stopFx){
10541                this.stopFx();
10542                return true;
10543            }
10544            return false;
10545         }
10546         return true;
10547     },
10548
10549         /**
10550          * Returns true if the element is currently blocking so that no other effect can be queued
10551          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10552          * used to ensure that an effect initiated by a user action runs to completion prior to the
10553          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10554          * @return {Boolean} True if blocking, else false
10555          */
10556     hasFxBlock : function(){
10557         var q = this.fxQueue;
10558         return q && q[0] && q[0].block;
10559     },
10560
10561         /* @private */
10562     queueFx : function(o, fn){
10563         if(!this.fxQueue){
10564             this.fxQueue = [];
10565         }
10566         if(!this.hasFxBlock()){
10567             Roo.applyIf(o, this.fxDefaults);
10568             if(!o.concurrent){
10569                 var run = this.beforeFx(o);
10570                 fn.block = o.block;
10571                 this.fxQueue.push(fn);
10572                 if(run){
10573                     this.nextFx();
10574                 }
10575             }else{
10576                 fn.call(this);
10577             }
10578         }
10579         return this;
10580     },
10581
10582         /* @private */
10583     fxWrap : function(pos, o, vis){
10584         var wrap;
10585         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10586             var wrapXY;
10587             if(o.fixPosition){
10588                 wrapXY = this.getXY();
10589             }
10590             var div = document.createElement("div");
10591             div.style.visibility = vis;
10592             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10593             wrap.setPositioning(pos);
10594             if(wrap.getStyle("position") == "static"){
10595                 wrap.position("relative");
10596             }
10597             this.clearPositioning('auto');
10598             wrap.clip();
10599             wrap.dom.appendChild(this.dom);
10600             if(wrapXY){
10601                 wrap.setXY(wrapXY);
10602             }
10603         }
10604         return wrap;
10605     },
10606
10607         /* @private */
10608     fxUnwrap : function(wrap, pos, o){
10609         this.clearPositioning();
10610         this.setPositioning(pos);
10611         if(!o.wrap){
10612             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10613             wrap.remove();
10614         }
10615     },
10616
10617         /* @private */
10618     getFxRestore : function(){
10619         var st = this.dom.style;
10620         return {pos: this.getPositioning(), width: st.width, height : st.height};
10621     },
10622
10623         /* @private */
10624     afterFx : function(o){
10625         if(o.afterStyle){
10626             this.applyStyles(o.afterStyle);
10627         }
10628         if(o.afterCls){
10629             this.addClass(o.afterCls);
10630         }
10631         if(o.remove === true){
10632             this.remove();
10633         }
10634         Roo.callback(o.callback, o.scope, [this]);
10635         if(!o.concurrent){
10636             this.fxQueue.shift();
10637             this.nextFx();
10638         }
10639     },
10640
10641         /* @private */
10642     getFxEl : function(){ // support for composite element fx
10643         return Roo.get(this.dom);
10644     },
10645
10646         /* @private */
10647     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10648         animType = animType || 'run';
10649         opt = opt || {};
10650         var anim = Roo.lib.Anim[animType](
10651             this.dom, args,
10652             (opt.duration || defaultDur) || .35,
10653             (opt.easing || defaultEase) || 'easeOut',
10654             function(){
10655                 Roo.callback(cb, this);
10656             },
10657             this
10658         );
10659         opt.anim = anim;
10660         return anim;
10661     }
10662 };
10663
10664 // backwords compat
10665 Roo.Fx.resize = Roo.Fx.scale;
10666
10667 //When included, Roo.Fx is automatically applied to Element so that all basic
10668 //effects are available directly via the Element API
10669 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10670  * Based on:
10671  * Ext JS Library 1.1.1
10672  * Copyright(c) 2006-2007, Ext JS, LLC.
10673  *
10674  * Originally Released Under LGPL - original licence link has changed is not relivant.
10675  *
10676  * Fork - LGPL
10677  * <script type="text/javascript">
10678  */
10679
10680
10681 /**
10682  * @class Roo.CompositeElement
10683  * Standard composite class. Creates a Roo.Element for every element in the collection.
10684  * <br><br>
10685  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10686  * actions will be performed on all the elements in this collection.</b>
10687  * <br><br>
10688  * All methods return <i>this</i> and can be chained.
10689  <pre><code>
10690  var els = Roo.select("#some-el div.some-class", true);
10691  // or select directly from an existing element
10692  var el = Roo.get('some-el');
10693  el.select('div.some-class', true);
10694
10695  els.setWidth(100); // all elements become 100 width
10696  els.hide(true); // all elements fade out and hide
10697  // or
10698  els.setWidth(100).hide(true);
10699  </code></pre>
10700  */
10701 Roo.CompositeElement = function(els){
10702     this.elements = [];
10703     this.addElements(els);
10704 };
10705 Roo.CompositeElement.prototype = {
10706     isComposite: true,
10707     addElements : function(els){
10708         if(!els) return this;
10709         if(typeof els == "string"){
10710             els = Roo.Element.selectorFunction(els);
10711         }
10712         var yels = this.elements;
10713         var index = yels.length-1;
10714         for(var i = 0, len = els.length; i < len; i++) {
10715                 yels[++index] = Roo.get(els[i]);
10716         }
10717         return this;
10718     },
10719
10720     /**
10721     * Clears this composite and adds the elements returned by the passed selector.
10722     * @param {String/Array} els A string CSS selector, an array of elements or an element
10723     * @return {CompositeElement} this
10724     */
10725     fill : function(els){
10726         this.elements = [];
10727         this.add(els);
10728         return this;
10729     },
10730
10731     /**
10732     * Filters this composite to only elements that match the passed selector.
10733     * @param {String} selector A string CSS selector
10734     * @return {CompositeElement} this
10735     */
10736     filter : function(selector){
10737         var els = [];
10738         this.each(function(el){
10739             if(el.is(selector)){
10740                 els[els.length] = el.dom;
10741             }
10742         });
10743         this.fill(els);
10744         return this;
10745     },
10746
10747     invoke : function(fn, args){
10748         var els = this.elements;
10749         for(var i = 0, len = els.length; i < len; i++) {
10750                 Roo.Element.prototype[fn].apply(els[i], args);
10751         }
10752         return this;
10753     },
10754     /**
10755     * Adds elements to this composite.
10756     * @param {String/Array} els A string CSS selector, an array of elements or an element
10757     * @return {CompositeElement} this
10758     */
10759     add : function(els){
10760         if(typeof els == "string"){
10761             this.addElements(Roo.Element.selectorFunction(els));
10762         }else if(els.length !== undefined){
10763             this.addElements(els);
10764         }else{
10765             this.addElements([els]);
10766         }
10767         return this;
10768     },
10769     /**
10770     * Calls the passed function passing (el, this, index) for each element in this composite.
10771     * @param {Function} fn The function to call
10772     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10773     * @return {CompositeElement} this
10774     */
10775     each : function(fn, scope){
10776         var els = this.elements;
10777         for(var i = 0, len = els.length; i < len; i++){
10778             if(fn.call(scope || els[i], els[i], this, i) === false) {
10779                 break;
10780             }
10781         }
10782         return this;
10783     },
10784
10785     /**
10786      * Returns the Element object at the specified index
10787      * @param {Number} index
10788      * @return {Roo.Element}
10789      */
10790     item : function(index){
10791         return this.elements[index] || null;
10792     },
10793
10794     /**
10795      * Returns the first Element
10796      * @return {Roo.Element}
10797      */
10798     first : function(){
10799         return this.item(0);
10800     },
10801
10802     /**
10803      * Returns the last Element
10804      * @return {Roo.Element}
10805      */
10806     last : function(){
10807         return this.item(this.elements.length-1);
10808     },
10809
10810     /**
10811      * Returns the number of elements in this composite
10812      * @return Number
10813      */
10814     getCount : function(){
10815         return this.elements.length;
10816     },
10817
10818     /**
10819      * Returns true if this composite contains the passed element
10820      * @return Boolean
10821      */
10822     contains : function(el){
10823         return this.indexOf(el) !== -1;
10824     },
10825
10826     /**
10827      * Returns true if this composite contains the passed element
10828      * @return Boolean
10829      */
10830     indexOf : function(el){
10831         return this.elements.indexOf(Roo.get(el));
10832     },
10833
10834
10835     /**
10836     * Removes the specified element(s).
10837     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10838     * or an array of any of those.
10839     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10840     * @return {CompositeElement} this
10841     */
10842     removeElement : function(el, removeDom){
10843         if(el instanceof Array){
10844             for(var i = 0, len = el.length; i < len; i++){
10845                 this.removeElement(el[i]);
10846             }
10847             return this;
10848         }
10849         var index = typeof el == 'number' ? el : this.indexOf(el);
10850         if(index !== -1){
10851             if(removeDom){
10852                 var d = this.elements[index];
10853                 if(d.dom){
10854                     d.remove();
10855                 }else{
10856                     d.parentNode.removeChild(d);
10857                 }
10858             }
10859             this.elements.splice(index, 1);
10860         }
10861         return this;
10862     },
10863
10864     /**
10865     * Replaces the specified element with the passed element.
10866     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10867     * to replace.
10868     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10869     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10870     * @return {CompositeElement} this
10871     */
10872     replaceElement : function(el, replacement, domReplace){
10873         var index = typeof el == 'number' ? el : this.indexOf(el);
10874         if(index !== -1){
10875             if(domReplace){
10876                 this.elements[index].replaceWith(replacement);
10877             }else{
10878                 this.elements.splice(index, 1, Roo.get(replacement))
10879             }
10880         }
10881         return this;
10882     },
10883
10884     /**
10885      * Removes all elements.
10886      */
10887     clear : function(){
10888         this.elements = [];
10889     }
10890 };
10891 (function(){
10892     Roo.CompositeElement.createCall = function(proto, fnName){
10893         if(!proto[fnName]){
10894             proto[fnName] = function(){
10895                 return this.invoke(fnName, arguments);
10896             };
10897         }
10898     };
10899     for(var fnName in Roo.Element.prototype){
10900         if(typeof Roo.Element.prototype[fnName] == "function"){
10901             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10902         }
10903     };
10904 })();
10905 /*
10906  * Based on:
10907  * Ext JS Library 1.1.1
10908  * Copyright(c) 2006-2007, Ext JS, LLC.
10909  *
10910  * Originally Released Under LGPL - original licence link has changed is not relivant.
10911  *
10912  * Fork - LGPL
10913  * <script type="text/javascript">
10914  */
10915
10916 /**
10917  * @class Roo.CompositeElementLite
10918  * @extends Roo.CompositeElement
10919  * Flyweight composite class. Reuses the same Roo.Element for element operations.
10920  <pre><code>
10921  var els = Roo.select("#some-el div.some-class");
10922  // or select directly from an existing element
10923  var el = Roo.get('some-el');
10924  el.select('div.some-class');
10925
10926  els.setWidth(100); // all elements become 100 width
10927  els.hide(true); // all elements fade out and hide
10928  // or
10929  els.setWidth(100).hide(true);
10930  </code></pre><br><br>
10931  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10932  * actions will be performed on all the elements in this collection.</b>
10933  */
10934 Roo.CompositeElementLite = function(els){
10935     Roo.CompositeElementLite.superclass.constructor.call(this, els);
10936     this.el = new Roo.Element.Flyweight();
10937 };
10938 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10939     addElements : function(els){
10940         if(els){
10941             if(els instanceof Array){
10942                 this.elements = this.elements.concat(els);
10943             }else{
10944                 var yels = this.elements;
10945                 var index = yels.length-1;
10946                 for(var i = 0, len = els.length; i < len; i++) {
10947                     yels[++index] = els[i];
10948                 }
10949             }
10950         }
10951         return this;
10952     },
10953     invoke : function(fn, args){
10954         var els = this.elements;
10955         var el = this.el;
10956         for(var i = 0, len = els.length; i < len; i++) {
10957             el.dom = els[i];
10958                 Roo.Element.prototype[fn].apply(el, args);
10959         }
10960         return this;
10961     },
10962     /**
10963      * Returns a flyweight Element of the dom element object at the specified index
10964      * @param {Number} index
10965      * @return {Roo.Element}
10966      */
10967     item : function(index){
10968         if(!this.elements[index]){
10969             return null;
10970         }
10971         this.el.dom = this.elements[index];
10972         return this.el;
10973     },
10974
10975     // fixes scope with flyweight
10976     addListener : function(eventName, handler, scope, opt){
10977         var els = this.elements;
10978         for(var i = 0, len = els.length; i < len; i++) {
10979             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10980         }
10981         return this;
10982     },
10983
10984     /**
10985     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10986     * passed is the flyweight (shared) Roo.Element instance, so if you require a
10987     * a reference to the dom node, use el.dom.</b>
10988     * @param {Function} fn The function to call
10989     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10990     * @return {CompositeElement} this
10991     */
10992     each : function(fn, scope){
10993         var els = this.elements;
10994         var el = this.el;
10995         for(var i = 0, len = els.length; i < len; i++){
10996             el.dom = els[i];
10997                 if(fn.call(scope || el, el, this, i) === false){
10998                 break;
10999             }
11000         }
11001         return this;
11002     },
11003
11004     indexOf : function(el){
11005         return this.elements.indexOf(Roo.getDom(el));
11006     },
11007
11008     replaceElement : function(el, replacement, domReplace){
11009         var index = typeof el == 'number' ? el : this.indexOf(el);
11010         if(index !== -1){
11011             replacement = Roo.getDom(replacement);
11012             if(domReplace){
11013                 var d = this.elements[index];
11014                 d.parentNode.insertBefore(replacement, d);
11015                 d.parentNode.removeChild(d);
11016             }
11017             this.elements.splice(index, 1, replacement);
11018         }
11019         return this;
11020     }
11021 });
11022 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11023
11024 /*
11025  * Based on:
11026  * Ext JS Library 1.1.1
11027  * Copyright(c) 2006-2007, Ext JS, LLC.
11028  *
11029  * Originally Released Under LGPL - original licence link has changed is not relivant.
11030  *
11031  * Fork - LGPL
11032  * <script type="text/javascript">
11033  */
11034
11035  
11036
11037 /**
11038  * @class Roo.data.Connection
11039  * @extends Roo.util.Observable
11040  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11041  * either to a configured URL, or to a URL specified at request time.<br><br>
11042  * <p>
11043  * Requests made by this class are asynchronous, and will return immediately. No data from
11044  * the server will be available to the statement immediately following the {@link #request} call.
11045  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11046  * <p>
11047  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11048  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11049  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11050  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11051  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11052  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11053  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11054  * standard DOM methods.
11055  * @constructor
11056  * @param {Object} config a configuration object.
11057  */
11058 Roo.data.Connection = function(config){
11059     Roo.apply(this, config);
11060     this.addEvents({
11061         /**
11062          * @event beforerequest
11063          * Fires before a network request is made to retrieve a data object.
11064          * @param {Connection} conn This Connection object.
11065          * @param {Object} options The options config object passed to the {@link #request} method.
11066          */
11067         "beforerequest" : true,
11068         /**
11069          * @event requestcomplete
11070          * Fires if the request was successfully completed.
11071          * @param {Connection} conn This Connection object.
11072          * @param {Object} response The XHR object containing the response data.
11073          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11074          * @param {Object} options The options config object passed to the {@link #request} method.
11075          */
11076         "requestcomplete" : true,
11077         /**
11078          * @event requestexception
11079          * Fires if an error HTTP status was returned from the server.
11080          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11081          * @param {Connection} conn This Connection object.
11082          * @param {Object} response The XHR object containing the response data.
11083          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11084          * @param {Object} options The options config object passed to the {@link #request} method.
11085          */
11086         "requestexception" : true
11087     });
11088     Roo.data.Connection.superclass.constructor.call(this);
11089 };
11090
11091 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11092     /**
11093      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11094      */
11095     /**
11096      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11097      * extra parameters to each request made by this object. (defaults to undefined)
11098      */
11099     /**
11100      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11101      *  to each request made by this object. (defaults to undefined)
11102      */
11103     /**
11104      * @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)
11105      */
11106     /**
11107      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11108      */
11109     timeout : 30000,
11110     /**
11111      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11112      * @type Boolean
11113      */
11114     autoAbort:false,
11115
11116     /**
11117      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11118      * @type Boolean
11119      */
11120     disableCaching: true,
11121
11122     /**
11123      * Sends an HTTP request to a remote server.
11124      * @param {Object} options An object which may contain the following properties:<ul>
11125      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11126      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11127      * request, a url encoded string or a function to call to get either.</li>
11128      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11129      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11130      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11131      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11132      * <li>options {Object} The parameter to the request call.</li>
11133      * <li>success {Boolean} True if the request succeeded.</li>
11134      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11135      * </ul></li>
11136      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11137      * The callback is passed the following parameters:<ul>
11138      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11139      * <li>options {Object} The parameter to the request call.</li>
11140      * </ul></li>
11141      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11142      * The callback is passed the following parameters:<ul>
11143      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11144      * <li>options {Object} The parameter to the request call.</li>
11145      * </ul></li>
11146      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11147      * for the callback function. Defaults to the browser window.</li>
11148      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11149      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11150      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11151      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11152      * params for the post data. Any params will be appended to the URL.</li>
11153      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11154      * </ul>
11155      * @return {Number} transactionId
11156      */
11157     request : function(o){
11158         if(this.fireEvent("beforerequest", this, o) !== false){
11159             var p = o.params;
11160
11161             if(typeof p == "function"){
11162                 p = p.call(o.scope||window, o);
11163             }
11164             if(typeof p == "object"){
11165                 p = Roo.urlEncode(o.params);
11166             }
11167             if(this.extraParams){
11168                 var extras = Roo.urlEncode(this.extraParams);
11169                 p = p ? (p + '&' + extras) : extras;
11170             }
11171
11172             var url = o.url || this.url;
11173             if(typeof url == 'function'){
11174                 url = url.call(o.scope||window, o);
11175             }
11176
11177             if(o.form){
11178                 var form = Roo.getDom(o.form);
11179                 url = url || form.action;
11180
11181                 var enctype = form.getAttribute("enctype");
11182                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11183                     return this.doFormUpload(o, p, url);
11184                 }
11185                 var f = Roo.lib.Ajax.serializeForm(form);
11186                 p = p ? (p + '&' + f) : f;
11187             }
11188
11189             var hs = o.headers;
11190             if(this.defaultHeaders){
11191                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11192                 if(!o.headers){
11193                     o.headers = hs;
11194                 }
11195             }
11196
11197             var cb = {
11198                 success: this.handleResponse,
11199                 failure: this.handleFailure,
11200                 scope: this,
11201                 argument: {options: o},
11202                 timeout : this.timeout
11203             };
11204
11205             var method = o.method||this.method||(p ? "POST" : "GET");
11206
11207             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11208                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11209             }
11210
11211             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11212                 if(o.autoAbort){
11213                     this.abort();
11214                 }
11215             }else if(this.autoAbort !== false){
11216                 this.abort();
11217             }
11218
11219             if((method == 'GET' && p) || o.xmlData){
11220                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11221                 p = '';
11222             }
11223             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11224             return this.transId;
11225         }else{
11226             Roo.callback(o.callback, o.scope, [o, null, null]);
11227             return null;
11228         }
11229     },
11230
11231     /**
11232      * Determine whether this object has a request outstanding.
11233      * @param {Number} transactionId (Optional) defaults to the last transaction
11234      * @return {Boolean} True if there is an outstanding request.
11235      */
11236     isLoading : function(transId){
11237         if(transId){
11238             return Roo.lib.Ajax.isCallInProgress(transId);
11239         }else{
11240             return this.transId ? true : false;
11241         }
11242     },
11243
11244     /**
11245      * Aborts any outstanding request.
11246      * @param {Number} transactionId (Optional) defaults to the last transaction
11247      */
11248     abort : function(transId){
11249         if(transId || this.isLoading()){
11250             Roo.lib.Ajax.abort(transId || this.transId);
11251         }
11252     },
11253
11254     // private
11255     handleResponse : function(response){
11256         this.transId = false;
11257         var options = response.argument.options;
11258         response.argument = options ? options.argument : null;
11259         this.fireEvent("requestcomplete", this, response, options);
11260         Roo.callback(options.success, options.scope, [response, options]);
11261         Roo.callback(options.callback, options.scope, [options, true, response]);
11262     },
11263
11264     // private
11265     handleFailure : function(response, e){
11266         this.transId = false;
11267         var options = response.argument.options;
11268         response.argument = options ? options.argument : null;
11269         this.fireEvent("requestexception", this, response, options, e);
11270         Roo.callback(options.failure, options.scope, [response, options]);
11271         Roo.callback(options.callback, options.scope, [options, false, response]);
11272     },
11273
11274     // private
11275     doFormUpload : function(o, ps, url){
11276         var id = Roo.id();
11277         var frame = document.createElement('iframe');
11278         frame.id = id;
11279         frame.name = id;
11280         frame.className = 'x-hidden';
11281         if(Roo.isIE){
11282             frame.src = Roo.SSL_SECURE_URL;
11283         }
11284         document.body.appendChild(frame);
11285
11286         if(Roo.isIE){
11287            document.frames[id].name = id;
11288         }
11289
11290         var form = Roo.getDom(o.form);
11291         form.target = id;
11292         form.method = 'POST';
11293         form.enctype = form.encoding = 'multipart/form-data';
11294         if(url){
11295             form.action = url;
11296         }
11297
11298         var hiddens, hd;
11299         if(ps){ // add dynamic params
11300             hiddens = [];
11301             ps = Roo.urlDecode(ps, false);
11302             for(var k in ps){
11303                 if(ps.hasOwnProperty(k)){
11304                     hd = document.createElement('input');
11305                     hd.type = 'hidden';
11306                     hd.name = k;
11307                     hd.value = ps[k];
11308                     form.appendChild(hd);
11309                     hiddens.push(hd);
11310                 }
11311             }
11312         }
11313
11314         function cb(){
11315             var r = {  // bogus response object
11316                 responseText : '',
11317                 responseXML : null
11318             };
11319
11320             r.argument = o ? o.argument : null;
11321
11322             try { //
11323                 var doc;
11324                 if(Roo.isIE){
11325                     doc = frame.contentWindow.document;
11326                 }else {
11327                     doc = (frame.contentDocument || window.frames[id].document);
11328                 }
11329                 if(doc && doc.body){
11330                     r.responseText = doc.body.innerHTML;
11331                 }
11332                 if(doc && doc.XMLDocument){
11333                     r.responseXML = doc.XMLDocument;
11334                 }else {
11335                     r.responseXML = doc;
11336                 }
11337             }
11338             catch(e) {
11339                 // ignore
11340             }
11341
11342             Roo.EventManager.removeListener(frame, 'load', cb, this);
11343
11344             this.fireEvent("requestcomplete", this, r, o);
11345             Roo.callback(o.success, o.scope, [r, o]);
11346             Roo.callback(o.callback, o.scope, [o, true, r]);
11347
11348             setTimeout(function(){document.body.removeChild(frame);}, 100);
11349         }
11350
11351         Roo.EventManager.on(frame, 'load', cb, this);
11352         form.submit();
11353
11354         if(hiddens){ // remove dynamic params
11355             for(var i = 0, len = hiddens.length; i < len; i++){
11356                 form.removeChild(hiddens[i]);
11357             }
11358         }
11359     }
11360 });
11361
11362 /**
11363  * @class Roo.Ajax
11364  * @extends Roo.data.Connection
11365  * Global Ajax request class.
11366  *
11367  * @singleton
11368  */
11369 Roo.Ajax = new Roo.data.Connection({
11370     // fix up the docs
11371    /**
11372      * @cfg {String} url @hide
11373      */
11374     /**
11375      * @cfg {Object} extraParams @hide
11376      */
11377     /**
11378      * @cfg {Object} defaultHeaders @hide
11379      */
11380     /**
11381      * @cfg {String} method (Optional) @hide
11382      */
11383     /**
11384      * @cfg {Number} timeout (Optional) @hide
11385      */
11386     /**
11387      * @cfg {Boolean} autoAbort (Optional) @hide
11388      */
11389
11390     /**
11391      * @cfg {Boolean} disableCaching (Optional) @hide
11392      */
11393
11394     /**
11395      * @property  disableCaching
11396      * True to add a unique cache-buster param to GET requests. (defaults to true)
11397      * @type Boolean
11398      */
11399     /**
11400      * @property  url
11401      * The default URL to be used for requests to the server. (defaults to undefined)
11402      * @type String
11403      */
11404     /**
11405      * @property  extraParams
11406      * An object containing properties which are used as
11407      * extra parameters to each request made by this object. (defaults to undefined)
11408      * @type Object
11409      */
11410     /**
11411      * @property  defaultHeaders
11412      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11413      * @type Object
11414      */
11415     /**
11416      * @property  method
11417      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11418      * @type String
11419      */
11420     /**
11421      * @property  timeout
11422      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11423      * @type Number
11424      */
11425
11426     /**
11427      * @property  autoAbort
11428      * Whether a new request should abort any pending requests. (defaults to false)
11429      * @type Boolean
11430      */
11431     autoAbort : false,
11432
11433     /**
11434      * Serialize the passed form into a url encoded string
11435      * @param {String/HTMLElement} form
11436      * @return {String}
11437      */
11438     serializeForm : function(form){
11439         return Roo.lib.Ajax.serializeForm(form);
11440     }
11441 });/*
11442  * Based on:
11443  * Ext JS Library 1.1.1
11444  * Copyright(c) 2006-2007, Ext JS, LLC.
11445  *
11446  * Originally Released Under LGPL - original licence link has changed is not relivant.
11447  *
11448  * Fork - LGPL
11449  * <script type="text/javascript">
11450  */
11451  
11452 /**
11453  * @class Roo.Ajax
11454  * @extends Roo.data.Connection
11455  * Global Ajax request class.
11456  *
11457  * @instanceOf  Roo.data.Connection
11458  */
11459 Roo.Ajax = new Roo.data.Connection({
11460     // fix up the docs
11461     
11462     /**
11463      * fix up scoping
11464      * @scope Roo.Ajax
11465      */
11466     
11467    /**
11468      * @cfg {String} url @hide
11469      */
11470     /**
11471      * @cfg {Object} extraParams @hide
11472      */
11473     /**
11474      * @cfg {Object} defaultHeaders @hide
11475      */
11476     /**
11477      * @cfg {String} method (Optional) @hide
11478      */
11479     /**
11480      * @cfg {Number} timeout (Optional) @hide
11481      */
11482     /**
11483      * @cfg {Boolean} autoAbort (Optional) @hide
11484      */
11485
11486     /**
11487      * @cfg {Boolean} disableCaching (Optional) @hide
11488      */
11489
11490     /**
11491      * @property  disableCaching
11492      * True to add a unique cache-buster param to GET requests. (defaults to true)
11493      * @type Boolean
11494      */
11495     /**
11496      * @property  url
11497      * The default URL to be used for requests to the server. (defaults to undefined)
11498      * @type String
11499      */
11500     /**
11501      * @property  extraParams
11502      * An object containing properties which are used as
11503      * extra parameters to each request made by this object. (defaults to undefined)
11504      * @type Object
11505      */
11506     /**
11507      * @property  defaultHeaders
11508      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11509      * @type Object
11510      */
11511     /**
11512      * @property  method
11513      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11514      * @type String
11515      */
11516     /**
11517      * @property  timeout
11518      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11519      * @type Number
11520      */
11521
11522     /**
11523      * @property  autoAbort
11524      * Whether a new request should abort any pending requests. (defaults to false)
11525      * @type Boolean
11526      */
11527     autoAbort : false,
11528
11529     /**
11530      * Serialize the passed form into a url encoded string
11531      * @param {String/HTMLElement} form
11532      * @return {String}
11533      */
11534     serializeForm : function(form){
11535         return Roo.lib.Ajax.serializeForm(form);
11536     }
11537 });/*
11538  * Based on:
11539  * Ext JS Library 1.1.1
11540  * Copyright(c) 2006-2007, Ext JS, LLC.
11541  *
11542  * Originally Released Under LGPL - original licence link has changed is not relivant.
11543  *
11544  * Fork - LGPL
11545  * <script type="text/javascript">
11546  */
11547
11548  
11549 /**
11550  * @class Roo.UpdateManager
11551  * @extends Roo.util.Observable
11552  * Provides AJAX-style update for Element object.<br><br>
11553  * Usage:<br>
11554  * <pre><code>
11555  * // Get it from a Roo.Element object
11556  * var el = Roo.get("foo");
11557  * var mgr = el.getUpdateManager();
11558  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11559  * ...
11560  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11561  * <br>
11562  * // or directly (returns the same UpdateManager instance)
11563  * var mgr = new Roo.UpdateManager("myElementId");
11564  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11565  * mgr.on("update", myFcnNeedsToKnow);
11566  * <br>
11567    // short handed call directly from the element object
11568    Roo.get("foo").load({
11569         url: "bar.php",
11570         scripts:true,
11571         params: "for=bar",
11572         text: "Loading Foo..."
11573    });
11574  * </code></pre>
11575  * @constructor
11576  * Create new UpdateManager directly.
11577  * @param {String/HTMLElement/Roo.Element} el The element to update
11578  * @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).
11579  */
11580 Roo.UpdateManager = function(el, forceNew){
11581     el = Roo.get(el);
11582     if(!forceNew && el.updateManager){
11583         return el.updateManager;
11584     }
11585     /**
11586      * The Element object
11587      * @type Roo.Element
11588      */
11589     this.el = el;
11590     /**
11591      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11592      * @type String
11593      */
11594     this.defaultUrl = null;
11595
11596     this.addEvents({
11597         /**
11598          * @event beforeupdate
11599          * Fired before an update is made, return false from your handler and the update is cancelled.
11600          * @param {Roo.Element} el
11601          * @param {String/Object/Function} url
11602          * @param {String/Object} params
11603          */
11604         "beforeupdate": true,
11605         /**
11606          * @event update
11607          * Fired after successful update is made.
11608          * @param {Roo.Element} el
11609          * @param {Object} oResponseObject The response Object
11610          */
11611         "update": true,
11612         /**
11613          * @event failure
11614          * Fired on update failure.
11615          * @param {Roo.Element} el
11616          * @param {Object} oResponseObject The response Object
11617          */
11618         "failure": true
11619     });
11620     var d = Roo.UpdateManager.defaults;
11621     /**
11622      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11623      * @type String
11624      */
11625     this.sslBlankUrl = d.sslBlankUrl;
11626     /**
11627      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11628      * @type Boolean
11629      */
11630     this.disableCaching = d.disableCaching;
11631     /**
11632      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11633      * @type String
11634      */
11635     this.indicatorText = d.indicatorText;
11636     /**
11637      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11638      * @type String
11639      */
11640     this.showLoadIndicator = d.showLoadIndicator;
11641     /**
11642      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11643      * @type Number
11644      */
11645     this.timeout = d.timeout;
11646
11647     /**
11648      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11649      * @type Boolean
11650      */
11651     this.loadScripts = d.loadScripts;
11652
11653     /**
11654      * Transaction object of current executing transaction
11655      */
11656     this.transaction = null;
11657
11658     /**
11659      * @private
11660      */
11661     this.autoRefreshProcId = null;
11662     /**
11663      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11664      * @type Function
11665      */
11666     this.refreshDelegate = this.refresh.createDelegate(this);
11667     /**
11668      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11669      * @type Function
11670      */
11671     this.updateDelegate = this.update.createDelegate(this);
11672     /**
11673      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11674      * @type Function
11675      */
11676     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11677     /**
11678      * @private
11679      */
11680     this.successDelegate = this.processSuccess.createDelegate(this);
11681     /**
11682      * @private
11683      */
11684     this.failureDelegate = this.processFailure.createDelegate(this);
11685
11686     if(!this.renderer){
11687      /**
11688       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11689       */
11690     this.renderer = new Roo.UpdateManager.BasicRenderer();
11691     }
11692     
11693     Roo.UpdateManager.superclass.constructor.call(this);
11694 };
11695
11696 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11697     /**
11698      * Get the Element this UpdateManager is bound to
11699      * @return {Roo.Element} The element
11700      */
11701     getEl : function(){
11702         return this.el;
11703     },
11704     /**
11705      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11706      * @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:
11707 <pre><code>
11708 um.update({<br/>
11709     url: "your-url.php",<br/>
11710     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11711     callback: yourFunction,<br/>
11712     scope: yourObject, //(optional scope)  <br/>
11713     discardUrl: false, <br/>
11714     nocache: false,<br/>
11715     text: "Loading...",<br/>
11716     timeout: 30,<br/>
11717     scripts: false<br/>
11718 });
11719 </code></pre>
11720      * The only required property is url. The optional properties nocache, text and scripts
11721      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11722      * @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}
11723      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11724      * @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.
11725      */
11726     update : function(url, params, callback, discardUrl){
11727         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11728             var method = this.method, cfg;
11729             if(typeof url == "object"){ // must be config object
11730                 cfg = url;
11731                 url = cfg.url;
11732                 params = params || cfg.params;
11733                 callback = callback || cfg.callback;
11734                 discardUrl = discardUrl || cfg.discardUrl;
11735                 if(callback && cfg.scope){
11736                     callback = callback.createDelegate(cfg.scope);
11737                 }
11738                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11739                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11740                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11741                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11742                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11743             }
11744             this.showLoading();
11745             if(!discardUrl){
11746                 this.defaultUrl = url;
11747             }
11748             if(typeof url == "function"){
11749                 url = url.call(this);
11750             }
11751
11752             method = method || (params ? "POST" : "GET");
11753             if(method == "GET"){
11754                 url = this.prepareUrl(url);
11755             }
11756
11757             var o = Roo.apply(cfg ||{}, {
11758                 url : url,
11759                 params: params,
11760                 success: this.successDelegate,
11761                 failure: this.failureDelegate,
11762                 callback: undefined,
11763                 timeout: (this.timeout*1000),
11764                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11765             });
11766
11767             this.transaction = Roo.Ajax.request(o);
11768         }
11769     },
11770
11771     /**
11772      * 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.
11773      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11774      * @param {String/HTMLElement} form The form Id or form element
11775      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11776      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11777      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11778      */
11779     formUpdate : function(form, url, reset, callback){
11780         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11781             if(typeof url == "function"){
11782                 url = url.call(this);
11783             }
11784             form = Roo.getDom(form);
11785             this.transaction = Roo.Ajax.request({
11786                 form: form,
11787                 url:url,
11788                 success: this.successDelegate,
11789                 failure: this.failureDelegate,
11790                 timeout: (this.timeout*1000),
11791                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11792             });
11793             this.showLoading.defer(1, this);
11794         }
11795     },
11796
11797     /**
11798      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11799      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11800      */
11801     refresh : function(callback){
11802         if(this.defaultUrl == null){
11803             return;
11804         }
11805         this.update(this.defaultUrl, null, callback, true);
11806     },
11807
11808     /**
11809      * Set this element to auto refresh.
11810      * @param {Number} interval How often to update (in seconds).
11811      * @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)
11812      * @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}
11813      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11814      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11815      */
11816     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11817         if(refreshNow){
11818             this.update(url || this.defaultUrl, params, callback, true);
11819         }
11820         if(this.autoRefreshProcId){
11821             clearInterval(this.autoRefreshProcId);
11822         }
11823         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11824     },
11825
11826     /**
11827      * Stop auto refresh on this element.
11828      */
11829      stopAutoRefresh : function(){
11830         if(this.autoRefreshProcId){
11831             clearInterval(this.autoRefreshProcId);
11832             delete this.autoRefreshProcId;
11833         }
11834     },
11835
11836     isAutoRefreshing : function(){
11837        return this.autoRefreshProcId ? true : false;
11838     },
11839     /**
11840      * Called to update the element to "Loading" state. Override to perform custom action.
11841      */
11842     showLoading : function(){
11843         if(this.showLoadIndicator){
11844             this.el.update(this.indicatorText);
11845         }
11846     },
11847
11848     /**
11849      * Adds unique parameter to query string if disableCaching = true
11850      * @private
11851      */
11852     prepareUrl : function(url){
11853         if(this.disableCaching){
11854             var append = "_dc=" + (new Date().getTime());
11855             if(url.indexOf("?") !== -1){
11856                 url += "&" + append;
11857             }else{
11858                 url += "?" + append;
11859             }
11860         }
11861         return url;
11862     },
11863
11864     /**
11865      * @private
11866      */
11867     processSuccess : function(response){
11868         this.transaction = null;
11869         if(response.argument.form && response.argument.reset){
11870             try{ // put in try/catch since some older FF releases had problems with this
11871                 response.argument.form.reset();
11872             }catch(e){}
11873         }
11874         if(this.loadScripts){
11875             this.renderer.render(this.el, response, this,
11876                 this.updateComplete.createDelegate(this, [response]));
11877         }else{
11878             this.renderer.render(this.el, response, this);
11879             this.updateComplete(response);
11880         }
11881     },
11882
11883     updateComplete : function(response){
11884         this.fireEvent("update", this.el, response);
11885         if(typeof response.argument.callback == "function"){
11886             response.argument.callback(this.el, true, response);
11887         }
11888     },
11889
11890     /**
11891      * @private
11892      */
11893     processFailure : function(response){
11894         this.transaction = null;
11895         this.fireEvent("failure", this.el, response);
11896         if(typeof response.argument.callback == "function"){
11897             response.argument.callback(this.el, false, response);
11898         }
11899     },
11900
11901     /**
11902      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11903      * @param {Object} renderer The object implementing the render() method
11904      */
11905     setRenderer : function(renderer){
11906         this.renderer = renderer;
11907     },
11908
11909     getRenderer : function(){
11910        return this.renderer;
11911     },
11912
11913     /**
11914      * Set the defaultUrl used for updates
11915      * @param {String/Function} defaultUrl The url or a function to call to get the url
11916      */
11917     setDefaultUrl : function(defaultUrl){
11918         this.defaultUrl = defaultUrl;
11919     },
11920
11921     /**
11922      * Aborts the executing transaction
11923      */
11924     abort : function(){
11925         if(this.transaction){
11926             Roo.Ajax.abort(this.transaction);
11927         }
11928     },
11929
11930     /**
11931      * Returns true if an update is in progress
11932      * @return {Boolean}
11933      */
11934     isUpdating : function(){
11935         if(this.transaction){
11936             return Roo.Ajax.isLoading(this.transaction);
11937         }
11938         return false;
11939     }
11940 });
11941
11942 /**
11943  * @class Roo.UpdateManager.defaults
11944  * @static (not really - but it helps the doc tool)
11945  * The defaults collection enables customizing the default properties of UpdateManager
11946  */
11947    Roo.UpdateManager.defaults = {
11948        /**
11949          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11950          * @type Number
11951          */
11952          timeout : 30,
11953
11954          /**
11955          * True to process scripts by default (Defaults to false).
11956          * @type Boolean
11957          */
11958         loadScripts : false,
11959
11960         /**
11961         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11962         * @type String
11963         */
11964         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11965         /**
11966          * Whether to append unique parameter on get request to disable caching (Defaults to false).
11967          * @type Boolean
11968          */
11969         disableCaching : false,
11970         /**
11971          * Whether to show indicatorText when loading (Defaults to true).
11972          * @type Boolean
11973          */
11974         showLoadIndicator : true,
11975         /**
11976          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11977          * @type String
11978          */
11979         indicatorText : '<div class="loading-indicator">Loading...</div>'
11980    };
11981
11982 /**
11983  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11984  *Usage:
11985  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11986  * @param {String/HTMLElement/Roo.Element} el The element to update
11987  * @param {String} url The url
11988  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11989  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11990  * @static
11991  * @deprecated
11992  * @member Roo.UpdateManager
11993  */
11994 Roo.UpdateManager.updateElement = function(el, url, params, options){
11995     var um = Roo.get(el, true).getUpdateManager();
11996     Roo.apply(um, options);
11997     um.update(url, params, options ? options.callback : null);
11998 };
11999 // alias for backwards compat
12000 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12001 /**
12002  * @class Roo.UpdateManager.BasicRenderer
12003  * Default Content renderer. Updates the elements innerHTML with the responseText.
12004  */
12005 Roo.UpdateManager.BasicRenderer = function(){};
12006
12007 Roo.UpdateManager.BasicRenderer.prototype = {
12008     /**
12009      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12010      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12011      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12012      * @param {Roo.Element} el The element being rendered
12013      * @param {Object} response The YUI Connect response object
12014      * @param {UpdateManager} updateManager The calling update manager
12015      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12016      */
12017      render : function(el, response, updateManager, callback){
12018         el.update(response.responseText, updateManager.loadScripts, callback);
12019     }
12020 };
12021 /*
12022  * Based on:
12023  * Ext JS Library 1.1.1
12024  * Copyright(c) 2006-2007, Ext JS, LLC.
12025  *
12026  * Originally Released Under LGPL - original licence link has changed is not relivant.
12027  *
12028  * Fork - LGPL
12029  * <script type="text/javascript">
12030  */
12031
12032 /**
12033  * @class Roo.util.DelayedTask
12034  * Provides a convenient method of performing setTimeout where a new
12035  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12036  * You can use this class to buffer
12037  * the keypress events for a certain number of milliseconds, and perform only if they stop
12038  * for that amount of time.
12039  * @constructor The parameters to this constructor serve as defaults and are not required.
12040  * @param {Function} fn (optional) The default function to timeout
12041  * @param {Object} scope (optional) The default scope of that timeout
12042  * @param {Array} args (optional) The default Array of arguments
12043  */
12044 Roo.util.DelayedTask = function(fn, scope, args){
12045     var id = null, d, t;
12046
12047     var call = function(){
12048         var now = new Date().getTime();
12049         if(now - t >= d){
12050             clearInterval(id);
12051             id = null;
12052             fn.apply(scope, args || []);
12053         }
12054     };
12055     /**
12056      * Cancels any pending timeout and queues a new one
12057      * @param {Number} delay The milliseconds to delay
12058      * @param {Function} newFn (optional) Overrides function passed to constructor
12059      * @param {Object} newScope (optional) Overrides scope passed to constructor
12060      * @param {Array} newArgs (optional) Overrides args passed to constructor
12061      */
12062     this.delay = function(delay, newFn, newScope, newArgs){
12063         if(id && delay != d){
12064             this.cancel();
12065         }
12066         d = delay;
12067         t = new Date().getTime();
12068         fn = newFn || fn;
12069         scope = newScope || scope;
12070         args = newArgs || args;
12071         if(!id){
12072             id = setInterval(call, d);
12073         }
12074     };
12075
12076     /**
12077      * Cancel the last queued timeout
12078      */
12079     this.cancel = function(){
12080         if(id){
12081             clearInterval(id);
12082             id = null;
12083         }
12084     };
12085 };/*
12086  * Based on:
12087  * Ext JS Library 1.1.1
12088  * Copyright(c) 2006-2007, Ext JS, LLC.
12089  *
12090  * Originally Released Under LGPL - original licence link has changed is not relivant.
12091  *
12092  * Fork - LGPL
12093  * <script type="text/javascript">
12094  */
12095  
12096  
12097 Roo.util.TaskRunner = function(interval){
12098     interval = interval || 10;
12099     var tasks = [], removeQueue = [];
12100     var id = 0;
12101     var running = false;
12102
12103     var stopThread = function(){
12104         running = false;
12105         clearInterval(id);
12106         id = 0;
12107     };
12108
12109     var startThread = function(){
12110         if(!running){
12111             running = true;
12112             id = setInterval(runTasks, interval);
12113         }
12114     };
12115
12116     var removeTask = function(task){
12117         removeQueue.push(task);
12118         if(task.onStop){
12119             task.onStop();
12120         }
12121     };
12122
12123     var runTasks = function(){
12124         if(removeQueue.length > 0){
12125             for(var i = 0, len = removeQueue.length; i < len; i++){
12126                 tasks.remove(removeQueue[i]);
12127             }
12128             removeQueue = [];
12129             if(tasks.length < 1){
12130                 stopThread();
12131                 return;
12132             }
12133         }
12134         var now = new Date().getTime();
12135         for(var i = 0, len = tasks.length; i < len; ++i){
12136             var t = tasks[i];
12137             var itime = now - t.taskRunTime;
12138             if(t.interval <= itime){
12139                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12140                 t.taskRunTime = now;
12141                 if(rt === false || t.taskRunCount === t.repeat){
12142                     removeTask(t);
12143                     return;
12144                 }
12145             }
12146             if(t.duration && t.duration <= (now - t.taskStartTime)){
12147                 removeTask(t);
12148             }
12149         }
12150     };
12151
12152     /**
12153      * Queues a new task.
12154      * @param {Object} task
12155      */
12156     this.start = function(task){
12157         tasks.push(task);
12158         task.taskStartTime = new Date().getTime();
12159         task.taskRunTime = 0;
12160         task.taskRunCount = 0;
12161         startThread();
12162         return task;
12163     };
12164
12165     this.stop = function(task){
12166         removeTask(task);
12167         return task;
12168     };
12169
12170     this.stopAll = function(){
12171         stopThread();
12172         for(var i = 0, len = tasks.length; i < len; i++){
12173             if(tasks[i].onStop){
12174                 tasks[i].onStop();
12175             }
12176         }
12177         tasks = [];
12178         removeQueue = [];
12179     };
12180 };
12181
12182 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12183  * Based on:
12184  * Ext JS Library 1.1.1
12185  * Copyright(c) 2006-2007, Ext JS, LLC.
12186  *
12187  * Originally Released Under LGPL - original licence link has changed is not relivant.
12188  *
12189  * Fork - LGPL
12190  * <script type="text/javascript">
12191  */
12192
12193  
12194 /**
12195  * @class Roo.util.MixedCollection
12196  * @extends Roo.util.Observable
12197  * A Collection class that maintains both numeric indexes and keys and exposes events.
12198  * @constructor
12199  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12200  * collection (defaults to false)
12201  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12202  * and return the key value for that item.  This is used when available to look up the key on items that
12203  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12204  * equivalent to providing an implementation for the {@link #getKey} method.
12205  */
12206 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12207     this.items = [];
12208     this.map = {};
12209     this.keys = [];
12210     this.length = 0;
12211     this.addEvents({
12212         /**
12213          * @event clear
12214          * Fires when the collection is cleared.
12215          */
12216         "clear" : true,
12217         /**
12218          * @event add
12219          * Fires when an item is added to the collection.
12220          * @param {Number} index The index at which the item was added.
12221          * @param {Object} o The item added.
12222          * @param {String} key The key associated with the added item.
12223          */
12224         "add" : true,
12225         /**
12226          * @event replace
12227          * Fires when an item is replaced in the collection.
12228          * @param {String} key he key associated with the new added.
12229          * @param {Object} old The item being replaced.
12230          * @param {Object} new The new item.
12231          */
12232         "replace" : true,
12233         /**
12234          * @event remove
12235          * Fires when an item is removed from the collection.
12236          * @param {Object} o The item being removed.
12237          * @param {String} key (optional) The key associated with the removed item.
12238          */
12239         "remove" : true,
12240         "sort" : true
12241     });
12242     this.allowFunctions = allowFunctions === true;
12243     if(keyFn){
12244         this.getKey = keyFn;
12245     }
12246     Roo.util.MixedCollection.superclass.constructor.call(this);
12247 };
12248
12249 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12250     allowFunctions : false,
12251     
12252 /**
12253  * Adds an item to the collection.
12254  * @param {String} key The key to associate with the item
12255  * @param {Object} o The item to add.
12256  * @return {Object} The item added.
12257  */
12258     add : function(key, o){
12259         if(arguments.length == 1){
12260             o = arguments[0];
12261             key = this.getKey(o);
12262         }
12263         if(typeof key == "undefined" || key === null){
12264             this.length++;
12265             this.items.push(o);
12266             this.keys.push(null);
12267         }else{
12268             var old = this.map[key];
12269             if(old){
12270                 return this.replace(key, o);
12271             }
12272             this.length++;
12273             this.items.push(o);
12274             this.map[key] = o;
12275             this.keys.push(key);
12276         }
12277         this.fireEvent("add", this.length-1, o, key);
12278         return o;
12279     },
12280        
12281 /**
12282   * MixedCollection has a generic way to fetch keys if you implement getKey.
12283 <pre><code>
12284 // normal way
12285 var mc = new Roo.util.MixedCollection();
12286 mc.add(someEl.dom.id, someEl);
12287 mc.add(otherEl.dom.id, otherEl);
12288 //and so on
12289
12290 // using getKey
12291 var mc = new Roo.util.MixedCollection();
12292 mc.getKey = function(el){
12293    return el.dom.id;
12294 };
12295 mc.add(someEl);
12296 mc.add(otherEl);
12297
12298 // or via the constructor
12299 var mc = new Roo.util.MixedCollection(false, function(el){
12300    return el.dom.id;
12301 });
12302 mc.add(someEl);
12303 mc.add(otherEl);
12304 </code></pre>
12305  * @param o {Object} The item for which to find the key.
12306  * @return {Object} The key for the passed item.
12307  */
12308     getKey : function(o){
12309          return o.id; 
12310     },
12311    
12312 /**
12313  * Replaces an item in the collection.
12314  * @param {String} key The key associated with the item to replace, or the item to replace.
12315  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12316  * @return {Object}  The new item.
12317  */
12318     replace : function(key, o){
12319         if(arguments.length == 1){
12320             o = arguments[0];
12321             key = this.getKey(o);
12322         }
12323         var old = this.item(key);
12324         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12325              return this.add(key, o);
12326         }
12327         var index = this.indexOfKey(key);
12328         this.items[index] = o;
12329         this.map[key] = o;
12330         this.fireEvent("replace", key, old, o);
12331         return o;
12332     },
12333    
12334 /**
12335  * Adds all elements of an Array or an Object to the collection.
12336  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12337  * an Array of values, each of which are added to the collection.
12338  */
12339     addAll : function(objs){
12340         if(arguments.length > 1 || objs instanceof Array){
12341             var args = arguments.length > 1 ? arguments : objs;
12342             for(var i = 0, len = args.length; i < len; i++){
12343                 this.add(args[i]);
12344             }
12345         }else{
12346             for(var key in objs){
12347                 if(this.allowFunctions || typeof objs[key] != "function"){
12348                     this.add(key, objs[key]);
12349                 }
12350             }
12351         }
12352     },
12353    
12354 /**
12355  * Executes the specified function once for every item in the collection, passing each
12356  * item as the first and only parameter. returning false from the function will stop the iteration.
12357  * @param {Function} fn The function to execute for each item.
12358  * @param {Object} scope (optional) The scope in which to execute the function.
12359  */
12360     each : function(fn, scope){
12361         var items = [].concat(this.items); // each safe for removal
12362         for(var i = 0, len = items.length; i < len; i++){
12363             if(fn.call(scope || items[i], items[i], i, len) === false){
12364                 break;
12365             }
12366         }
12367     },
12368    
12369 /**
12370  * Executes the specified function once for every key in the collection, passing each
12371  * key, and its associated item as the first two parameters.
12372  * @param {Function} fn The function to execute for each item.
12373  * @param {Object} scope (optional) The scope in which to execute the function.
12374  */
12375     eachKey : function(fn, scope){
12376         for(var i = 0, len = this.keys.length; i < len; i++){
12377             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12378         }
12379     },
12380    
12381 /**
12382  * Returns the first item in the collection which elicits a true return value from the
12383  * passed selection function.
12384  * @param {Function} fn The selection function to execute for each item.
12385  * @param {Object} scope (optional) The scope in which to execute the function.
12386  * @return {Object} The first item in the collection which returned true from the selection function.
12387  */
12388     find : function(fn, scope){
12389         for(var i = 0, len = this.items.length; i < len; i++){
12390             if(fn.call(scope || window, this.items[i], this.keys[i])){
12391                 return this.items[i];
12392             }
12393         }
12394         return null;
12395     },
12396    
12397 /**
12398  * Inserts an item at the specified index in the collection.
12399  * @param {Number} index The index to insert the item at.
12400  * @param {String} key The key to associate with the new item, or the item itself.
12401  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12402  * @return {Object} The item inserted.
12403  */
12404     insert : function(index, key, o){
12405         if(arguments.length == 2){
12406             o = arguments[1];
12407             key = this.getKey(o);
12408         }
12409         if(index >= this.length){
12410             return this.add(key, o);
12411         }
12412         this.length++;
12413         this.items.splice(index, 0, o);
12414         if(typeof key != "undefined" && key != null){
12415             this.map[key] = o;
12416         }
12417         this.keys.splice(index, 0, key);
12418         this.fireEvent("add", index, o, key);
12419         return o;
12420     },
12421    
12422 /**
12423  * Removed an item from the collection.
12424  * @param {Object} o The item to remove.
12425  * @return {Object} The item removed.
12426  */
12427     remove : function(o){
12428         return this.removeAt(this.indexOf(o));
12429     },
12430    
12431 /**
12432  * Remove an item from a specified index in the collection.
12433  * @param {Number} index The index within the collection of the item to remove.
12434  */
12435     removeAt : function(index){
12436         if(index < this.length && index >= 0){
12437             this.length--;
12438             var o = this.items[index];
12439             this.items.splice(index, 1);
12440             var key = this.keys[index];
12441             if(typeof key != "undefined"){
12442                 delete this.map[key];
12443             }
12444             this.keys.splice(index, 1);
12445             this.fireEvent("remove", o, key);
12446         }
12447     },
12448    
12449 /**
12450  * Removed an item associated with the passed key fom the collection.
12451  * @param {String} key The key of the item to remove.
12452  */
12453     removeKey : function(key){
12454         return this.removeAt(this.indexOfKey(key));
12455     },
12456    
12457 /**
12458  * Returns the number of items in the collection.
12459  * @return {Number} the number of items in the collection.
12460  */
12461     getCount : function(){
12462         return this.length; 
12463     },
12464    
12465 /**
12466  * Returns index within the collection of the passed Object.
12467  * @param {Object} o The item to find the index of.
12468  * @return {Number} index of the item.
12469  */
12470     indexOf : function(o){
12471         if(!this.items.indexOf){
12472             for(var i = 0, len = this.items.length; i < len; i++){
12473                 if(this.items[i] == o) return i;
12474             }
12475             return -1;
12476         }else{
12477             return this.items.indexOf(o);
12478         }
12479     },
12480    
12481 /**
12482  * Returns index within the collection of the passed key.
12483  * @param {String} key The key to find the index of.
12484  * @return {Number} index of the key.
12485  */
12486     indexOfKey : function(key){
12487         if(!this.keys.indexOf){
12488             for(var i = 0, len = this.keys.length; i < len; i++){
12489                 if(this.keys[i] == key) return i;
12490             }
12491             return -1;
12492         }else{
12493             return this.keys.indexOf(key);
12494         }
12495     },
12496    
12497 /**
12498  * Returns the item associated with the passed key OR index. Key has priority over index.
12499  * @param {String/Number} key The key or index of the item.
12500  * @return {Object} The item associated with the passed key.
12501  */
12502     item : function(key){
12503         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12504         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12505     },
12506     
12507 /**
12508  * Returns the item at the specified index.
12509  * @param {Number} index The index of the item.
12510  * @return {Object}
12511  */
12512     itemAt : function(index){
12513         return this.items[index];
12514     },
12515     
12516 /**
12517  * Returns the item associated with the passed key.
12518  * @param {String/Number} key The key of the item.
12519  * @return {Object} The item associated with the passed key.
12520  */
12521     key : function(key){
12522         return this.map[key];
12523     },
12524    
12525 /**
12526  * Returns true if the collection contains the passed Object as an item.
12527  * @param {Object} o  The Object to look for in the collection.
12528  * @return {Boolean} True if the collection contains the Object as an item.
12529  */
12530     contains : function(o){
12531         return this.indexOf(o) != -1;
12532     },
12533    
12534 /**
12535  * Returns true if the collection contains the passed Object as a key.
12536  * @param {String} key The key to look for in the collection.
12537  * @return {Boolean} True if the collection contains the Object as a key.
12538  */
12539     containsKey : function(key){
12540         return typeof this.map[key] != "undefined";
12541     },
12542    
12543 /**
12544  * Removes all items from the collection.
12545  */
12546     clear : function(){
12547         this.length = 0;
12548         this.items = [];
12549         this.keys = [];
12550         this.map = {};
12551         this.fireEvent("clear");
12552     },
12553    
12554 /**
12555  * Returns the first item in the collection.
12556  * @return {Object} the first item in the collection..
12557  */
12558     first : function(){
12559         return this.items[0]; 
12560     },
12561    
12562 /**
12563  * Returns the last item in the collection.
12564  * @return {Object} the last item in the collection..
12565  */
12566     last : function(){
12567         return this.items[this.length-1];   
12568     },
12569     
12570     _sort : function(property, dir, fn){
12571         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12572         fn = fn || function(a, b){
12573             return a-b;
12574         };
12575         var c = [], k = this.keys, items = this.items;
12576         for(var i = 0, len = items.length; i < len; i++){
12577             c[c.length] = {key: k[i], value: items[i], index: i};
12578         }
12579         c.sort(function(a, b){
12580             var v = fn(a[property], b[property]) * dsc;
12581             if(v == 0){
12582                 v = (a.index < b.index ? -1 : 1);
12583             }
12584             return v;
12585         });
12586         for(var i = 0, len = c.length; i < len; i++){
12587             items[i] = c[i].value;
12588             k[i] = c[i].key;
12589         }
12590         this.fireEvent("sort", this);
12591     },
12592     
12593     /**
12594      * Sorts this collection with the passed comparison function
12595      * @param {String} direction (optional) "ASC" or "DESC"
12596      * @param {Function} fn (optional) comparison function
12597      */
12598     sort : function(dir, fn){
12599         this._sort("value", dir, fn);
12600     },
12601     
12602     /**
12603      * Sorts this collection by keys
12604      * @param {String} direction (optional) "ASC" or "DESC"
12605      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12606      */
12607     keySort : function(dir, fn){
12608         this._sort("key", dir, fn || function(a, b){
12609             return String(a).toUpperCase()-String(b).toUpperCase();
12610         });
12611     },
12612     
12613     /**
12614      * Returns a range of items in this collection
12615      * @param {Number} startIndex (optional) defaults to 0
12616      * @param {Number} endIndex (optional) default to the last item
12617      * @return {Array} An array of items
12618      */
12619     getRange : function(start, end){
12620         var items = this.items;
12621         if(items.length < 1){
12622             return [];
12623         }
12624         start = start || 0;
12625         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12626         var r = [];
12627         if(start <= end){
12628             for(var i = start; i <= end; i++) {
12629                     r[r.length] = items[i];
12630             }
12631         }else{
12632             for(var i = start; i >= end; i--) {
12633                     r[r.length] = items[i];
12634             }
12635         }
12636         return r;
12637     },
12638         
12639     /**
12640      * Filter the <i>objects</i> in this collection by a specific property. 
12641      * Returns a new collection that has been filtered.
12642      * @param {String} property A property on your objects
12643      * @param {String/RegExp} value Either string that the property values 
12644      * should start with or a RegExp to test against the property
12645      * @return {MixedCollection} The new filtered collection
12646      */
12647     filter : function(property, value){
12648         if(!value.exec){ // not a regex
12649             value = String(value);
12650             if(value.length == 0){
12651                 return this.clone();
12652             }
12653             value = new RegExp("^" + Roo.escapeRe(value), "i");
12654         }
12655         return this.filterBy(function(o){
12656             return o && value.test(o[property]);
12657         });
12658         },
12659     
12660     /**
12661      * Filter by a function. * Returns a new collection that has been filtered.
12662      * The passed function will be called with each 
12663      * object in the collection. If the function returns true, the value is included 
12664      * otherwise it is filtered.
12665      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12666      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12667      * @return {MixedCollection} The new filtered collection
12668      */
12669     filterBy : function(fn, scope){
12670         var r = new Roo.util.MixedCollection();
12671         r.getKey = this.getKey;
12672         var k = this.keys, it = this.items;
12673         for(var i = 0, len = it.length; i < len; i++){
12674             if(fn.call(scope||this, it[i], k[i])){
12675                                 r.add(k[i], it[i]);
12676                         }
12677         }
12678         return r;
12679     },
12680     
12681     /**
12682      * Creates a duplicate of this collection
12683      * @return {MixedCollection}
12684      */
12685     clone : function(){
12686         var r = new Roo.util.MixedCollection();
12687         var k = this.keys, it = this.items;
12688         for(var i = 0, len = it.length; i < len; i++){
12689             r.add(k[i], it[i]);
12690         }
12691         r.getKey = this.getKey;
12692         return r;
12693     }
12694 });
12695 /**
12696  * Returns the item associated with the passed key or index.
12697  * @method
12698  * @param {String/Number} key The key or index of the item.
12699  * @return {Object} The item associated with the passed key.
12700  */
12701 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12702  * Based on:
12703  * Ext JS Library 1.1.1
12704  * Copyright(c) 2006-2007, Ext JS, LLC.
12705  *
12706  * Originally Released Under LGPL - original licence link has changed is not relivant.
12707  *
12708  * Fork - LGPL
12709  * <script type="text/javascript">
12710  */
12711 /**
12712  * @class Roo.util.JSON
12713  * Modified version of Douglas Crockford"s json.js that doesn"t
12714  * mess with the Object prototype 
12715  * http://www.json.org/js.html
12716  * @singleton
12717  */
12718 Roo.util.JSON = new (function(){
12719     var useHasOwn = {}.hasOwnProperty ? true : false;
12720     
12721     // crashes Safari in some instances
12722     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12723     
12724     var pad = function(n) {
12725         return n < 10 ? "0" + n : n;
12726     };
12727     
12728     var m = {
12729         "\b": '\\b',
12730         "\t": '\\t',
12731         "\n": '\\n',
12732         "\f": '\\f',
12733         "\r": '\\r',
12734         '"' : '\\"',
12735         "\\": '\\\\'
12736     };
12737
12738     var encodeString = function(s){
12739         if (/["\\\x00-\x1f]/.test(s)) {
12740             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12741                 var c = m[b];
12742                 if(c){
12743                     return c;
12744                 }
12745                 c = b.charCodeAt();
12746                 return "\\u00" +
12747                     Math.floor(c / 16).toString(16) +
12748                     (c % 16).toString(16);
12749             }) + '"';
12750         }
12751         return '"' + s + '"';
12752     };
12753     
12754     var encodeArray = function(o){
12755         var a = ["["], b, i, l = o.length, v;
12756             for (i = 0; i < l; i += 1) {
12757                 v = o[i];
12758                 switch (typeof v) {
12759                     case "undefined":
12760                     case "function":
12761                     case "unknown":
12762                         break;
12763                     default:
12764                         if (b) {
12765                             a.push(',');
12766                         }
12767                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12768                         b = true;
12769                 }
12770             }
12771             a.push("]");
12772             return a.join("");
12773     };
12774     
12775     var encodeDate = function(o){
12776         return '"' + o.getFullYear() + "-" +
12777                 pad(o.getMonth() + 1) + "-" +
12778                 pad(o.getDate()) + "T" +
12779                 pad(o.getHours()) + ":" +
12780                 pad(o.getMinutes()) + ":" +
12781                 pad(o.getSeconds()) + '"';
12782     };
12783     
12784     /**
12785      * Encodes an Object, Array or other value
12786      * @param {Mixed} o The variable to encode
12787      * @return {String} The JSON string
12788      */
12789     this.encode = function(o)
12790     {
12791         // should this be extended to fully wrap stringify..
12792         
12793         if(typeof o == "undefined" || o === null){
12794             return "null";
12795         }else if(o instanceof Array){
12796             return encodeArray(o);
12797         }else if(o instanceof Date){
12798             return encodeDate(o);
12799         }else if(typeof o == "string"){
12800             return encodeString(o);
12801         }else if(typeof o == "number"){
12802             return isFinite(o) ? String(o) : "null";
12803         }else if(typeof o == "boolean"){
12804             return String(o);
12805         }else {
12806             var a = ["{"], b, i, v;
12807             for (i in o) {
12808                 if(!useHasOwn || o.hasOwnProperty(i)) {
12809                     v = o[i];
12810                     switch (typeof v) {
12811                     case "undefined":
12812                     case "function":
12813                     case "unknown":
12814                         break;
12815                     default:
12816                         if(b){
12817                             a.push(',');
12818                         }
12819                         a.push(this.encode(i), ":",
12820                                 v === null ? "null" : this.encode(v));
12821                         b = true;
12822                     }
12823                 }
12824             }
12825             a.push("}");
12826             return a.join("");
12827         }
12828     };
12829     
12830     /**
12831      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12832      * @param {String} json The JSON string
12833      * @return {Object} The resulting object
12834      */
12835     this.decode = function(json){
12836         
12837         return  /** eval:var:json */ eval("(" + json + ')');
12838     };
12839 })();
12840 /** 
12841  * Shorthand for {@link Roo.util.JSON#encode}
12842  * @member Roo encode 
12843  * @method */
12844 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12845 /** 
12846  * Shorthand for {@link Roo.util.JSON#decode}
12847  * @member Roo decode 
12848  * @method */
12849 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12850 /*
12851  * Based on:
12852  * Ext JS Library 1.1.1
12853  * Copyright(c) 2006-2007, Ext JS, LLC.
12854  *
12855  * Originally Released Under LGPL - original licence link has changed is not relivant.
12856  *
12857  * Fork - LGPL
12858  * <script type="text/javascript">
12859  */
12860  
12861 /**
12862  * @class Roo.util.Format
12863  * Reusable data formatting functions
12864  * @singleton
12865  */
12866 Roo.util.Format = function(){
12867     var trimRe = /^\s+|\s+$/g;
12868     return {
12869         /**
12870          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12871          * @param {String} value The string to truncate
12872          * @param {Number} length The maximum length to allow before truncating
12873          * @return {String} The converted text
12874          */
12875         ellipsis : function(value, len){
12876             if(value && value.length > len){
12877                 return value.substr(0, len-3)+"...";
12878             }
12879             return value;
12880         },
12881
12882         /**
12883          * Checks a reference and converts it to empty string if it is undefined
12884          * @param {Mixed} value Reference to check
12885          * @return {Mixed} Empty string if converted, otherwise the original value
12886          */
12887         undef : function(value){
12888             return typeof value != "undefined" ? value : "";
12889         },
12890
12891         /**
12892          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12893          * @param {String} value The string to encode
12894          * @return {String} The encoded text
12895          */
12896         htmlEncode : function(value){
12897             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12898         },
12899
12900         /**
12901          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12902          * @param {String} value The string to decode
12903          * @return {String} The decoded text
12904          */
12905         htmlDecode : function(value){
12906             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12907         },
12908
12909         /**
12910          * Trims any whitespace from either side of a string
12911          * @param {String} value The text to trim
12912          * @return {String} The trimmed text
12913          */
12914         trim : function(value){
12915             return String(value).replace(trimRe, "");
12916         },
12917
12918         /**
12919          * Returns a substring from within an original string
12920          * @param {String} value The original text
12921          * @param {Number} start The start index of the substring
12922          * @param {Number} length The length of the substring
12923          * @return {String} The substring
12924          */
12925         substr : function(value, start, length){
12926             return String(value).substr(start, length);
12927         },
12928
12929         /**
12930          * Converts a string to all lower case letters
12931          * @param {String} value The text to convert
12932          * @return {String} The converted text
12933          */
12934         lowercase : function(value){
12935             return String(value).toLowerCase();
12936         },
12937
12938         /**
12939          * Converts a string to all upper case letters
12940          * @param {String} value The text to convert
12941          * @return {String} The converted text
12942          */
12943         uppercase : function(value){
12944             return String(value).toUpperCase();
12945         },
12946
12947         /**
12948          * Converts the first character only of a string to upper case
12949          * @param {String} value The text to convert
12950          * @return {String} The converted text
12951          */
12952         capitalize : function(value){
12953             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12954         },
12955
12956         // private
12957         call : function(value, fn){
12958             if(arguments.length > 2){
12959                 var args = Array.prototype.slice.call(arguments, 2);
12960                 args.unshift(value);
12961                  
12962                 return /** eval:var:value */  eval(fn).apply(window, args);
12963             }else{
12964                 /** eval:var:value */
12965                 return /** eval:var:value */ eval(fn).call(window, value);
12966             }
12967         },
12968
12969        
12970         /**
12971          * safer version of Math.toFixed..??/
12972          * @param {Number/String} value The numeric value to format
12973          * @param {Number/String} value Decimal places 
12974          * @return {String} The formatted currency string
12975          */
12976         toFixed : function(v, n)
12977         {
12978             // why not use to fixed - precision is buggered???
12979             if (!n) {
12980                 return Math.round(v-0);
12981             }
12982             var fact = Math.pow(10,n+1);
12983             v = (Math.round((v-0)*fact))/fact;
12984             var z = (''+fact).substring(2);
12985             if (v == Math.floor(v)) {
12986                 return Math.floor(v) + '.' + z;
12987             }
12988             
12989             // now just padd decimals..
12990             var ps = String(v).split('.');
12991             var fd = (ps[1] + z);
12992             var r = fd.substring(0,n); 
12993             var rm = fd.substring(n); 
12994             if (rm < 5) {
12995                 return ps[0] + '.' + r;
12996             }
12997             r*=1; // turn it into a number;
12998             r++;
12999             if (String(r).length != n) {
13000                 ps[0]*=1;
13001                 ps[0]++;
13002                 r = String(r).substring(1); // chop the end off.
13003             }
13004             
13005             return ps[0] + '.' + r;
13006              
13007         },
13008         
13009         /**
13010          * Format a number as US currency
13011          * @param {Number/String} value The numeric value to format
13012          * @return {String} The formatted currency string
13013          */
13014         usMoney : function(v){
13015             v = (Math.round((v-0)*100))/100;
13016             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13017             v = String(v);
13018             var ps = v.split('.');
13019             var whole = ps[0];
13020             var sub = ps[1] ? '.'+ ps[1] : '.00';
13021             var r = /(\d+)(\d{3})/;
13022             while (r.test(whole)) {
13023                 whole = whole.replace(r, '$1' + ',' + '$2');
13024             }
13025             return "$" + whole + sub ;
13026         },
13027         
13028         /**
13029          * Parse a value into a formatted date using the specified format pattern.
13030          * @param {Mixed} value The value to format
13031          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13032          * @return {String} The formatted date string
13033          */
13034         date : function(v, format){
13035             if(!v){
13036                 return "";
13037             }
13038             if(!(v instanceof Date)){
13039                 v = new Date(Date.parse(v));
13040             }
13041             return v.dateFormat(format || "m/d/Y");
13042         },
13043
13044         /**
13045          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13046          * @param {String} format Any valid date format string
13047          * @return {Function} The date formatting function
13048          */
13049         dateRenderer : function(format){
13050             return function(v){
13051                 return Roo.util.Format.date(v, format);  
13052             };
13053         },
13054
13055         // private
13056         stripTagsRE : /<\/?[^>]+>/gi,
13057         
13058         /**
13059          * Strips all HTML tags
13060          * @param {Mixed} value The text from which to strip tags
13061          * @return {String} The stripped text
13062          */
13063         stripTags : function(v){
13064             return !v ? v : String(v).replace(this.stripTagsRE, "");
13065         }
13066     };
13067 }();/*
13068  * Based on:
13069  * Ext JS Library 1.1.1
13070  * Copyright(c) 2006-2007, Ext JS, LLC.
13071  *
13072  * Originally Released Under LGPL - original licence link has changed is not relivant.
13073  *
13074  * Fork - LGPL
13075  * <script type="text/javascript">
13076  */
13077
13078
13079  
13080
13081 /**
13082  * @class Roo.MasterTemplate
13083  * @extends Roo.Template
13084  * Provides a template that can have child templates. The syntax is:
13085 <pre><code>
13086 var t = new Roo.MasterTemplate(
13087         '&lt;select name="{name}"&gt;',
13088                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13089         '&lt;/select&gt;'
13090 );
13091 t.add('options', {value: 'foo', text: 'bar'});
13092 // or you can add multiple child elements in one shot
13093 t.addAll('options', [
13094     {value: 'foo', text: 'bar'},
13095     {value: 'foo2', text: 'bar2'},
13096     {value: 'foo3', text: 'bar3'}
13097 ]);
13098 // then append, applying the master template values
13099 t.append('my-form', {name: 'my-select'});
13100 </code></pre>
13101 * A name attribute for the child template is not required if you have only one child
13102 * template or you want to refer to them by index.
13103  */
13104 Roo.MasterTemplate = function(){
13105     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13106     this.originalHtml = this.html;
13107     var st = {};
13108     var m, re = this.subTemplateRe;
13109     re.lastIndex = 0;
13110     var subIndex = 0;
13111     while(m = re.exec(this.html)){
13112         var name = m[1], content = m[2];
13113         st[subIndex] = {
13114             name: name,
13115             index: subIndex,
13116             buffer: [],
13117             tpl : new Roo.Template(content)
13118         };
13119         if(name){
13120             st[name] = st[subIndex];
13121         }
13122         st[subIndex].tpl.compile();
13123         st[subIndex].tpl.call = this.call.createDelegate(this);
13124         subIndex++;
13125     }
13126     this.subCount = subIndex;
13127     this.subs = st;
13128 };
13129 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13130     /**
13131     * The regular expression used to match sub templates
13132     * @type RegExp
13133     * @property
13134     */
13135     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13136
13137     /**
13138      * Applies the passed values to a child template.
13139      * @param {String/Number} name (optional) The name or index of the child template
13140      * @param {Array/Object} values The values to be applied to the template
13141      * @return {MasterTemplate} this
13142      */
13143      add : function(name, values){
13144         if(arguments.length == 1){
13145             values = arguments[0];
13146             name = 0;
13147         }
13148         var s = this.subs[name];
13149         s.buffer[s.buffer.length] = s.tpl.apply(values);
13150         return this;
13151     },
13152
13153     /**
13154      * Applies all the passed values to a child template.
13155      * @param {String/Number} name (optional) The name or index of the child template
13156      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13157      * @param {Boolean} reset (optional) True to reset the template first
13158      * @return {MasterTemplate} this
13159      */
13160     fill : function(name, values, reset){
13161         var a = arguments;
13162         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13163             values = a[0];
13164             name = 0;
13165             reset = a[1];
13166         }
13167         if(reset){
13168             this.reset();
13169         }
13170         for(var i = 0, len = values.length; i < len; i++){
13171             this.add(name, values[i]);
13172         }
13173         return this;
13174     },
13175
13176     /**
13177      * Resets the template for reuse
13178      * @return {MasterTemplate} this
13179      */
13180      reset : function(){
13181         var s = this.subs;
13182         for(var i = 0; i < this.subCount; i++){
13183             s[i].buffer = [];
13184         }
13185         return this;
13186     },
13187
13188     applyTemplate : function(values){
13189         var s = this.subs;
13190         var replaceIndex = -1;
13191         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13192             return s[++replaceIndex].buffer.join("");
13193         });
13194         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13195     },
13196
13197     apply : function(){
13198         return this.applyTemplate.apply(this, arguments);
13199     },
13200
13201     compile : function(){return this;}
13202 });
13203
13204 /**
13205  * Alias for fill().
13206  * @method
13207  */
13208 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13209  /**
13210  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13211  * var tpl = Roo.MasterTemplate.from('element-id');
13212  * @param {String/HTMLElement} el
13213  * @param {Object} config
13214  * @static
13215  */
13216 Roo.MasterTemplate.from = function(el, config){
13217     el = Roo.getDom(el);
13218     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13219 };/*
13220  * Based on:
13221  * Ext JS Library 1.1.1
13222  * Copyright(c) 2006-2007, Ext JS, LLC.
13223  *
13224  * Originally Released Under LGPL - original licence link has changed is not relivant.
13225  *
13226  * Fork - LGPL
13227  * <script type="text/javascript">
13228  */
13229
13230  
13231 /**
13232  * @class Roo.util.CSS
13233  * Utility class for manipulating CSS rules
13234  * @singleton
13235  */
13236 Roo.util.CSS = function(){
13237         var rules = null;
13238         var doc = document;
13239
13240     var camelRe = /(-[a-z])/gi;
13241     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13242
13243    return {
13244    /**
13245     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13246     * tag and appended to the HEAD of the document.
13247     * @param {String|Object} cssText The text containing the css rules
13248     * @param {String} id An id to add to the stylesheet for later removal
13249     * @return {StyleSheet}
13250     */
13251     createStyleSheet : function(cssText, id){
13252         var ss;
13253         var head = doc.getElementsByTagName("head")[0];
13254         var nrules = doc.createElement("style");
13255         nrules.setAttribute("type", "text/css");
13256         if(id){
13257             nrules.setAttribute("id", id);
13258         }
13259         if (typeof(cssText) != 'string') {
13260             // support object maps..
13261             // not sure if this a good idea.. 
13262             // perhaps it should be merged with the general css handling
13263             // and handle js style props.
13264             var cssTextNew = [];
13265             for(var n in cssText) {
13266                 var citems = [];
13267                 for(var k in cssText[n]) {
13268                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13269                 }
13270                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13271                 
13272             }
13273             cssText = cssTextNew.join("\n");
13274             
13275         }
13276        
13277        
13278        if(Roo.isIE){
13279            head.appendChild(nrules);
13280            ss = nrules.styleSheet;
13281            ss.cssText = cssText;
13282        }else{
13283            try{
13284                 nrules.appendChild(doc.createTextNode(cssText));
13285            }catch(e){
13286                nrules.cssText = cssText; 
13287            }
13288            head.appendChild(nrules);
13289            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13290        }
13291        this.cacheStyleSheet(ss);
13292        return ss;
13293    },
13294
13295    /**
13296     * Removes a style or link tag by id
13297     * @param {String} id The id of the tag
13298     */
13299    removeStyleSheet : function(id){
13300        var existing = doc.getElementById(id);
13301        if(existing){
13302            existing.parentNode.removeChild(existing);
13303        }
13304    },
13305
13306    /**
13307     * Dynamically swaps an existing stylesheet reference for a new one
13308     * @param {String} id The id of an existing link tag to remove
13309     * @param {String} url The href of the new stylesheet to include
13310     */
13311    swapStyleSheet : function(id, url){
13312        this.removeStyleSheet(id);
13313        var ss = doc.createElement("link");
13314        ss.setAttribute("rel", "stylesheet");
13315        ss.setAttribute("type", "text/css");
13316        ss.setAttribute("id", id);
13317        ss.setAttribute("href", url);
13318        doc.getElementsByTagName("head")[0].appendChild(ss);
13319    },
13320    
13321    /**
13322     * Refresh the rule cache if you have dynamically added stylesheets
13323     * @return {Object} An object (hash) of rules indexed by selector
13324     */
13325    refreshCache : function(){
13326        return this.getRules(true);
13327    },
13328
13329    // private
13330    cacheStyleSheet : function(stylesheet){
13331        if(!rules){
13332            rules = {};
13333        }
13334        try{// try catch for cross domain access issue
13335            var ssRules = stylesheet.cssRules || stylesheet.rules;
13336            for(var j = ssRules.length-1; j >= 0; --j){
13337                rules[ssRules[j].selectorText] = ssRules[j];
13338            }
13339        }catch(e){}
13340    },
13341    
13342    /**
13343     * Gets all css rules for the document
13344     * @param {Boolean} refreshCache true to refresh the internal cache
13345     * @return {Object} An object (hash) of rules indexed by selector
13346     */
13347    getRules : function(refreshCache){
13348                 if(rules == null || refreshCache){
13349                         rules = {};
13350                         var ds = doc.styleSheets;
13351                         for(var i =0, len = ds.length; i < len; i++){
13352                             try{
13353                         this.cacheStyleSheet(ds[i]);
13354                     }catch(e){} 
13355                 }
13356                 }
13357                 return rules;
13358         },
13359         
13360         /**
13361     * Gets an an individual CSS rule by selector(s)
13362     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13363     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13364     * @return {CSSRule} The CSS rule or null if one is not found
13365     */
13366    getRule : function(selector, refreshCache){
13367                 var rs = this.getRules(refreshCache);
13368                 if(!(selector instanceof Array)){
13369                     return rs[selector];
13370                 }
13371                 for(var i = 0; i < selector.length; i++){
13372                         if(rs[selector[i]]){
13373                                 return rs[selector[i]];
13374                         }
13375                 }
13376                 return null;
13377         },
13378         
13379         
13380         /**
13381     * Updates a rule property
13382     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13383     * @param {String} property The css property
13384     * @param {String} value The new value for the property
13385     * @return {Boolean} true If a rule was found and updated
13386     */
13387    updateRule : function(selector, property, value){
13388                 if(!(selector instanceof Array)){
13389                         var rule = this.getRule(selector);
13390                         if(rule){
13391                                 rule.style[property.replace(camelRe, camelFn)] = value;
13392                                 return true;
13393                         }
13394                 }else{
13395                         for(var i = 0; i < selector.length; i++){
13396                                 if(this.updateRule(selector[i], property, value)){
13397                                         return true;
13398                                 }
13399                         }
13400                 }
13401                 return false;
13402         }
13403    };   
13404 }();/*
13405  * Based on:
13406  * Ext JS Library 1.1.1
13407  * Copyright(c) 2006-2007, Ext JS, LLC.
13408  *
13409  * Originally Released Under LGPL - original licence link has changed is not relivant.
13410  *
13411  * Fork - LGPL
13412  * <script type="text/javascript">
13413  */
13414
13415  
13416
13417 /**
13418  * @class Roo.util.ClickRepeater
13419  * @extends Roo.util.Observable
13420  * 
13421  * A wrapper class which can be applied to any element. Fires a "click" event while the
13422  * mouse is pressed. The interval between firings may be specified in the config but
13423  * defaults to 10 milliseconds.
13424  * 
13425  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13426  * 
13427  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13428  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13429  * Similar to an autorepeat key delay.
13430  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13431  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13432  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13433  *           "interval" and "delay" are ignored. "immediate" is honored.
13434  * @cfg {Boolean} preventDefault True to prevent the default click event
13435  * @cfg {Boolean} stopDefault True to stop the default click event
13436  * 
13437  * @history
13438  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13439  *     2007-02-02 jvs Renamed to ClickRepeater
13440  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13441  *
13442  *  @constructor
13443  * @param {String/HTMLElement/Element} el The element to listen on
13444  * @param {Object} config
13445  **/
13446 Roo.util.ClickRepeater = function(el, config)
13447 {
13448     this.el = Roo.get(el);
13449     this.el.unselectable();
13450
13451     Roo.apply(this, config);
13452
13453     this.addEvents({
13454     /**
13455      * @event mousedown
13456      * Fires when the mouse button is depressed.
13457      * @param {Roo.util.ClickRepeater} this
13458      */
13459         "mousedown" : true,
13460     /**
13461      * @event click
13462      * Fires on a specified interval during the time the element is pressed.
13463      * @param {Roo.util.ClickRepeater} this
13464      */
13465         "click" : true,
13466     /**
13467      * @event mouseup
13468      * Fires when the mouse key is released.
13469      * @param {Roo.util.ClickRepeater} this
13470      */
13471         "mouseup" : true
13472     });
13473
13474     this.el.on("mousedown", this.handleMouseDown, this);
13475     if(this.preventDefault || this.stopDefault){
13476         this.el.on("click", function(e){
13477             if(this.preventDefault){
13478                 e.preventDefault();
13479             }
13480             if(this.stopDefault){
13481                 e.stopEvent();
13482             }
13483         }, this);
13484     }
13485
13486     // allow inline handler
13487     if(this.handler){
13488         this.on("click", this.handler,  this.scope || this);
13489     }
13490
13491     Roo.util.ClickRepeater.superclass.constructor.call(this);
13492 };
13493
13494 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13495     interval : 20,
13496     delay: 250,
13497     preventDefault : true,
13498     stopDefault : false,
13499     timer : 0,
13500
13501     // private
13502     handleMouseDown : function(){
13503         clearTimeout(this.timer);
13504         this.el.blur();
13505         if(this.pressClass){
13506             this.el.addClass(this.pressClass);
13507         }
13508         this.mousedownTime = new Date();
13509
13510         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13511         this.el.on("mouseout", this.handleMouseOut, this);
13512
13513         this.fireEvent("mousedown", this);
13514         this.fireEvent("click", this);
13515         
13516         this.timer = this.click.defer(this.delay || this.interval, this);
13517     },
13518
13519     // private
13520     click : function(){
13521         this.fireEvent("click", this);
13522         this.timer = this.click.defer(this.getInterval(), this);
13523     },
13524
13525     // private
13526     getInterval: function(){
13527         if(!this.accelerate){
13528             return this.interval;
13529         }
13530         var pressTime = this.mousedownTime.getElapsed();
13531         if(pressTime < 500){
13532             return 400;
13533         }else if(pressTime < 1700){
13534             return 320;
13535         }else if(pressTime < 2600){
13536             return 250;
13537         }else if(pressTime < 3500){
13538             return 180;
13539         }else if(pressTime < 4400){
13540             return 140;
13541         }else if(pressTime < 5300){
13542             return 80;
13543         }else if(pressTime < 6200){
13544             return 50;
13545         }else{
13546             return 10;
13547         }
13548     },
13549
13550     // private
13551     handleMouseOut : function(){
13552         clearTimeout(this.timer);
13553         if(this.pressClass){
13554             this.el.removeClass(this.pressClass);
13555         }
13556         this.el.on("mouseover", this.handleMouseReturn, this);
13557     },
13558
13559     // private
13560     handleMouseReturn : function(){
13561         this.el.un("mouseover", this.handleMouseReturn);
13562         if(this.pressClass){
13563             this.el.addClass(this.pressClass);
13564         }
13565         this.click();
13566     },
13567
13568     // private
13569     handleMouseUp : function(){
13570         clearTimeout(this.timer);
13571         this.el.un("mouseover", this.handleMouseReturn);
13572         this.el.un("mouseout", this.handleMouseOut);
13573         Roo.get(document).un("mouseup", this.handleMouseUp);
13574         this.el.removeClass(this.pressClass);
13575         this.fireEvent("mouseup", this);
13576     }
13577 });/*
13578  * Based on:
13579  * Ext JS Library 1.1.1
13580  * Copyright(c) 2006-2007, Ext JS, LLC.
13581  *
13582  * Originally Released Under LGPL - original licence link has changed is not relivant.
13583  *
13584  * Fork - LGPL
13585  * <script type="text/javascript">
13586  */
13587
13588  
13589 /**
13590  * @class Roo.KeyNav
13591  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13592  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13593  * way to implement custom navigation schemes for any UI component.</p>
13594  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13595  * pageUp, pageDown, del, home, end.  Usage:</p>
13596  <pre><code>
13597 var nav = new Roo.KeyNav("my-element", {
13598     "left" : function(e){
13599         this.moveLeft(e.ctrlKey);
13600     },
13601     "right" : function(e){
13602         this.moveRight(e.ctrlKey);
13603     },
13604     "enter" : function(e){
13605         this.save();
13606     },
13607     scope : this
13608 });
13609 </code></pre>
13610  * @constructor
13611  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13612  * @param {Object} config The config
13613  */
13614 Roo.KeyNav = function(el, config){
13615     this.el = Roo.get(el);
13616     Roo.apply(this, config);
13617     if(!this.disabled){
13618         this.disabled = true;
13619         this.enable();
13620     }
13621 };
13622
13623 Roo.KeyNav.prototype = {
13624     /**
13625      * @cfg {Boolean} disabled
13626      * True to disable this KeyNav instance (defaults to false)
13627      */
13628     disabled : false,
13629     /**
13630      * @cfg {String} defaultEventAction
13631      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13632      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13633      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13634      */
13635     defaultEventAction: "stopEvent",
13636     /**
13637      * @cfg {Boolean} forceKeyDown
13638      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13639      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13640      * handle keydown instead of keypress.
13641      */
13642     forceKeyDown : false,
13643
13644     // private
13645     prepareEvent : function(e){
13646         var k = e.getKey();
13647         var h = this.keyToHandler[k];
13648         //if(h && this[h]){
13649         //    e.stopPropagation();
13650         //}
13651         if(Roo.isSafari && h && k >= 37 && k <= 40){
13652             e.stopEvent();
13653         }
13654     },
13655
13656     // private
13657     relay : function(e){
13658         var k = e.getKey();
13659         var h = this.keyToHandler[k];
13660         if(h && this[h]){
13661             if(this.doRelay(e, this[h], h) !== true){
13662                 e[this.defaultEventAction]();
13663             }
13664         }
13665     },
13666
13667     // private
13668     doRelay : function(e, h, hname){
13669         return h.call(this.scope || this, e);
13670     },
13671
13672     // possible handlers
13673     enter : false,
13674     left : false,
13675     right : false,
13676     up : false,
13677     down : false,
13678     tab : false,
13679     esc : false,
13680     pageUp : false,
13681     pageDown : false,
13682     del : false,
13683     home : false,
13684     end : false,
13685
13686     // quick lookup hash
13687     keyToHandler : {
13688         37 : "left",
13689         39 : "right",
13690         38 : "up",
13691         40 : "down",
13692         33 : "pageUp",
13693         34 : "pageDown",
13694         46 : "del",
13695         36 : "home",
13696         35 : "end",
13697         13 : "enter",
13698         27 : "esc",
13699         9  : "tab"
13700     },
13701
13702         /**
13703          * Enable this KeyNav
13704          */
13705         enable: function(){
13706                 if(this.disabled){
13707             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13708             // the EventObject will normalize Safari automatically
13709             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13710                 this.el.on("keydown", this.relay,  this);
13711             }else{
13712                 this.el.on("keydown", this.prepareEvent,  this);
13713                 this.el.on("keypress", this.relay,  this);
13714             }
13715                     this.disabled = false;
13716                 }
13717         },
13718
13719         /**
13720          * Disable this KeyNav
13721          */
13722         disable: function(){
13723                 if(!this.disabled){
13724                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13725                 this.el.un("keydown", this.relay);
13726             }else{
13727                 this.el.un("keydown", this.prepareEvent);
13728                 this.el.un("keypress", this.relay);
13729             }
13730                     this.disabled = true;
13731                 }
13732         }
13733 };/*
13734  * Based on:
13735  * Ext JS Library 1.1.1
13736  * Copyright(c) 2006-2007, Ext JS, LLC.
13737  *
13738  * Originally Released Under LGPL - original licence link has changed is not relivant.
13739  *
13740  * Fork - LGPL
13741  * <script type="text/javascript">
13742  */
13743
13744  
13745 /**
13746  * @class Roo.KeyMap
13747  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13748  * The constructor accepts the same config object as defined by {@link #addBinding}.
13749  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13750  * combination it will call the function with this signature (if the match is a multi-key
13751  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13752  * A KeyMap can also handle a string representation of keys.<br />
13753  * Usage:
13754  <pre><code>
13755 // map one key by key code
13756 var map = new Roo.KeyMap("my-element", {
13757     key: 13, // or Roo.EventObject.ENTER
13758     fn: myHandler,
13759     scope: myObject
13760 });
13761
13762 // map multiple keys to one action by string
13763 var map = new Roo.KeyMap("my-element", {
13764     key: "a\r\n\t",
13765     fn: myHandler,
13766     scope: myObject
13767 });
13768
13769 // map multiple keys to multiple actions by strings and array of codes
13770 var map = new Roo.KeyMap("my-element", [
13771     {
13772         key: [10,13],
13773         fn: function(){ alert("Return was pressed"); }
13774     }, {
13775         key: "abc",
13776         fn: function(){ alert('a, b or c was pressed'); }
13777     }, {
13778         key: "\t",
13779         ctrl:true,
13780         shift:true,
13781         fn: function(){ alert('Control + shift + tab was pressed.'); }
13782     }
13783 ]);
13784 </code></pre>
13785  * <b>Note: A KeyMap starts enabled</b>
13786  * @constructor
13787  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13788  * @param {Object} config The config (see {@link #addBinding})
13789  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13790  */
13791 Roo.KeyMap = function(el, config, eventName){
13792     this.el  = Roo.get(el);
13793     this.eventName = eventName || "keydown";
13794     this.bindings = [];
13795     if(config){
13796         this.addBinding(config);
13797     }
13798     this.enable();
13799 };
13800
13801 Roo.KeyMap.prototype = {
13802     /**
13803      * True to stop the event from bubbling and prevent the default browser action if the
13804      * key was handled by the KeyMap (defaults to false)
13805      * @type Boolean
13806      */
13807     stopEvent : false,
13808
13809     /**
13810      * Add a new binding to this KeyMap. The following config object properties are supported:
13811      * <pre>
13812 Property    Type             Description
13813 ----------  ---------------  ----------------------------------------------------------------------
13814 key         String/Array     A single keycode or an array of keycodes to handle
13815 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13816 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13817 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13818 fn          Function         The function to call when KeyMap finds the expected key combination
13819 scope       Object           The scope of the callback function
13820 </pre>
13821      *
13822      * Usage:
13823      * <pre><code>
13824 // Create a KeyMap
13825 var map = new Roo.KeyMap(document, {
13826     key: Roo.EventObject.ENTER,
13827     fn: handleKey,
13828     scope: this
13829 });
13830
13831 //Add a new binding to the existing KeyMap later
13832 map.addBinding({
13833     key: 'abc',
13834     shift: true,
13835     fn: handleKey,
13836     scope: this
13837 });
13838 </code></pre>
13839      * @param {Object/Array} config A single KeyMap config or an array of configs
13840      */
13841         addBinding : function(config){
13842         if(config instanceof Array){
13843             for(var i = 0, len = config.length; i < len; i++){
13844                 this.addBinding(config[i]);
13845             }
13846             return;
13847         }
13848         var keyCode = config.key,
13849             shift = config.shift, 
13850             ctrl = config.ctrl, 
13851             alt = config.alt,
13852             fn = config.fn,
13853             scope = config.scope;
13854         if(typeof keyCode == "string"){
13855             var ks = [];
13856             var keyString = keyCode.toUpperCase();
13857             for(var j = 0, len = keyString.length; j < len; j++){
13858                 ks.push(keyString.charCodeAt(j));
13859             }
13860             keyCode = ks;
13861         }
13862         var keyArray = keyCode instanceof Array;
13863         var handler = function(e){
13864             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13865                 var k = e.getKey();
13866                 if(keyArray){
13867                     for(var i = 0, len = keyCode.length; i < len; i++){
13868                         if(keyCode[i] == k){
13869                           if(this.stopEvent){
13870                               e.stopEvent();
13871                           }
13872                           fn.call(scope || window, k, e);
13873                           return;
13874                         }
13875                     }
13876                 }else{
13877                     if(k == keyCode){
13878                         if(this.stopEvent){
13879                            e.stopEvent();
13880                         }
13881                         fn.call(scope || window, k, e);
13882                     }
13883                 }
13884             }
13885         };
13886         this.bindings.push(handler);  
13887         },
13888
13889     /**
13890      * Shorthand for adding a single key listener
13891      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13892      * following options:
13893      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13894      * @param {Function} fn The function to call
13895      * @param {Object} scope (optional) The scope of the function
13896      */
13897     on : function(key, fn, scope){
13898         var keyCode, shift, ctrl, alt;
13899         if(typeof key == "object" && !(key instanceof Array)){
13900             keyCode = key.key;
13901             shift = key.shift;
13902             ctrl = key.ctrl;
13903             alt = key.alt;
13904         }else{
13905             keyCode = key;
13906         }
13907         this.addBinding({
13908             key: keyCode,
13909             shift: shift,
13910             ctrl: ctrl,
13911             alt: alt,
13912             fn: fn,
13913             scope: scope
13914         })
13915     },
13916
13917     // private
13918     handleKeyDown : function(e){
13919             if(this.enabled){ //just in case
13920             var b = this.bindings;
13921             for(var i = 0, len = b.length; i < len; i++){
13922                 b[i].call(this, e);
13923             }
13924             }
13925         },
13926         
13927         /**
13928          * Returns true if this KeyMap is enabled
13929          * @return {Boolean} 
13930          */
13931         isEnabled : function(){
13932             return this.enabled;  
13933         },
13934         
13935         /**
13936          * Enables this KeyMap
13937          */
13938         enable: function(){
13939                 if(!this.enabled){
13940                     this.el.on(this.eventName, this.handleKeyDown, this);
13941                     this.enabled = true;
13942                 }
13943         },
13944
13945         /**
13946          * Disable this KeyMap
13947          */
13948         disable: function(){
13949                 if(this.enabled){
13950                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
13951                     this.enabled = false;
13952                 }
13953         }
13954 };/*
13955  * Based on:
13956  * Ext JS Library 1.1.1
13957  * Copyright(c) 2006-2007, Ext JS, LLC.
13958  *
13959  * Originally Released Under LGPL - original licence link has changed is not relivant.
13960  *
13961  * Fork - LGPL
13962  * <script type="text/javascript">
13963  */
13964
13965  
13966 /**
13967  * @class Roo.util.TextMetrics
13968  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13969  * wide, in pixels, a given block of text will be.
13970  * @singleton
13971  */
13972 Roo.util.TextMetrics = function(){
13973     var shared;
13974     return {
13975         /**
13976          * Measures the size of the specified text
13977          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13978          * that can affect the size of the rendered text
13979          * @param {String} text The text to measure
13980          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13981          * in order to accurately measure the text height
13982          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13983          */
13984         measure : function(el, text, fixedWidth){
13985             if(!shared){
13986                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13987             }
13988             shared.bind(el);
13989             shared.setFixedWidth(fixedWidth || 'auto');
13990             return shared.getSize(text);
13991         },
13992
13993         /**
13994          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
13995          * the overhead of multiple calls to initialize the style properties on each measurement.
13996          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13997          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13998          * in order to accurately measure the text height
13999          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14000          */
14001         createInstance : function(el, fixedWidth){
14002             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14003         }
14004     };
14005 }();
14006
14007  
14008
14009 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14010     var ml = new Roo.Element(document.createElement('div'));
14011     document.body.appendChild(ml.dom);
14012     ml.position('absolute');
14013     ml.setLeftTop(-1000, -1000);
14014     ml.hide();
14015
14016     if(fixedWidth){
14017         ml.setWidth(fixedWidth);
14018     }
14019      
14020     var instance = {
14021         /**
14022          * Returns the size of the specified text based on the internal element's style and width properties
14023          * @memberOf Roo.util.TextMetrics.Instance#
14024          * @param {String} text The text to measure
14025          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14026          */
14027         getSize : function(text){
14028             ml.update(text);
14029             var s = ml.getSize();
14030             ml.update('');
14031             return s;
14032         },
14033
14034         /**
14035          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14036          * that can affect the size of the rendered text
14037          * @memberOf Roo.util.TextMetrics.Instance#
14038          * @param {String/HTMLElement} el The element, dom node or id
14039          */
14040         bind : function(el){
14041             ml.setStyle(
14042                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14043             );
14044         },
14045
14046         /**
14047          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14048          * to set a fixed width in order to accurately measure the text height.
14049          * @memberOf Roo.util.TextMetrics.Instance#
14050          * @param {Number} width The width to set on the element
14051          */
14052         setFixedWidth : function(width){
14053             ml.setWidth(width);
14054         },
14055
14056         /**
14057          * Returns the measured width of the specified text
14058          * @memberOf Roo.util.TextMetrics.Instance#
14059          * @param {String} text The text to measure
14060          * @return {Number} width The width in pixels
14061          */
14062         getWidth : function(text){
14063             ml.dom.style.width = 'auto';
14064             return this.getSize(text).width;
14065         },
14066
14067         /**
14068          * Returns the measured height of the specified text.  For multiline text, be sure to call
14069          * {@link #setFixedWidth} if necessary.
14070          * @memberOf Roo.util.TextMetrics.Instance#
14071          * @param {String} text The text to measure
14072          * @return {Number} height The height in pixels
14073          */
14074         getHeight : function(text){
14075             return this.getSize(text).height;
14076         }
14077     };
14078
14079     instance.bind(bindTo);
14080
14081     return instance;
14082 };
14083
14084 // backwards compat
14085 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14086  * Based on:
14087  * Ext JS Library 1.1.1
14088  * Copyright(c) 2006-2007, Ext JS, LLC.
14089  *
14090  * Originally Released Under LGPL - original licence link has changed is not relivant.
14091  *
14092  * Fork - LGPL
14093  * <script type="text/javascript">
14094  */
14095
14096 /**
14097  * @class Roo.state.Provider
14098  * Abstract base class for state provider implementations. This class provides methods
14099  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14100  * Provider interface.
14101  */
14102 Roo.state.Provider = function(){
14103     /**
14104      * @event statechange
14105      * Fires when a state change occurs.
14106      * @param {Provider} this This state provider
14107      * @param {String} key The state key which was changed
14108      * @param {String} value The encoded value for the state
14109      */
14110     this.addEvents({
14111         "statechange": true
14112     });
14113     this.state = {};
14114     Roo.state.Provider.superclass.constructor.call(this);
14115 };
14116 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14117     /**
14118      * Returns the current value for a key
14119      * @param {String} name The key name
14120      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14121      * @return {Mixed} The state data
14122      */
14123     get : function(name, defaultValue){
14124         return typeof this.state[name] == "undefined" ?
14125             defaultValue : this.state[name];
14126     },
14127     
14128     /**
14129      * Clears a value from the state
14130      * @param {String} name The key name
14131      */
14132     clear : function(name){
14133         delete this.state[name];
14134         this.fireEvent("statechange", this, name, null);
14135     },
14136     
14137     /**
14138      * Sets the value for a key
14139      * @param {String} name The key name
14140      * @param {Mixed} value The value to set
14141      */
14142     set : function(name, value){
14143         this.state[name] = value;
14144         this.fireEvent("statechange", this, name, value);
14145     },
14146     
14147     /**
14148      * Decodes a string previously encoded with {@link #encodeValue}.
14149      * @param {String} value The value to decode
14150      * @return {Mixed} The decoded value
14151      */
14152     decodeValue : function(cookie){
14153         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14154         var matches = re.exec(unescape(cookie));
14155         if(!matches || !matches[1]) return; // non state cookie
14156         var type = matches[1];
14157         var v = matches[2];
14158         switch(type){
14159             case "n":
14160                 return parseFloat(v);
14161             case "d":
14162                 return new Date(Date.parse(v));
14163             case "b":
14164                 return (v == "1");
14165             case "a":
14166                 var all = [];
14167                 var values = v.split("^");
14168                 for(var i = 0, len = values.length; i < len; i++){
14169                     all.push(this.decodeValue(values[i]));
14170                 }
14171                 return all;
14172            case "o":
14173                 var all = {};
14174                 var values = v.split("^");
14175                 for(var i = 0, len = values.length; i < len; i++){
14176                     var kv = values[i].split("=");
14177                     all[kv[0]] = this.decodeValue(kv[1]);
14178                 }
14179                 return all;
14180            default:
14181                 return v;
14182         }
14183     },
14184     
14185     /**
14186      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14187      * @param {Mixed} value The value to encode
14188      * @return {String} The encoded value
14189      */
14190     encodeValue : function(v){
14191         var enc;
14192         if(typeof v == "number"){
14193             enc = "n:" + v;
14194         }else if(typeof v == "boolean"){
14195             enc = "b:" + (v ? "1" : "0");
14196         }else if(v instanceof Date){
14197             enc = "d:" + v.toGMTString();
14198         }else if(v instanceof Array){
14199             var flat = "";
14200             for(var i = 0, len = v.length; i < len; i++){
14201                 flat += this.encodeValue(v[i]);
14202                 if(i != len-1) flat += "^";
14203             }
14204             enc = "a:" + flat;
14205         }else if(typeof v == "object"){
14206             var flat = "";
14207             for(var key in v){
14208                 if(typeof v[key] != "function"){
14209                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14210                 }
14211             }
14212             enc = "o:" + flat.substring(0, flat.length-1);
14213         }else{
14214             enc = "s:" + v;
14215         }
14216         return escape(enc);        
14217     }
14218 });
14219
14220 /*
14221  * Based on:
14222  * Ext JS Library 1.1.1
14223  * Copyright(c) 2006-2007, Ext JS, LLC.
14224  *
14225  * Originally Released Under LGPL - original licence link has changed is not relivant.
14226  *
14227  * Fork - LGPL
14228  * <script type="text/javascript">
14229  */
14230 /**
14231  * @class Roo.state.Manager
14232  * This is the global state manager. By default all components that are "state aware" check this class
14233  * for state information if you don't pass them a custom state provider. In order for this class
14234  * to be useful, it must be initialized with a provider when your application initializes.
14235  <pre><code>
14236 // in your initialization function
14237 init : function(){
14238    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14239    ...
14240    // supposed you have a {@link Roo.BorderLayout}
14241    var layout = new Roo.BorderLayout(...);
14242    layout.restoreState();
14243    // or a {Roo.BasicDialog}
14244    var dialog = new Roo.BasicDialog(...);
14245    dialog.restoreState();
14246  </code></pre>
14247  * @singleton
14248  */
14249 Roo.state.Manager = function(){
14250     var provider = new Roo.state.Provider();
14251     
14252     return {
14253         /**
14254          * Configures the default state provider for your application
14255          * @param {Provider} stateProvider The state provider to set
14256          */
14257         setProvider : function(stateProvider){
14258             provider = stateProvider;
14259         },
14260         
14261         /**
14262          * Returns the current value for a key
14263          * @param {String} name The key name
14264          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14265          * @return {Mixed} The state data
14266          */
14267         get : function(key, defaultValue){
14268             return provider.get(key, defaultValue);
14269         },
14270         
14271         /**
14272          * Sets the value for a key
14273          * @param {String} name The key name
14274          * @param {Mixed} value The state data
14275          */
14276          set : function(key, value){
14277             provider.set(key, value);
14278         },
14279         
14280         /**
14281          * Clears a value from the state
14282          * @param {String} name The key name
14283          */
14284         clear : function(key){
14285             provider.clear(key);
14286         },
14287         
14288         /**
14289          * Gets the currently configured state provider
14290          * @return {Provider} The state provider
14291          */
14292         getProvider : function(){
14293             return provider;
14294         }
14295     };
14296 }();
14297 /*
14298  * Based on:
14299  * Ext JS Library 1.1.1
14300  * Copyright(c) 2006-2007, Ext JS, LLC.
14301  *
14302  * Originally Released Under LGPL - original licence link has changed is not relivant.
14303  *
14304  * Fork - LGPL
14305  * <script type="text/javascript">
14306  */
14307 /**
14308  * @class Roo.state.CookieProvider
14309  * @extends Roo.state.Provider
14310  * The default Provider implementation which saves state via cookies.
14311  * <br />Usage:
14312  <pre><code>
14313    var cp = new Roo.state.CookieProvider({
14314        path: "/cgi-bin/",
14315        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14316        domain: "roojs.com"
14317    })
14318    Roo.state.Manager.setProvider(cp);
14319  </code></pre>
14320  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14321  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14322  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14323  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14324  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14325  * domain the page is running on including the 'www' like 'www.roojs.com')
14326  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14327  * @constructor
14328  * Create a new CookieProvider
14329  * @param {Object} config The configuration object
14330  */
14331 Roo.state.CookieProvider = function(config){
14332     Roo.state.CookieProvider.superclass.constructor.call(this);
14333     this.path = "/";
14334     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14335     this.domain = null;
14336     this.secure = false;
14337     Roo.apply(this, config);
14338     this.state = this.readCookies();
14339 };
14340
14341 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14342     // private
14343     set : function(name, value){
14344         if(typeof value == "undefined" || value === null){
14345             this.clear(name);
14346             return;
14347         }
14348         this.setCookie(name, value);
14349         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14350     },
14351
14352     // private
14353     clear : function(name){
14354         this.clearCookie(name);
14355         Roo.state.CookieProvider.superclass.clear.call(this, name);
14356     },
14357
14358     // private
14359     readCookies : function(){
14360         var cookies = {};
14361         var c = document.cookie + ";";
14362         var re = /\s?(.*?)=(.*?);/g;
14363         var matches;
14364         while((matches = re.exec(c)) != null){
14365             var name = matches[1];
14366             var value = matches[2];
14367             if(name && name.substring(0,3) == "ys-"){
14368                 cookies[name.substr(3)] = this.decodeValue(value);
14369             }
14370         }
14371         return cookies;
14372     },
14373
14374     // private
14375     setCookie : function(name, value){
14376         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14377            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14378            ((this.path == null) ? "" : ("; path=" + this.path)) +
14379            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14380            ((this.secure == true) ? "; secure" : "");
14381     },
14382
14383     // private
14384     clearCookie : function(name){
14385         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14386            ((this.path == null) ? "" : ("; path=" + this.path)) +
14387            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14388            ((this.secure == true) ? "; secure" : "");
14389     }
14390 });