710cb8bb46b0f91c9be9eb2309da73f39a4ad638
[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
576 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
577                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
578 /*
579  * Based on:
580  * Ext JS Library 1.1.1
581  * Copyright(c) 2006-2007, Ext JS, LLC.
582  *
583  * Originally Released Under LGPL - original licence link has changed is not relivant.
584  *
585  * Fork - LGPL
586  * <script type="text/javascript">
587  */
588
589 (function() {    
590     // wrappedn so fnCleanup is not in global scope...
591     if(Roo.isIE) {
592         function fnCleanUp() {
593             var p = Function.prototype;
594             delete p.createSequence;
595             delete p.defer;
596             delete p.createDelegate;
597             delete p.createCallback;
598             delete p.createInterceptor;
599
600             window.detachEvent("onunload", fnCleanUp);
601         }
602         window.attachEvent("onunload", fnCleanUp);
603     }
604 })();
605
606
607 /**
608  * @class Function
609  * These functions are available on every Function object (any JavaScript function).
610  */
611 Roo.apply(Function.prototype, {
612      /**
613      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
614      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
615      * Will create a function that is bound to those 2 args.
616      * @return {Function} The new function
617     */
618     createCallback : function(/*args...*/){
619         // make args available, in function below
620         var args = arguments;
621         var method = this;
622         return function() {
623             return method.apply(window, args);
624         };
625     },
626
627     /**
628      * Creates a delegate (callback) that sets the scope to obj.
629      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
630      * Will create a function that is automatically scoped to this.
631      * @param {Object} obj (optional) The object for which the scope is set
632      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
633      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
634      *                                             if a number the args are inserted at the specified position
635      * @return {Function} The new function
636      */
637     createDelegate : function(obj, args, appendArgs){
638         var method = this;
639         return function() {
640             var callArgs = args || arguments;
641             if(appendArgs === true){
642                 callArgs = Array.prototype.slice.call(arguments, 0);
643                 callArgs = callArgs.concat(args);
644             }else if(typeof appendArgs == "number"){
645                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
646                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
647                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
648             }
649             return method.apply(obj || window, callArgs);
650         };
651     },
652
653     /**
654      * Calls this function after the number of millseconds specified.
655      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
656      * @param {Object} obj (optional) The object for which the scope is set
657      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
658      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
659      *                                             if a number the args are inserted at the specified position
660      * @return {Number} The timeout id that can be used with clearTimeout
661      */
662     defer : function(millis, obj, args, appendArgs){
663         var fn = this.createDelegate(obj, args, appendArgs);
664         if(millis){
665             return setTimeout(fn, millis);
666         }
667         fn();
668         return 0;
669     },
670     /**
671      * Create a combined function call sequence of the original function + the passed function.
672      * The resulting function returns the results of the original function.
673      * The passed fcn is called with the parameters of the original function
674      * @param {Function} fcn The function to sequence
675      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
676      * @return {Function} The new function
677      */
678     createSequence : function(fcn, scope){
679         if(typeof fcn != "function"){
680             return this;
681         }
682         var method = this;
683         return function() {
684             var retval = method.apply(this || window, arguments);
685             fcn.apply(scope || this || window, arguments);
686             return retval;
687         };
688     },
689
690     /**
691      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
692      * The resulting function returns the results of the original function.
693      * The passed fcn is called with the parameters of the original function.
694      * @addon
695      * @param {Function} fcn The function to call before the original
696      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
697      * @return {Function} The new function
698      */
699     createInterceptor : function(fcn, scope){
700         if(typeof fcn != "function"){
701             return this;
702         }
703         var method = this;
704         return function() {
705             fcn.target = this;
706             fcn.method = method;
707             if(fcn.apply(scope || this || window, arguments) === false){
708                 return;
709             }
710             return method.apply(this || window, arguments);
711         };
712     }
713 });
714 /*
715  * Based on:
716  * Ext JS Library 1.1.1
717  * Copyright(c) 2006-2007, Ext JS, LLC.
718  *
719  * Originally Released Under LGPL - original licence link has changed is not relivant.
720  *
721  * Fork - LGPL
722  * <script type="text/javascript">
723  */
724
725 Roo.applyIf(String, {
726     
727     /** @scope String */
728     
729     /**
730      * Escapes the passed string for ' and \
731      * @param {String} string The string to escape
732      * @return {String} The escaped string
733      * @static
734      */
735     escape : function(string) {
736         return string.replace(/('|\\)/g, "\\$1");
737     },
738
739     /**
740      * Pads the left side of a string with a specified character.  This is especially useful
741      * for normalizing number and date strings.  Example usage:
742      * <pre><code>
743 var s = String.leftPad('123', 5, '0');
744 // s now contains the string: '00123'
745 </code></pre>
746      * @param {String} string The original string
747      * @param {Number} size The total length of the output string
748      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
749      * @return {String} The padded string
750      * @static
751      */
752     leftPad : function (val, size, ch) {
753         var result = new String(val);
754         if(ch === null || ch === undefined || ch === '') {
755             ch = " ";
756         }
757         while (result.length < size) {
758             result = ch + result;
759         }
760         return result;
761     },
762
763     /**
764      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
765      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
766      * <pre><code>
767 var cls = 'my-class', text = 'Some text';
768 var s = String.format('<div class="{0}">{1}</div>', cls, text);
769 // s now contains the string: '<div class="my-class">Some text</div>'
770 </code></pre>
771      * @param {String} string The tokenized string to be formatted
772      * @param {String} value1 The value to replace token {0}
773      * @param {String} value2 Etc...
774      * @return {String} The formatted string
775      * @static
776      */
777     format : function(format){
778         var args = Array.prototype.slice.call(arguments, 1);
779         return format.replace(/\{(\d+)\}/g, function(m, i){
780             return Roo.util.Format.htmlEncode(args[i]);
781         });
782     }
783 });
784
785 /**
786  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
787  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
788  * they are already different, the first value passed in is returned.  Note that this method returns the new value
789  * but does not change the current string.
790  * <pre><code>
791 // alternate sort directions
792 sort = sort.toggle('ASC', 'DESC');
793
794 // instead of conditional logic:
795 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
796 </code></pre>
797  * @param {String} value The value to compare to the current string
798  * @param {String} other The new value to use if the string already equals the first value passed in
799  * @return {String} The new value
800  */
801  
802 String.prototype.toggle = function(value, other){
803     return this == value ? other : value;
804 };/*
805  * Based on:
806  * Ext JS Library 1.1.1
807  * Copyright(c) 2006-2007, Ext JS, LLC.
808  *
809  * Originally Released Under LGPL - original licence link has changed is not relivant.
810  *
811  * Fork - LGPL
812  * <script type="text/javascript">
813  */
814
815  /**
816  * @class Number
817  */
818 Roo.applyIf(Number.prototype, {
819     /**
820      * Checks whether or not the current number is within a desired range.  If the number is already within the
821      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
822      * exceeded.  Note that this method returns the constrained value but does not change the current number.
823      * @param {Number} min The minimum number in the range
824      * @param {Number} max The maximum number in the range
825      * @return {Number} The constrained value if outside the range, otherwise the current value
826      */
827     constrain : function(min, max){
828         return Math.min(Math.max(this, min), max);
829     }
830 });/*
831  * Based on:
832  * Ext JS Library 1.1.1
833  * Copyright(c) 2006-2007, Ext JS, LLC.
834  *
835  * Originally Released Under LGPL - original licence link has changed is not relivant.
836  *
837  * Fork - LGPL
838  * <script type="text/javascript">
839  */
840  /**
841  * @class Array
842  */
843 Roo.applyIf(Array.prototype, {
844     /**
845      * Checks whether or not the specified object exists in the array.
846      * @param {Object} o The object to check for
847      * @return {Number} The index of o in the array (or -1 if it is not found)
848      */
849     indexOf : function(o){
850        for (var i = 0, len = this.length; i < len; i++){
851               if(this[i] == o) return i;
852        }
853            return -1;
854     },
855
856     /**
857      * Removes the specified object from the array.  If the object is not found nothing happens.
858      * @param {Object} o The object to remove
859      */
860     remove : function(o){
861        var index = this.indexOf(o);
862        if(index != -1){
863            this.splice(index, 1);
864        }
865     },
866     /**
867      * Map (JS 1.6 compatibility)
868      * @param {Function} function  to call
869      */
870     map : function(fun )
871     {
872         var len = this.length >>> 0;
873         if (typeof fun != "function")
874             throw new TypeError();
875
876         var res = new Array(len);
877         var thisp = arguments[1];
878         for (var i = 0; i < len; i++)
879         {
880             if (i in this)
881                 res[i] = fun.call(thisp, this[i], i, this);
882         }
883
884         return res;
885     }
886     
887 });
888
889
890  /*
891  * Based on:
892  * Ext JS Library 1.1.1
893  * Copyright(c) 2006-2007, Ext JS, LLC.
894  *
895  * Originally Released Under LGPL - original licence link has changed is not relivant.
896  *
897  * Fork - LGPL
898  * <script type="text/javascript">
899  */
900
901 /**
902  * @class Date
903  *
904  * The date parsing and format syntax is a subset of
905  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
906  * supported will provide results equivalent to their PHP versions.
907  *
908  * Following is the list of all currently supported formats:
909  *<pre>
910 Sample date:
911 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
912
913 Format  Output      Description
914 ------  ----------  --------------------------------------------------------------
915   d      10         Day of the month, 2 digits with leading zeros
916   D      Wed        A textual representation of a day, three letters
917   j      10         Day of the month without leading zeros
918   l      Wednesday  A full textual representation of the day of the week
919   S      th         English ordinal day of month suffix, 2 chars (use with j)
920   w      3          Numeric representation of the day of the week
921   z      9          The julian date, or day of the year (0-365)
922   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
923   F      January    A full textual representation of the month
924   m      01         Numeric representation of a month, with leading zeros
925   M      Jan        Month name abbreviation, three letters
926   n      1          Numeric representation of a month, without leading zeros
927   t      31         Number of days in the given month
928   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
929   Y      2007       A full numeric representation of a year, 4 digits
930   y      07         A two digit representation of a year
931   a      pm         Lowercase Ante meridiem and Post meridiem
932   A      PM         Uppercase Ante meridiem and Post meridiem
933   g      3          12-hour format of an hour without leading zeros
934   G      15         24-hour format of an hour without leading zeros
935   h      03         12-hour format of an hour with leading zeros
936   H      15         24-hour format of an hour with leading zeros
937   i      05         Minutes with leading zeros
938   s      01         Seconds, with leading zeros
939   O      -0600      Difference to Greenwich time (GMT) in hours
940   T      CST        Timezone setting of the machine running the code
941   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
942 </pre>
943  *
944  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
945  * <pre><code>
946 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
947 document.write(dt.format('Y-m-d'));                         //2007-01-10
948 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
949 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
950  </code></pre>
951  *
952  * Here are some standard date/time patterns that you might find helpful.  They
953  * are not part of the source of Date.js, but to use them you can simply copy this
954  * block of code into any script that is included after Date.js and they will also become
955  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
956  * <pre><code>
957 Date.patterns = {
958     ISO8601Long:"Y-m-d H:i:s",
959     ISO8601Short:"Y-m-d",
960     ShortDate: "n/j/Y",
961     LongDate: "l, F d, Y",
962     FullDateTime: "l, F d, Y g:i:s A",
963     MonthDay: "F d",
964     ShortTime: "g:i A",
965     LongTime: "g:i:s A",
966     SortableDateTime: "Y-m-d\\TH:i:s",
967     UniversalSortableDateTime: "Y-m-d H:i:sO",
968     YearMonth: "F, Y"
969 };
970 </code></pre>
971  *
972  * Example usage:
973  * <pre><code>
974 var dt = new Date();
975 document.write(dt.format(Date.patterns.ShortDate));
976  </code></pre>
977  */
978
979 /*
980  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
981  * They generate precompiled functions from date formats instead of parsing and
982  * processing the pattern every time you format a date.  These functions are available
983  * on every Date object (any javascript function).
984  *
985  * The original article and download are here:
986  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
987  *
988  */
989  
990  
991  // was in core
992 /**
993  Returns the number of milliseconds between this date and date
994  @param {Date} date (optional) Defaults to now
995  @return {Number} The diff in milliseconds
996  @member Date getElapsed
997  */
998 Date.prototype.getElapsed = function(date) {
999         return Math.abs((date || new Date()).getTime()-this.getTime());
1000 };
1001 // was in date file..
1002
1003
1004 // private
1005 Date.parseFunctions = {count:0};
1006 // private
1007 Date.parseRegexes = [];
1008 // private
1009 Date.formatFunctions = {count:0};
1010
1011 // private
1012 Date.prototype.dateFormat = function(format) {
1013     if (Date.formatFunctions[format] == null) {
1014         Date.createNewFormat(format);
1015     }
1016     var func = Date.formatFunctions[format];
1017     return this[func]();
1018 };
1019
1020
1021 /**
1022  * Formats a date given the supplied format string
1023  * @param {String} format The format string
1024  * @return {String} The formatted date
1025  * @method
1026  */
1027 Date.prototype.format = Date.prototype.dateFormat;
1028
1029 // private
1030 Date.createNewFormat = function(format) {
1031     var funcName = "format" + Date.formatFunctions.count++;
1032     Date.formatFunctions[format] = funcName;
1033     var code = "Date.prototype." + funcName + " = function(){return ";
1034     var special = false;
1035     var ch = '';
1036     for (var i = 0; i < format.length; ++i) {
1037         ch = format.charAt(i);
1038         if (!special && ch == "\\") {
1039             special = true;
1040         }
1041         else if (special) {
1042             special = false;
1043             code += "'" + String.escape(ch) + "' + ";
1044         }
1045         else {
1046             code += Date.getFormatCode(ch);
1047         }
1048     }
1049     /** eval:var:zzzzzzzzzzzzz */
1050     eval(code.substring(0, code.length - 3) + ";}");
1051 };
1052
1053 // private
1054 Date.getFormatCode = function(character) {
1055     switch (character) {
1056     case "d":
1057         return "String.leftPad(this.getDate(), 2, '0') + ";
1058     case "D":
1059         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1060     case "j":
1061         return "this.getDate() + ";
1062     case "l":
1063         return "Date.dayNames[this.getDay()] + ";
1064     case "S":
1065         return "this.getSuffix() + ";
1066     case "w":
1067         return "this.getDay() + ";
1068     case "z":
1069         return "this.getDayOfYear() + ";
1070     case "W":
1071         return "this.getWeekOfYear() + ";
1072     case "F":
1073         return "Date.monthNames[this.getMonth()] + ";
1074     case "m":
1075         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1076     case "M":
1077         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1078     case "n":
1079         return "(this.getMonth() + 1) + ";
1080     case "t":
1081         return "this.getDaysInMonth() + ";
1082     case "L":
1083         return "(this.isLeapYear() ? 1 : 0) + ";
1084     case "Y":
1085         return "this.getFullYear() + ";
1086     case "y":
1087         return "('' + this.getFullYear()).substring(2, 4) + ";
1088     case "a":
1089         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1090     case "A":
1091         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1092     case "g":
1093         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1094     case "G":
1095         return "this.getHours() + ";
1096     case "h":
1097         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1098     case "H":
1099         return "String.leftPad(this.getHours(), 2, '0') + ";
1100     case "i":
1101         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1102     case "s":
1103         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1104     case "O":
1105         return "this.getGMTOffset() + ";
1106     case "T":
1107         return "this.getTimezone() + ";
1108     case "Z":
1109         return "(this.getTimezoneOffset() * -60) + ";
1110     default:
1111         return "'" + String.escape(character) + "' + ";
1112     }
1113 };
1114
1115 /**
1116  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1117  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1118  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1119  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1120  * string or the parse operation will fail.
1121  * Example Usage:
1122 <pre><code>
1123 //dt = Fri May 25 2007 (current date)
1124 var dt = new Date();
1125
1126 //dt = Thu May 25 2006 (today's month/day in 2006)
1127 dt = Date.parseDate("2006", "Y");
1128
1129 //dt = Sun Jan 15 2006 (all date parts specified)
1130 dt = Date.parseDate("2006-1-15", "Y-m-d");
1131
1132 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1133 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1134 </code></pre>
1135  * @param {String} input The unparsed date as a string
1136  * @param {String} format The format the date is in
1137  * @return {Date} The parsed date
1138  * @static
1139  */
1140 Date.parseDate = function(input, format) {
1141     if (Date.parseFunctions[format] == null) {
1142         Date.createParser(format);
1143     }
1144     var func = Date.parseFunctions[format];
1145     return Date[func](input);
1146 };
1147 /**
1148  * @private
1149  */
1150 Date.createParser = function(format) {
1151     var funcName = "parse" + Date.parseFunctions.count++;
1152     var regexNum = Date.parseRegexes.length;
1153     var currentGroup = 1;
1154     Date.parseFunctions[format] = funcName;
1155
1156     var code = "Date." + funcName + " = function(input){\n"
1157         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1158         + "var d = new Date();\n"
1159         + "y = d.getFullYear();\n"
1160         + "m = d.getMonth();\n"
1161         + "d = d.getDate();\n"
1162         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1163         + "if (results && results.length > 0) {";
1164     var regex = "";
1165
1166     var special = false;
1167     var ch = '';
1168     for (var i = 0; i < format.length; ++i) {
1169         ch = format.charAt(i);
1170         if (!special && ch == "\\") {
1171             special = true;
1172         }
1173         else if (special) {
1174             special = false;
1175             regex += String.escape(ch);
1176         }
1177         else {
1178             var obj = Date.formatCodeToRegex(ch, currentGroup);
1179             currentGroup += obj.g;
1180             regex += obj.s;
1181             if (obj.g && obj.c) {
1182                 code += obj.c;
1183             }
1184         }
1185     }
1186
1187     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1188         + "{v = new Date(y, m, d, h, i, s);}\n"
1189         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1190         + "{v = new Date(y, m, d, h, i);}\n"
1191         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1192         + "{v = new Date(y, m, d, h);}\n"
1193         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1194         + "{v = new Date(y, m, d);}\n"
1195         + "else if (y >= 0 && m >= 0)\n"
1196         + "{v = new Date(y, m);}\n"
1197         + "else if (y >= 0)\n"
1198         + "{v = new Date(y);}\n"
1199         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1200         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1201         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1202         + ";}";
1203
1204     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1205     /** eval:var:zzzzzzzzzzzzz */
1206     eval(code);
1207 };
1208
1209 // private
1210 Date.formatCodeToRegex = function(character, currentGroup) {
1211     switch (character) {
1212     case "D":
1213         return {g:0,
1214         c:null,
1215         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1216     case "j":
1217         return {g:1,
1218             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1219             s:"(\\d{1,2})"}; // day of month without leading zeroes
1220     case "d":
1221         return {g:1,
1222             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1223             s:"(\\d{2})"}; // day of month with leading zeroes
1224     case "l":
1225         return {g:0,
1226             c:null,
1227             s:"(?:" + Date.dayNames.join("|") + ")"};
1228     case "S":
1229         return {g:0,
1230             c:null,
1231             s:"(?:st|nd|rd|th)"};
1232     case "w":
1233         return {g:0,
1234             c:null,
1235             s:"\\d"};
1236     case "z":
1237         return {g:0,
1238             c:null,
1239             s:"(?:\\d{1,3})"};
1240     case "W":
1241         return {g:0,
1242             c:null,
1243             s:"(?:\\d{2})"};
1244     case "F":
1245         return {g:1,
1246             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1247             s:"(" + Date.monthNames.join("|") + ")"};
1248     case "M":
1249         return {g:1,
1250             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1251             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1252     case "n":
1253         return {g:1,
1254             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1255             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1256     case "m":
1257         return {g:1,
1258             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1259             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1260     case "t":
1261         return {g:0,
1262             c:null,
1263             s:"\\d{1,2}"};
1264     case "L":
1265         return {g:0,
1266             c:null,
1267             s:"(?:1|0)"};
1268     case "Y":
1269         return {g:1,
1270             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1271             s:"(\\d{4})"};
1272     case "y":
1273         return {g:1,
1274             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1275                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1276             s:"(\\d{1,2})"};
1277     case "a":
1278         return {g:1,
1279             c:"if (results[" + currentGroup + "] == 'am') {\n"
1280                 + "if (h == 12) { h = 0; }\n"
1281                 + "} else { if (h < 12) { h += 12; }}",
1282             s:"(am|pm)"};
1283     case "A":
1284         return {g:1,
1285             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1286                 + "if (h == 12) { h = 0; }\n"
1287                 + "} else { if (h < 12) { h += 12; }}",
1288             s:"(AM|PM)"};
1289     case "g":
1290     case "G":
1291         return {g:1,
1292             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1293             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1294     case "h":
1295     case "H":
1296         return {g:1,
1297             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1299     case "i":
1300         return {g:1,
1301             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1302             s:"(\\d{2})"};
1303     case "s":
1304         return {g:1,
1305             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1306             s:"(\\d{2})"};
1307     case "O":
1308         return {g:1,
1309             c:[
1310                 "o = results[", currentGroup, "];\n",
1311                 "var sn = o.substring(0,1);\n", // get + / - sign
1312                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1313                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1314                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1315                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1316             ].join(""),
1317             s:"([+\-]\\d{4})"};
1318     case "T":
1319         return {g:0,
1320             c:null,
1321             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1322     case "Z":
1323         return {g:1,
1324             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1325                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1326             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1327     default:
1328         return {g:0,
1329             c:null,
1330             s:String.escape(character)};
1331     }
1332 };
1333
1334 /**
1335  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1336  * @return {String} The abbreviated timezone name (e.g. 'CST')
1337  */
1338 Date.prototype.getTimezone = function() {
1339     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1340 };
1341
1342 /**
1343  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1344  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1345  */
1346 Date.prototype.getGMTOffset = function() {
1347     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1348         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1349         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1350 };
1351
1352 /**
1353  * Get the numeric day number of the year, adjusted for leap year.
1354  * @return {Number} 0 through 364 (365 in leap years)
1355  */
1356 Date.prototype.getDayOfYear = function() {
1357     var num = 0;
1358     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1359     for (var i = 0; i < this.getMonth(); ++i) {
1360         num += Date.daysInMonth[i];
1361     }
1362     return num + this.getDate() - 1;
1363 };
1364
1365 /**
1366  * Get the string representation of the numeric week number of the year
1367  * (equivalent to the format specifier 'W').
1368  * @return {String} '00' through '52'
1369  */
1370 Date.prototype.getWeekOfYear = function() {
1371     // Skip to Thursday of this week
1372     var now = this.getDayOfYear() + (4 - this.getDay());
1373     // Find the first Thursday of the year
1374     var jan1 = new Date(this.getFullYear(), 0, 1);
1375     var then = (7 - jan1.getDay() + 4);
1376     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1377 };
1378
1379 /**
1380  * Whether or not the current date is in a leap year.
1381  * @return {Boolean} True if the current date is in a leap year, else false
1382  */
1383 Date.prototype.isLeapYear = function() {
1384     var year = this.getFullYear();
1385     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1386 };
1387
1388 /**
1389  * Get the first day of the current month, adjusted for leap year.  The returned value
1390  * is the numeric day index within the week (0-6) which can be used in conjunction with
1391  * the {@link #monthNames} array to retrieve the textual day name.
1392  * Example:
1393  *<pre><code>
1394 var dt = new Date('1/10/2007');
1395 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1396 </code></pre>
1397  * @return {Number} The day number (0-6)
1398  */
1399 Date.prototype.getFirstDayOfMonth = function() {
1400     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1401     return (day < 0) ? (day + 7) : day;
1402 };
1403
1404 /**
1405  * Get the last 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.getLastDayOfMonth()]); //output: 'Wednesday'
1412 </code></pre>
1413  * @return {Number} The day number (0-6)
1414  */
1415 Date.prototype.getLastDayOfMonth = function() {
1416     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1417     return (day < 0) ? (day + 7) : day;
1418 };
1419
1420
1421 /**
1422  * Get the first date of this date's month
1423  * @return {Date}
1424  */
1425 Date.prototype.getFirstDateOfMonth = function() {
1426     return new Date(this.getFullYear(), this.getMonth(), 1);
1427 };
1428
1429 /**
1430  * Get the last date of this date's month
1431  * @return {Date}
1432  */
1433 Date.prototype.getLastDateOfMonth = function() {
1434     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1435 };
1436 /**
1437  * Get the number of days in the current month, adjusted for leap year.
1438  * @return {Number} The number of days in the month
1439  */
1440 Date.prototype.getDaysInMonth = function() {
1441     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1442     return Date.daysInMonth[this.getMonth()];
1443 };
1444
1445 /**
1446  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1447  * @return {String} 'st, 'nd', 'rd' or 'th'
1448  */
1449 Date.prototype.getSuffix = function() {
1450     switch (this.getDate()) {
1451         case 1:
1452         case 21:
1453         case 31:
1454             return "st";
1455         case 2:
1456         case 22:
1457             return "nd";
1458         case 3:
1459         case 23:
1460             return "rd";
1461         default:
1462             return "th";
1463     }
1464 };
1465
1466 // private
1467 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1468
1469 /**
1470  * An array of textual month names.
1471  * Override these values for international dates, for example...
1472  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1473  * @type Array
1474  * @static
1475  */
1476 Date.monthNames =
1477    ["January",
1478     "February",
1479     "March",
1480     "April",
1481     "May",
1482     "June",
1483     "July",
1484     "August",
1485     "September",
1486     "October",
1487     "November",
1488     "December"];
1489
1490 /**
1491  * An array of textual day names.
1492  * Override these values for international dates, for example...
1493  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1494  * @type Array
1495  * @static
1496  */
1497 Date.dayNames =
1498    ["Sunday",
1499     "Monday",
1500     "Tuesday",
1501     "Wednesday",
1502     "Thursday",
1503     "Friday",
1504     "Saturday"];
1505
1506 // private
1507 Date.y2kYear = 50;
1508 // private
1509 Date.monthNumbers = {
1510     Jan:0,
1511     Feb:1,
1512     Mar:2,
1513     Apr:3,
1514     May:4,
1515     Jun:5,
1516     Jul:6,
1517     Aug:7,
1518     Sep:8,
1519     Oct:9,
1520     Nov:10,
1521     Dec:11};
1522
1523 /**
1524  * Creates and returns a new Date instance with the exact same date value as the called instance.
1525  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1526  * variable will also be changed.  When the intention is to create a new variable that will not
1527  * modify the original instance, you should create a clone.
1528  *
1529  * Example of correctly cloning a date:
1530  * <pre><code>
1531 //wrong way:
1532 var orig = new Date('10/1/2006');
1533 var copy = orig;
1534 copy.setDate(5);
1535 document.write(orig);  //returns 'Thu Oct 05 2006'!
1536
1537 //correct way:
1538 var orig = new Date('10/1/2006');
1539 var copy = orig.clone();
1540 copy.setDate(5);
1541 document.write(orig);  //returns 'Thu Oct 01 2006'
1542 </code></pre>
1543  * @return {Date} The new Date instance
1544  */
1545 Date.prototype.clone = function() {
1546         return new Date(this.getTime());
1547 };
1548
1549 /**
1550  * Clears any time information from this date
1551  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1552  @return {Date} this or the clone
1553  */
1554 Date.prototype.clearTime = function(clone){
1555     if(clone){
1556         return this.clone().clearTime();
1557     }
1558     this.setHours(0);
1559     this.setMinutes(0);
1560     this.setSeconds(0);
1561     this.setMilliseconds(0);
1562     return this;
1563 };
1564
1565 // private
1566 // safari setMonth is broken
1567 if(Roo.isSafari){
1568     Date.brokenSetMonth = Date.prototype.setMonth;
1569         Date.prototype.setMonth = function(num){
1570                 if(num <= -1){
1571                         var n = Math.ceil(-num);
1572                         var back_year = Math.ceil(n/12);
1573                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1574                         this.setFullYear(this.getFullYear() - back_year);
1575                         return Date.brokenSetMonth.call(this, month);
1576                 } else {
1577                         return Date.brokenSetMonth.apply(this, arguments);
1578                 }
1579         };
1580 }
1581
1582 /** Date interval constant 
1583 * @static 
1584 * @type String */
1585 Date.MILLI = "ms";
1586 /** Date interval constant 
1587 * @static 
1588 * @type String */
1589 Date.SECOND = "s";
1590 /** Date interval constant 
1591 * @static 
1592 * @type String */
1593 Date.MINUTE = "mi";
1594 /** Date interval constant 
1595 * @static 
1596 * @type String */
1597 Date.HOUR = "h";
1598 /** Date interval constant 
1599 * @static 
1600 * @type String */
1601 Date.DAY = "d";
1602 /** Date interval constant 
1603 * @static 
1604 * @type String */
1605 Date.MONTH = "mo";
1606 /** Date interval constant 
1607 * @static 
1608 * @type String */
1609 Date.YEAR = "y";
1610
1611 /**
1612  * Provides a convenient method of performing basic date arithmetic.  This method
1613  * does not modify the Date instance being called - it creates and returns
1614  * a new Date instance containing the resulting date value.
1615  *
1616  * Examples:
1617  * <pre><code>
1618 //Basic usage:
1619 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1620 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1621
1622 //Negative values will subtract correctly:
1623 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1624 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1625
1626 //You can even chain several calls together in one line!
1627 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1628 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1629  </code></pre>
1630  *
1631  * @param {String} interval   A valid date interval enum value
1632  * @param {Number} value      The amount to add to the current date
1633  * @return {Date} The new Date instance
1634  */
1635 Date.prototype.add = function(interval, value){
1636   var d = this.clone();
1637   if (!interval || value === 0) return d;
1638   switch(interval.toLowerCase()){
1639     case Date.MILLI:
1640       d.setMilliseconds(this.getMilliseconds() + value);
1641       break;
1642     case Date.SECOND:
1643       d.setSeconds(this.getSeconds() + value);
1644       break;
1645     case Date.MINUTE:
1646       d.setMinutes(this.getMinutes() + value);
1647       break;
1648     case Date.HOUR:
1649       d.setHours(this.getHours() + value);
1650       break;
1651     case Date.DAY:
1652       d.setDate(this.getDate() + value);
1653       break;
1654     case Date.MONTH:
1655       var day = this.getDate();
1656       if(day > 28){
1657           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1658       }
1659       d.setDate(day);
1660       d.setMonth(this.getMonth() + value);
1661       break;
1662     case Date.YEAR:
1663       d.setFullYear(this.getFullYear() + value);
1664       break;
1665   }
1666   return d;
1667 };/*
1668  * Based on:
1669  * Ext JS Library 1.1.1
1670  * Copyright(c) 2006-2007, Ext JS, LLC.
1671  *
1672  * Originally Released Under LGPL - original licence link has changed is not relivant.
1673  *
1674  * Fork - LGPL
1675  * <script type="text/javascript">
1676  */
1677
1678 Roo.lib.Dom = {
1679     getViewWidth : function(full) {
1680         return full ? this.getDocumentWidth() : this.getViewportWidth();
1681     },
1682
1683     getViewHeight : function(full) {
1684         return full ? this.getDocumentHeight() : this.getViewportHeight();
1685     },
1686
1687     getDocumentHeight: function() {
1688         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1689         return Math.max(scrollHeight, this.getViewportHeight());
1690     },
1691
1692     getDocumentWidth: function() {
1693         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1694         return Math.max(scrollWidth, this.getViewportWidth());
1695     },
1696
1697     getViewportHeight: function() {
1698         var height = self.innerHeight;
1699         var mode = document.compatMode;
1700
1701         if ((mode || Roo.isIE) && !Roo.isOpera) {
1702             height = (mode == "CSS1Compat") ?
1703                      document.documentElement.clientHeight :
1704                      document.body.clientHeight;
1705         }
1706
1707         return height;
1708     },
1709
1710     getViewportWidth: function() {
1711         var width = self.innerWidth;
1712         var mode = document.compatMode;
1713
1714         if (mode || Roo.isIE) {
1715             width = (mode == "CSS1Compat") ?
1716                     document.documentElement.clientWidth :
1717                     document.body.clientWidth;
1718         }
1719         return width;
1720     },
1721
1722     isAncestor : function(p, c) {
1723         p = Roo.getDom(p);
1724         c = Roo.getDom(c);
1725         if (!p || !c) {
1726             return false;
1727         }
1728
1729         if (p.contains && !Roo.isSafari) {
1730             return p.contains(c);
1731         } else if (p.compareDocumentPosition) {
1732             return !!(p.compareDocumentPosition(c) & 16);
1733         } else {
1734             var parent = c.parentNode;
1735             while (parent) {
1736                 if (parent == p) {
1737                     return true;
1738                 }
1739                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1740                     return false;
1741                 }
1742                 parent = parent.parentNode;
1743             }
1744             return false;
1745         }
1746     },
1747
1748     getRegion : function(el) {
1749         return Roo.lib.Region.getRegion(el);
1750     },
1751
1752     getY : function(el) {
1753         return this.getXY(el)[1];
1754     },
1755
1756     getX : function(el) {
1757         return this.getXY(el)[0];
1758     },
1759
1760     getXY : function(el) {
1761         var p, pe, b, scroll, bd = document.body;
1762         el = Roo.getDom(el);
1763         var fly = Roo.lib.AnimBase.fly;
1764         if (el.getBoundingClientRect) {
1765             b = el.getBoundingClientRect();
1766             scroll = fly(document).getScroll();
1767             return [b.left + scroll.left, b.top + scroll.top];
1768         }
1769         var x = 0, y = 0;
1770
1771         p = el;
1772
1773         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1774
1775         while (p) {
1776
1777             x += p.offsetLeft;
1778             y += p.offsetTop;
1779
1780             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1781                 hasAbsolute = true;
1782             }
1783
1784             if (Roo.isGecko) {
1785                 pe = fly(p);
1786
1787                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1788                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1789
1790
1791                 x += bl;
1792                 y += bt;
1793
1794
1795                 if (p != el && pe.getStyle('overflow') != 'visible') {
1796                     x += bl;
1797                     y += bt;
1798                 }
1799             }
1800             p = p.offsetParent;
1801         }
1802
1803         if (Roo.isSafari && hasAbsolute) {
1804             x -= bd.offsetLeft;
1805             y -= bd.offsetTop;
1806         }
1807
1808         if (Roo.isGecko && !hasAbsolute) {
1809             var dbd = fly(bd);
1810             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1811             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1812         }
1813
1814         p = el.parentNode;
1815         while (p && p != bd) {
1816             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1817                 x -= p.scrollLeft;
1818                 y -= p.scrollTop;
1819             }
1820             p = p.parentNode;
1821         }
1822         return [x, y];
1823     },
1824  
1825   
1826
1827
1828     setXY : function(el, xy) {
1829         el = Roo.fly(el, '_setXY');
1830         el.position();
1831         var pts = el.translatePoints(xy);
1832         if (xy[0] !== false) {
1833             el.dom.style.left = pts.left + "px";
1834         }
1835         if (xy[1] !== false) {
1836             el.dom.style.top = pts.top + "px";
1837         }
1838     },
1839
1840     setX : function(el, x) {
1841         this.setXY(el, [x, false]);
1842     },
1843
1844     setY : function(el, y) {
1845         this.setXY(el, [false, y]);
1846     }
1847 };
1848 /*
1849  * Portions of this file are based on pieces of Yahoo User Interface Library
1850  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1851  * YUI licensed under the BSD License:
1852  * http://developer.yahoo.net/yui/license.txt
1853  * <script type="text/javascript">
1854  *
1855  */
1856
1857 Roo.lib.Event = function() {
1858     var loadComplete = false;
1859     var listeners = [];
1860     var unloadListeners = [];
1861     var retryCount = 0;
1862     var onAvailStack = [];
1863     var counter = 0;
1864     var lastError = null;
1865
1866     return {
1867         POLL_RETRYS: 200,
1868         POLL_INTERVAL: 20,
1869         EL: 0,
1870         TYPE: 1,
1871         FN: 2,
1872         WFN: 3,
1873         OBJ: 3,
1874         ADJ_SCOPE: 4,
1875         _interval: null,
1876
1877         startInterval: function() {
1878             if (!this._interval) {
1879                 var self = this;
1880                 var callback = function() {
1881                     self._tryPreloadAttach();
1882                 };
1883                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1884
1885             }
1886         },
1887
1888         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1889             onAvailStack.push({ id:         p_id,
1890                 fn:         p_fn,
1891                 obj:        p_obj,
1892                 override:   p_override,
1893                 checkReady: false    });
1894
1895             retryCount = this.POLL_RETRYS;
1896             this.startInterval();
1897         },
1898
1899
1900         addListener: function(el, eventName, fn) {
1901             el = Roo.getDom(el);
1902             if (!el || !fn) {
1903                 return false;
1904             }
1905
1906             if ("unload" == eventName) {
1907                 unloadListeners[unloadListeners.length] =
1908                 [el, eventName, fn];
1909                 return true;
1910             }
1911
1912             var wrappedFn = function(e) {
1913                 return fn(Roo.lib.Event.getEvent(e));
1914             };
1915
1916             var li = [el, eventName, fn, wrappedFn];
1917
1918             var index = listeners.length;
1919             listeners[index] = li;
1920
1921             this.doAdd(el, eventName, wrappedFn, false);
1922             return true;
1923
1924         },
1925
1926
1927         removeListener: function(el, eventName, fn) {
1928             var i, len;
1929
1930             el = Roo.getDom(el);
1931
1932             if(!fn) {
1933                 return this.purgeElement(el, false, eventName);
1934             }
1935
1936
1937             if ("unload" == eventName) {
1938
1939                 for (i = 0,len = unloadListeners.length; i < len; i++) {
1940                     var li = unloadListeners[i];
1941                     if (li &&
1942                         li[0] == el &&
1943                         li[1] == eventName &&
1944                         li[2] == fn) {
1945                         unloadListeners.splice(i, 1);
1946                         return true;
1947                     }
1948                 }
1949
1950                 return false;
1951             }
1952
1953             var cacheItem = null;
1954
1955
1956             var index = arguments[3];
1957
1958             if ("undefined" == typeof index) {
1959                 index = this._getCacheIndex(el, eventName, fn);
1960             }
1961
1962             if (index >= 0) {
1963                 cacheItem = listeners[index];
1964             }
1965
1966             if (!el || !cacheItem) {
1967                 return false;
1968             }
1969
1970             this.doRemove(el, eventName, cacheItem[this.WFN], false);
1971
1972             delete listeners[index][this.WFN];
1973             delete listeners[index][this.FN];
1974             listeners.splice(index, 1);
1975
1976             return true;
1977
1978         },
1979
1980
1981         getTarget: function(ev, resolveTextNode) {
1982             ev = ev.browserEvent || ev;
1983             var t = ev.target || ev.srcElement;
1984             return this.resolveTextNode(t);
1985         },
1986
1987
1988         resolveTextNode: function(node) {
1989             if (Roo.isSafari && node && 3 == node.nodeType) {
1990                 return node.parentNode;
1991             } else {
1992                 return node;
1993             }
1994         },
1995
1996
1997         getPageX: function(ev) {
1998             ev = ev.browserEvent || ev;
1999             var x = ev.pageX;
2000             if (!x && 0 !== x) {
2001                 x = ev.clientX || 0;
2002
2003                 if (Roo.isIE) {
2004                     x += this.getScroll()[1];
2005                 }
2006             }
2007
2008             return x;
2009         },
2010
2011
2012         getPageY: function(ev) {
2013             ev = ev.browserEvent || ev;
2014             var y = ev.pageY;
2015             if (!y && 0 !== y) {
2016                 y = ev.clientY || 0;
2017
2018                 if (Roo.isIE) {
2019                     y += this.getScroll()[0];
2020                 }
2021             }
2022
2023
2024             return y;
2025         },
2026
2027
2028         getXY: function(ev) {
2029             ev = ev.browserEvent || ev;
2030             return [this.getPageX(ev), this.getPageY(ev)];
2031         },
2032
2033
2034         getRelatedTarget: function(ev) {
2035             ev = ev.browserEvent || ev;
2036             var t = ev.relatedTarget;
2037             if (!t) {
2038                 if (ev.type == "mouseout") {
2039                     t = ev.toElement;
2040                 } else if (ev.type == "mouseover") {
2041                     t = ev.fromElement;
2042                 }
2043             }
2044
2045             return this.resolveTextNode(t);
2046         },
2047
2048
2049         getTime: function(ev) {
2050             ev = ev.browserEvent || ev;
2051             if (!ev.time) {
2052                 var t = new Date().getTime();
2053                 try {
2054                     ev.time = t;
2055                 } catch(ex) {
2056                     this.lastError = ex;
2057                     return t;
2058                 }
2059             }
2060
2061             return ev.time;
2062         },
2063
2064
2065         stopEvent: function(ev) {
2066             this.stopPropagation(ev);
2067             this.preventDefault(ev);
2068         },
2069
2070
2071         stopPropagation: function(ev) {
2072             ev = ev.browserEvent || ev;
2073             if (ev.stopPropagation) {
2074                 ev.stopPropagation();
2075             } else {
2076                 ev.cancelBubble = true;
2077             }
2078         },
2079
2080
2081         preventDefault: function(ev) {
2082             ev = ev.browserEvent || ev;
2083             if(ev.preventDefault) {
2084                 ev.preventDefault();
2085             } else {
2086                 ev.returnValue = false;
2087             }
2088         },
2089
2090
2091         getEvent: function(e) {
2092             var ev = e || window.event;
2093             if (!ev) {
2094                 var c = this.getEvent.caller;
2095                 while (c) {
2096                     ev = c.arguments[0];
2097                     if (ev && Event == ev.constructor) {
2098                         break;
2099                     }
2100                     c = c.caller;
2101                 }
2102             }
2103             return ev;
2104         },
2105
2106
2107         getCharCode: function(ev) {
2108             ev = ev.browserEvent || ev;
2109             return ev.charCode || ev.keyCode || 0;
2110         },
2111
2112
2113         _getCacheIndex: function(el, eventName, fn) {
2114             for (var i = 0,len = listeners.length; i < len; ++i) {
2115                 var li = listeners[i];
2116                 if (li &&
2117                     li[this.FN] == fn &&
2118                     li[this.EL] == el &&
2119                     li[this.TYPE] == eventName) {
2120                     return i;
2121                 }
2122             }
2123
2124             return -1;
2125         },
2126
2127
2128         elCache: {},
2129
2130
2131         getEl: function(id) {
2132             return document.getElementById(id);
2133         },
2134
2135
2136         clearCache: function() {
2137         },
2138
2139
2140         _load: function(e) {
2141             loadComplete = true;
2142             var EU = Roo.lib.Event;
2143
2144
2145             if (Roo.isIE) {
2146                 EU.doRemove(window, "load", EU._load);
2147             }
2148         },
2149
2150
2151         _tryPreloadAttach: function() {
2152
2153             if (this.locked) {
2154                 return false;
2155             }
2156
2157             this.locked = true;
2158
2159
2160             var tryAgain = !loadComplete;
2161             if (!tryAgain) {
2162                 tryAgain = (retryCount > 0);
2163             }
2164
2165
2166             var notAvail = [];
2167             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2168                 var item = onAvailStack[i];
2169                 if (item) {
2170                     var el = this.getEl(item.id);
2171
2172                     if (el) {
2173                         if (!item.checkReady ||
2174                             loadComplete ||
2175                             el.nextSibling ||
2176                             (document && document.body)) {
2177
2178                             var scope = el;
2179                             if (item.override) {
2180                                 if (item.override === true) {
2181                                     scope = item.obj;
2182                                 } else {
2183                                     scope = item.override;
2184                                 }
2185                             }
2186                             item.fn.call(scope, item.obj);
2187                             onAvailStack[i] = null;
2188                         }
2189                     } else {
2190                         notAvail.push(item);
2191                     }
2192                 }
2193             }
2194
2195             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2196
2197             if (tryAgain) {
2198
2199                 this.startInterval();
2200             } else {
2201                 clearInterval(this._interval);
2202                 this._interval = null;
2203             }
2204
2205             this.locked = false;
2206
2207             return true;
2208
2209         },
2210
2211
2212         purgeElement: function(el, recurse, eventName) {
2213             var elListeners = this.getListeners(el, eventName);
2214             if (elListeners) {
2215                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2216                     var l = elListeners[i];
2217                     this.removeListener(el, l.type, l.fn);
2218                 }
2219             }
2220
2221             if (recurse && el && el.childNodes) {
2222                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2223                     this.purgeElement(el.childNodes[i], recurse, eventName);
2224                 }
2225             }
2226         },
2227
2228
2229         getListeners: function(el, eventName) {
2230             var results = [], searchLists;
2231             if (!eventName) {
2232                 searchLists = [listeners, unloadListeners];
2233             } else if (eventName == "unload") {
2234                 searchLists = [unloadListeners];
2235             } else {
2236                 searchLists = [listeners];
2237             }
2238
2239             for (var j = 0; j < searchLists.length; ++j) {
2240                 var searchList = searchLists[j];
2241                 if (searchList && searchList.length > 0) {
2242                     for (var i = 0,len = searchList.length; i < len; ++i) {
2243                         var l = searchList[i];
2244                         if (l && l[this.EL] === el &&
2245                             (!eventName || eventName === l[this.TYPE])) {
2246                             results.push({
2247                                 type:   l[this.TYPE],
2248                                 fn:     l[this.FN],
2249                                 obj:    l[this.OBJ],
2250                                 adjust: l[this.ADJ_SCOPE],
2251                                 index:  i
2252                             });
2253                         }
2254                     }
2255                 }
2256             }
2257
2258             return (results.length) ? results : null;
2259         },
2260
2261
2262         _unload: function(e) {
2263
2264             var EU = Roo.lib.Event, i, j, l, len, index;
2265
2266             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2267                 l = unloadListeners[i];
2268                 if (l) {
2269                     var scope = window;
2270                     if (l[EU.ADJ_SCOPE]) {
2271                         if (l[EU.ADJ_SCOPE] === true) {
2272                             scope = l[EU.OBJ];
2273                         } else {
2274                             scope = l[EU.ADJ_SCOPE];
2275                         }
2276                     }
2277                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2278                     unloadListeners[i] = null;
2279                     l = null;
2280                     scope = null;
2281                 }
2282             }
2283
2284             unloadListeners = null;
2285
2286             if (listeners && listeners.length > 0) {
2287                 j = listeners.length;
2288                 while (j) {
2289                     index = j - 1;
2290                     l = listeners[index];
2291                     if (l) {
2292                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2293                                 l[EU.FN], index);
2294                     }
2295                     j = j - 1;
2296                 }
2297                 l = null;
2298
2299                 EU.clearCache();
2300             }
2301
2302             EU.doRemove(window, "unload", EU._unload);
2303
2304         },
2305
2306
2307         getScroll: function() {
2308             var dd = document.documentElement, db = document.body;
2309             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2310                 return [dd.scrollTop, dd.scrollLeft];
2311             } else if (db) {
2312                 return [db.scrollTop, db.scrollLeft];
2313             } else {
2314                 return [0, 0];
2315             }
2316         },
2317
2318
2319         doAdd: function () {
2320             if (window.addEventListener) {
2321                 return function(el, eventName, fn, capture) {
2322                     el.addEventListener(eventName, fn, (capture));
2323                 };
2324             } else if (window.attachEvent) {
2325                 return function(el, eventName, fn, capture) {
2326                     el.attachEvent("on" + eventName, fn);
2327                 };
2328             } else {
2329                 return function() {
2330                 };
2331             }
2332         }(),
2333
2334
2335         doRemove: function() {
2336             if (window.removeEventListener) {
2337                 return function (el, eventName, fn, capture) {
2338                     el.removeEventListener(eventName, fn, (capture));
2339                 };
2340             } else if (window.detachEvent) {
2341                 return function (el, eventName, fn) {
2342                     el.detachEvent("on" + eventName, fn);
2343                 };
2344             } else {
2345                 return function() {
2346                 };
2347             }
2348         }()
2349     };
2350     
2351 }();
2352 (function() {     
2353    
2354     var E = Roo.lib.Event;
2355     E.on = E.addListener;
2356     E.un = E.removeListener;
2357
2358     if (document && document.body) {
2359         E._load();
2360     } else {
2361         E.doAdd(window, "load", E._load);
2362     }
2363     E.doAdd(window, "unload", E._unload);
2364     E._tryPreloadAttach();
2365 })();
2366
2367 /*
2368  * Portions of this file are based on pieces of Yahoo User Interface Library
2369  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2370  * YUI licensed under the BSD License:
2371  * http://developer.yahoo.net/yui/license.txt
2372  * <script type="text/javascript">
2373  *
2374  */
2375
2376 (function() {
2377     
2378     Roo.lib.Ajax = {
2379         request : function(method, uri, cb, data, options) {
2380             if(options){
2381                 var hs = options.headers;
2382                 if(hs){
2383                     for(var h in hs){
2384                         if(hs.hasOwnProperty(h)){
2385                             this.initHeader(h, hs[h], false);
2386                         }
2387                     }
2388                 }
2389                 if(options.xmlData){
2390                     this.initHeader('Content-Type', 'text/xml', false);
2391                     method = 'POST';
2392                     data = options.xmlData;
2393                 }
2394             }
2395
2396             return this.asyncRequest(method, uri, cb, data);
2397         },
2398
2399         serializeForm : function(form) {
2400             if(typeof form == 'string') {
2401                 form = (document.getElementById(form) || document.forms[form]);
2402             }
2403
2404             var el, name, val, disabled, data = '', hasSubmit = false;
2405             for (var i = 0; i < form.elements.length; i++) {
2406                 el = form.elements[i];
2407                 disabled = form.elements[i].disabled;
2408                 name = form.elements[i].name;
2409                 val = form.elements[i].value;
2410
2411                 if (!disabled && name){
2412                     switch (el.type)
2413                             {
2414                         case 'select-one':
2415                         case 'select-multiple':
2416                             for (var j = 0; j < el.options.length; j++) {
2417                                 if (el.options[j].selected) {
2418                                     if (Roo.isIE) {
2419                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2420                                     }
2421                                     else {
2422                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2423                                     }
2424                                 }
2425                             }
2426                             break;
2427                         case 'radio':
2428                         case 'checkbox':
2429                             if (el.checked) {
2430                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2431                             }
2432                             break;
2433                         case 'file':
2434
2435                         case undefined:
2436
2437                         case 'reset':
2438
2439                         case 'button':
2440
2441                             break;
2442                         case 'submit':
2443                             if(hasSubmit == false) {
2444                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2445                                 hasSubmit = true;
2446                             }
2447                             break;
2448                         default:
2449                             data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2450                             break;
2451                     }
2452                 }
2453             }
2454             data = data.substr(0, data.length - 1);
2455             return data;
2456         },
2457
2458         headers:{},
2459
2460         hasHeaders:false,
2461
2462         useDefaultHeader:true,
2463
2464         defaultPostHeader:'application/x-www-form-urlencoded',
2465
2466         useDefaultXhrHeader:true,
2467
2468         defaultXhrHeader:'XMLHttpRequest',
2469
2470         hasDefaultHeaders:true,
2471
2472         defaultHeaders:{},
2473
2474         poll:{},
2475
2476         timeout:{},
2477
2478         pollInterval:50,
2479
2480         transactionId:0,
2481
2482         setProgId:function(id)
2483         {
2484             this.activeX.unshift(id);
2485         },
2486
2487         setDefaultPostHeader:function(b)
2488         {
2489             this.useDefaultHeader = b;
2490         },
2491
2492         setDefaultXhrHeader:function(b)
2493         {
2494             this.useDefaultXhrHeader = b;
2495         },
2496
2497         setPollingInterval:function(i)
2498         {
2499             if (typeof i == 'number' && isFinite(i)) {
2500                 this.pollInterval = i;
2501             }
2502         },
2503
2504         createXhrObject:function(transactionId)
2505         {
2506             var obj,http;
2507             try
2508             {
2509
2510                 http = new XMLHttpRequest();
2511
2512                 obj = { conn:http, tId:transactionId };
2513             }
2514             catch(e)
2515             {
2516                 for (var i = 0; i < this.activeX.length; ++i) {
2517                     try
2518                     {
2519
2520                         http = new ActiveXObject(this.activeX[i]);
2521
2522                         obj = { conn:http, tId:transactionId };
2523                         break;
2524                     }
2525                     catch(e) {
2526                     }
2527                 }
2528             }
2529             finally
2530             {
2531                 return obj;
2532             }
2533         },
2534
2535         getConnectionObject:function()
2536         {
2537             var o;
2538             var tId = this.transactionId;
2539
2540             try
2541             {
2542                 o = this.createXhrObject(tId);
2543                 if (o) {
2544                     this.transactionId++;
2545                 }
2546             }
2547             catch(e) {
2548             }
2549             finally
2550             {
2551                 return o;
2552             }
2553         },
2554
2555         asyncRequest:function(method, uri, callback, postData)
2556         {
2557             var o = this.getConnectionObject();
2558
2559             if (!o) {
2560                 return null;
2561             }
2562             else {
2563                 o.conn.open(method, uri, true);
2564
2565                 if (this.useDefaultXhrHeader) {
2566                     if (!this.defaultHeaders['X-Requested-With']) {
2567                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2568                     }
2569                 }
2570
2571                 if(postData && this.useDefaultHeader){
2572                     this.initHeader('Content-Type', this.defaultPostHeader);
2573                 }
2574
2575                  if (this.hasDefaultHeaders || this.hasHeaders) {
2576                     this.setHeader(o);
2577                 }
2578
2579                 this.handleReadyState(o, callback);
2580                 o.conn.send(postData || null);
2581
2582                 return o;
2583             }
2584         },
2585
2586         handleReadyState:function(o, callback)
2587         {
2588             var oConn = this;
2589
2590             if (callback && callback.timeout) {
2591                 this.timeout[o.tId] = window.setTimeout(function() {
2592                     oConn.abort(o, callback, true);
2593                 }, callback.timeout);
2594             }
2595
2596             this.poll[o.tId] = window.setInterval(
2597                     function() {
2598                         if (o.conn && o.conn.readyState == 4) {
2599                             window.clearInterval(oConn.poll[o.tId]);
2600                             delete oConn.poll[o.tId];
2601
2602                             if(callback && callback.timeout) {
2603                                 window.clearTimeout(oConn.timeout[o.tId]);
2604                                 delete oConn.timeout[o.tId];
2605                             }
2606
2607                             oConn.handleTransactionResponse(o, callback);
2608                         }
2609                     }
2610                     , this.pollInterval);
2611         },
2612
2613         handleTransactionResponse:function(o, callback, isAbort)
2614         {
2615
2616             if (!callback) {
2617                 this.releaseObject(o);
2618                 return;
2619             }
2620
2621             var httpStatus, responseObject;
2622
2623             try
2624             {
2625                 if (o.conn.status !== undefined && o.conn.status != 0) {
2626                     httpStatus = o.conn.status;
2627                 }
2628                 else {
2629                     httpStatus = 13030;
2630                 }
2631             }
2632             catch(e) {
2633
2634
2635                 httpStatus = 13030;
2636             }
2637
2638             if (httpStatus >= 200 && httpStatus < 300) {
2639                 responseObject = this.createResponseObject(o, callback.argument);
2640                 if (callback.success) {
2641                     if (!callback.scope) {
2642                         callback.success(responseObject);
2643                     }
2644                     else {
2645
2646
2647                         callback.success.apply(callback.scope, [responseObject]);
2648                     }
2649                 }
2650             }
2651             else {
2652                 switch (httpStatus) {
2653
2654                     case 12002:
2655                     case 12029:
2656                     case 12030:
2657                     case 12031:
2658                     case 12152:
2659                     case 13030:
2660                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2661                         if (callback.failure) {
2662                             if (!callback.scope) {
2663                                 callback.failure(responseObject);
2664                             }
2665                             else {
2666                                 callback.failure.apply(callback.scope, [responseObject]);
2667                             }
2668                         }
2669                         break;
2670                     default:
2671                         responseObject = this.createResponseObject(o, callback.argument);
2672                         if (callback.failure) {
2673                             if (!callback.scope) {
2674                                 callback.failure(responseObject);
2675                             }
2676                             else {
2677                                 callback.failure.apply(callback.scope, [responseObject]);
2678                             }
2679                         }
2680                 }
2681             }
2682
2683             this.releaseObject(o);
2684             responseObject = null;
2685         },
2686
2687         createResponseObject:function(o, callbackArg)
2688         {
2689             var obj = {};
2690             var headerObj = {};
2691
2692             try
2693             {
2694                 var headerStr = o.conn.getAllResponseHeaders();
2695                 var header = headerStr.split('\n');
2696                 for (var i = 0; i < header.length; i++) {
2697                     var delimitPos = header[i].indexOf(':');
2698                     if (delimitPos != -1) {
2699                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2700                     }
2701                 }
2702             }
2703             catch(e) {
2704             }
2705
2706             obj.tId = o.tId;
2707             obj.status = o.conn.status;
2708             obj.statusText = o.conn.statusText;
2709             obj.getResponseHeader = headerObj;
2710             obj.getAllResponseHeaders = headerStr;
2711             obj.responseText = o.conn.responseText;
2712             obj.responseXML = o.conn.responseXML;
2713
2714             if (typeof callbackArg !== undefined) {
2715                 obj.argument = callbackArg;
2716             }
2717
2718             return obj;
2719         },
2720
2721         createExceptionObject:function(tId, callbackArg, isAbort)
2722         {
2723             var COMM_CODE = 0;
2724             var COMM_ERROR = 'communication failure';
2725             var ABORT_CODE = -1;
2726             var ABORT_ERROR = 'transaction aborted';
2727
2728             var obj = {};
2729
2730             obj.tId = tId;
2731             if (isAbort) {
2732                 obj.status = ABORT_CODE;
2733                 obj.statusText = ABORT_ERROR;
2734             }
2735             else {
2736                 obj.status = COMM_CODE;
2737                 obj.statusText = COMM_ERROR;
2738             }
2739
2740             if (callbackArg) {
2741                 obj.argument = callbackArg;
2742             }
2743
2744             return obj;
2745         },
2746
2747         initHeader:function(label, value, isDefault)
2748         {
2749             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2750
2751             if (headerObj[label] === undefined) {
2752                 headerObj[label] = value;
2753             }
2754             else {
2755
2756
2757                 headerObj[label] = value + "," + headerObj[label];
2758             }
2759
2760             if (isDefault) {
2761                 this.hasDefaultHeaders = true;
2762             }
2763             else {
2764                 this.hasHeaders = true;
2765             }
2766         },
2767
2768
2769         setHeader:function(o)
2770         {
2771             if (this.hasDefaultHeaders) {
2772                 for (var prop in this.defaultHeaders) {
2773                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2774                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2775                     }
2776                 }
2777             }
2778
2779             if (this.hasHeaders) {
2780                 for (var prop in this.headers) {
2781                     if (this.headers.hasOwnProperty(prop)) {
2782                         o.conn.setRequestHeader(prop, this.headers[prop]);
2783                     }
2784                 }
2785                 this.headers = {};
2786                 this.hasHeaders = false;
2787             }
2788         },
2789
2790         resetDefaultHeaders:function() {
2791             delete this.defaultHeaders;
2792             this.defaultHeaders = {};
2793             this.hasDefaultHeaders = false;
2794         },
2795
2796         abort:function(o, callback, isTimeout)
2797         {
2798             if(this.isCallInProgress(o)) {
2799                 o.conn.abort();
2800                 window.clearInterval(this.poll[o.tId]);
2801                 delete this.poll[o.tId];
2802                 if (isTimeout) {
2803                     delete this.timeout[o.tId];
2804                 }
2805
2806                 this.handleTransactionResponse(o, callback, true);
2807
2808                 return true;
2809             }
2810             else {
2811                 return false;
2812             }
2813         },
2814
2815
2816         isCallInProgress:function(o)
2817         {
2818             if (o && o.conn) {
2819                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2820             }
2821             else {
2822
2823                 return false;
2824             }
2825         },
2826
2827
2828         releaseObject:function(o)
2829         {
2830
2831             o.conn = null;
2832
2833             o = null;
2834         },
2835
2836         activeX:[
2837         'MSXML2.XMLHTTP.3.0',
2838         'MSXML2.XMLHTTP',
2839         'Microsoft.XMLHTTP'
2840         ]
2841
2842
2843     };
2844 })();/*
2845  * Portions of this file are based on pieces of Yahoo User Interface Library
2846  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2847  * YUI licensed under the BSD License:
2848  * http://developer.yahoo.net/yui/license.txt
2849  * <script type="text/javascript">
2850  *
2851  */
2852
2853 Roo.lib.Region = function(t, r, b, l) {
2854     this.top = t;
2855     this[1] = t;
2856     this.right = r;
2857     this.bottom = b;
2858     this.left = l;
2859     this[0] = l;
2860 };
2861
2862
2863 Roo.lib.Region.prototype = {
2864     contains : function(region) {
2865         return ( region.left >= this.left &&
2866                  region.right <= this.right &&
2867                  region.top >= this.top &&
2868                  region.bottom <= this.bottom    );
2869
2870     },
2871
2872     getArea : function() {
2873         return ( (this.bottom - this.top) * (this.right - this.left) );
2874     },
2875
2876     intersect : function(region) {
2877         var t = Math.max(this.top, region.top);
2878         var r = Math.min(this.right, region.right);
2879         var b = Math.min(this.bottom, region.bottom);
2880         var l = Math.max(this.left, region.left);
2881
2882         if (b >= t && r >= l) {
2883             return new Roo.lib.Region(t, r, b, l);
2884         } else {
2885             return null;
2886         }
2887     },
2888     union : function(region) {
2889         var t = Math.min(this.top, region.top);
2890         var r = Math.max(this.right, region.right);
2891         var b = Math.max(this.bottom, region.bottom);
2892         var l = Math.min(this.left, region.left);
2893
2894         return new Roo.lib.Region(t, r, b, l);
2895     },
2896
2897     adjust : function(t, l, b, r) {
2898         this.top += t;
2899         this.left += l;
2900         this.right += r;
2901         this.bottom += b;
2902         return this;
2903     }
2904 };
2905
2906 Roo.lib.Region.getRegion = function(el) {
2907     var p = Roo.lib.Dom.getXY(el);
2908
2909     var t = p[1];
2910     var r = p[0] + el.offsetWidth;
2911     var b = p[1] + el.offsetHeight;
2912     var l = p[0];
2913
2914     return new Roo.lib.Region(t, r, b, l);
2915 };
2916 /*
2917  * Portions of this file are based on pieces of Yahoo User Interface Library
2918  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2919  * YUI licensed under the BSD License:
2920  * http://developer.yahoo.net/yui/license.txt
2921  * <script type="text/javascript">
2922  *
2923  */
2924 //@@dep Roo.lib.Region
2925
2926
2927 Roo.lib.Point = function(x, y) {
2928     if (x instanceof Array) {
2929         y = x[1];
2930         x = x[0];
2931     }
2932     this.x = this.right = this.left = this[0] = x;
2933     this.y = this.top = this.bottom = this[1] = y;
2934 };
2935
2936 Roo.lib.Point.prototype = new Roo.lib.Region();
2937 /*
2938  * Portions of this file are based on pieces of Yahoo User Interface Library
2939  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2940  * YUI licensed under the BSD License:
2941  * http://developer.yahoo.net/yui/license.txt
2942  * <script type="text/javascript">
2943  *
2944  */
2945  
2946 (function() {   
2947
2948     Roo.lib.Anim = {
2949         scroll : function(el, args, duration, easing, cb, scope) {
2950             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2951         },
2952
2953         motion : function(el, args, duration, easing, cb, scope) {
2954             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2955         },
2956
2957         color : function(el, args, duration, easing, cb, scope) {
2958             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2959         },
2960
2961         run : function(el, args, duration, easing, cb, scope, type) {
2962             type = type || Roo.lib.AnimBase;
2963             if (typeof easing == "string") {
2964                 easing = Roo.lib.Easing[easing];
2965             }
2966             var anim = new type(el, args, duration, easing);
2967             anim.animateX(function() {
2968                 Roo.callback(cb, scope);
2969             });
2970             return anim;
2971         }
2972     };
2973 })();/*
2974  * Portions of this file are based on pieces of Yahoo User Interface Library
2975  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2976  * YUI licensed under the BSD License:
2977  * http://developer.yahoo.net/yui/license.txt
2978  * <script type="text/javascript">
2979  *
2980  */
2981
2982 (function() {    
2983     var libFlyweight;
2984     
2985     function fly(el) {
2986         if (!libFlyweight) {
2987             libFlyweight = new Roo.Element.Flyweight();
2988         }
2989         libFlyweight.dom = el;
2990         return libFlyweight;
2991     }
2992
2993     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2994     
2995    
2996     
2997     Roo.lib.AnimBase = function(el, attributes, duration, method) {
2998         if (el) {
2999             this.init(el, attributes, duration, method);
3000         }
3001     };
3002
3003     Roo.lib.AnimBase.fly = fly;
3004     
3005     
3006     
3007     Roo.lib.AnimBase.prototype = {
3008
3009         toString: function() {
3010             var el = this.getEl();
3011             var id = el.id || el.tagName;
3012             return ("Anim " + id);
3013         },
3014
3015         patterns: {
3016             noNegatives:        /width|height|opacity|padding/i,
3017             offsetAttribute:  /^((width|height)|(top|left))$/,
3018             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3019             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3020         },
3021
3022
3023         doMethod: function(attr, start, end) {
3024             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3025         },
3026
3027
3028         setAttribute: function(attr, val, unit) {
3029             if (this.patterns.noNegatives.test(attr)) {
3030                 val = (val > 0) ? val : 0;
3031             }
3032
3033             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3034         },
3035
3036
3037         getAttribute: function(attr) {
3038             var el = this.getEl();
3039             var val = fly(el).getStyle(attr);
3040
3041             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3042                 return parseFloat(val);
3043             }
3044
3045             var a = this.patterns.offsetAttribute.exec(attr) || [];
3046             var pos = !!( a[3] );
3047             var box = !!( a[2] );
3048
3049
3050             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3051                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3052             } else {
3053                 val = 0;
3054             }
3055
3056             return val;
3057         },
3058
3059
3060         getDefaultUnit: function(attr) {
3061             if (this.patterns.defaultUnit.test(attr)) {
3062                 return 'px';
3063             }
3064
3065             return '';
3066         },
3067
3068         animateX : function(callback, scope) {
3069             var f = function() {
3070                 this.onComplete.removeListener(f);
3071                 if (typeof callback == "function") {
3072                     callback.call(scope || this, this);
3073                 }
3074             };
3075             this.onComplete.addListener(f, this);
3076             this.animate();
3077         },
3078
3079
3080         setRuntimeAttribute: function(attr) {
3081             var start;
3082             var end;
3083             var attributes = this.attributes;
3084
3085             this.runtimeAttributes[attr] = {};
3086
3087             var isset = function(prop) {
3088                 return (typeof prop !== 'undefined');
3089             };
3090
3091             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3092                 return false;
3093             }
3094
3095             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3096
3097
3098             if (isset(attributes[attr]['to'])) {
3099                 end = attributes[attr]['to'];
3100             } else if (isset(attributes[attr]['by'])) {
3101                 if (start.constructor == Array) {
3102                     end = [];
3103                     for (var i = 0, len = start.length; i < len; ++i) {
3104                         end[i] = start[i] + attributes[attr]['by'][i];
3105                     }
3106                 } else {
3107                     end = start + attributes[attr]['by'];
3108                 }
3109             }
3110
3111             this.runtimeAttributes[attr].start = start;
3112             this.runtimeAttributes[attr].end = end;
3113
3114
3115             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3116         },
3117
3118
3119         init: function(el, attributes, duration, method) {
3120
3121             var isAnimated = false;
3122
3123
3124             var startTime = null;
3125
3126
3127             var actualFrames = 0;
3128
3129
3130             el = Roo.getDom(el);
3131
3132
3133             this.attributes = attributes || {};
3134
3135
3136             this.duration = duration || 1;
3137
3138
3139             this.method = method || Roo.lib.Easing.easeNone;
3140
3141
3142             this.useSeconds = true;
3143
3144
3145             this.currentFrame = 0;
3146
3147
3148             this.totalFrames = Roo.lib.AnimMgr.fps;
3149
3150
3151             this.getEl = function() {
3152                 return el;
3153             };
3154
3155
3156             this.isAnimated = function() {
3157                 return isAnimated;
3158             };
3159
3160
3161             this.getStartTime = function() {
3162                 return startTime;
3163             };
3164
3165             this.runtimeAttributes = {};
3166
3167
3168             this.animate = function() {
3169                 if (this.isAnimated()) {
3170                     return false;
3171                 }
3172
3173                 this.currentFrame = 0;
3174
3175                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3176
3177                 Roo.lib.AnimMgr.registerElement(this);
3178             };
3179
3180
3181             this.stop = function(finish) {
3182                 if (finish) {
3183                     this.currentFrame = this.totalFrames;
3184                     this._onTween.fire();
3185                 }
3186                 Roo.lib.AnimMgr.stop(this);
3187             };
3188
3189             var onStart = function() {
3190                 this.onStart.fire();
3191
3192                 this.runtimeAttributes = {};
3193                 for (var attr in this.attributes) {
3194                     this.setRuntimeAttribute(attr);
3195                 }
3196
3197                 isAnimated = true;
3198                 actualFrames = 0;
3199                 startTime = new Date();
3200             };
3201
3202
3203             var onTween = function() {
3204                 var data = {
3205                     duration: new Date() - this.getStartTime(),
3206                     currentFrame: this.currentFrame
3207                 };
3208
3209                 data.toString = function() {
3210                     return (
3211                             'duration: ' + data.duration +
3212                             ', currentFrame: ' + data.currentFrame
3213                             );
3214                 };
3215
3216                 this.onTween.fire(data);
3217
3218                 var runtimeAttributes = this.runtimeAttributes;
3219
3220                 for (var attr in runtimeAttributes) {
3221                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3222                 }
3223
3224                 actualFrames += 1;
3225             };
3226
3227             var onComplete = function() {
3228                 var actual_duration = (new Date() - startTime) / 1000 ;
3229
3230                 var data = {
3231                     duration: actual_duration,
3232                     frames: actualFrames,
3233                     fps: actualFrames / actual_duration
3234                 };
3235
3236                 data.toString = function() {
3237                     return (
3238                             'duration: ' + data.duration +
3239                             ', frames: ' + data.frames +
3240                             ', fps: ' + data.fps
3241                             );
3242                 };
3243
3244                 isAnimated = false;
3245                 actualFrames = 0;
3246                 this.onComplete.fire(data);
3247             };
3248
3249
3250             this._onStart = new Roo.util.Event(this);
3251             this.onStart = new Roo.util.Event(this);
3252             this.onTween = new Roo.util.Event(this);
3253             this._onTween = new Roo.util.Event(this);
3254             this.onComplete = new Roo.util.Event(this);
3255             this._onComplete = new Roo.util.Event(this);
3256             this._onStart.addListener(onStart);
3257             this._onTween.addListener(onTween);
3258             this._onComplete.addListener(onComplete);
3259         }
3260     };
3261 })();
3262 /*
3263  * Portions of this file are based on pieces of Yahoo User Interface Library
3264  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3265  * YUI licensed under the BSD License:
3266  * http://developer.yahoo.net/yui/license.txt
3267  * <script type="text/javascript">
3268  *
3269  */
3270
3271 Roo.lib.AnimMgr = new function() {
3272
3273         var thread = null;
3274
3275
3276         var queue = [];
3277
3278
3279         var tweenCount = 0;
3280
3281
3282         this.fps = 1000;
3283
3284
3285         this.delay = 1;
3286
3287
3288         this.registerElement = function(tween) {
3289             queue[queue.length] = tween;
3290             tweenCount += 1;
3291             tween._onStart.fire();
3292             this.start();
3293         };
3294
3295
3296         this.unRegister = function(tween, index) {
3297             tween._onComplete.fire();
3298             index = index || getIndex(tween);
3299             if (index != -1) {
3300                 queue.splice(index, 1);
3301             }
3302
3303             tweenCount -= 1;
3304             if (tweenCount <= 0) {
3305                 this.stop();
3306             }
3307         };
3308
3309
3310         this.start = function() {
3311             if (thread === null) {
3312                 thread = setInterval(this.run, this.delay);
3313             }
3314         };
3315
3316
3317         this.stop = function(tween) {
3318             if (!tween) {
3319                 clearInterval(thread);
3320
3321                 for (var i = 0, len = queue.length; i < len; ++i) {
3322                     if (queue[0].isAnimated()) {
3323                         this.unRegister(queue[0], 0);
3324                     }
3325                 }
3326
3327                 queue = [];
3328                 thread = null;
3329                 tweenCount = 0;
3330             }
3331             else {
3332                 this.unRegister(tween);
3333             }
3334         };
3335
3336
3337         this.run = function() {
3338             for (var i = 0, len = queue.length; i < len; ++i) {
3339                 var tween = queue[i];
3340                 if (!tween || !tween.isAnimated()) {
3341                     continue;
3342                 }
3343
3344                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3345                 {
3346                     tween.currentFrame += 1;
3347
3348                     if (tween.useSeconds) {
3349                         correctFrame(tween);
3350                     }
3351                     tween._onTween.fire();
3352                 }
3353                 else {
3354                     Roo.lib.AnimMgr.stop(tween, i);
3355                 }
3356             }
3357         };
3358
3359         var getIndex = function(anim) {
3360             for (var i = 0, len = queue.length; i < len; ++i) {
3361                 if (queue[i] == anim) {
3362                     return i;
3363                 }
3364             }
3365             return -1;
3366         };
3367
3368
3369         var correctFrame = function(tween) {
3370             var frames = tween.totalFrames;
3371             var frame = tween.currentFrame;
3372             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3373             var elapsed = (new Date() - tween.getStartTime());
3374             var tweak = 0;
3375
3376             if (elapsed < tween.duration * 1000) {
3377                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3378             } else {
3379                 tweak = frames - (frame + 1);
3380             }
3381             if (tweak > 0 && isFinite(tweak)) {
3382                 if (tween.currentFrame + tweak >= frames) {
3383                     tweak = frames - (frame + 1);
3384                 }
3385
3386                 tween.currentFrame += tweak;
3387             }
3388         };
3389     };/*
3390  * Portions of this file are based on pieces of Yahoo User Interface Library
3391  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3392  * YUI licensed under the BSD License:
3393  * http://developer.yahoo.net/yui/license.txt
3394  * <script type="text/javascript">
3395  *
3396  */
3397 Roo.lib.Bezier = new function() {
3398
3399         this.getPosition = function(points, t) {
3400             var n = points.length;
3401             var tmp = [];
3402
3403             for (var i = 0; i < n; ++i) {
3404                 tmp[i] = [points[i][0], points[i][1]];
3405             }
3406
3407             for (var j = 1; j < n; ++j) {
3408                 for (i = 0; i < n - j; ++i) {
3409                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3410                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3411                 }
3412             }
3413
3414             return [ tmp[0][0], tmp[0][1] ];
3415
3416         };
3417     };/*
3418  * Portions of this file are based on pieces of Yahoo User Interface Library
3419  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3420  * YUI licensed under the BSD License:
3421  * http://developer.yahoo.net/yui/license.txt
3422  * <script type="text/javascript">
3423  *
3424  */
3425 (function() {
3426
3427     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3428         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3429     };
3430
3431     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3432
3433     var fly = Roo.lib.AnimBase.fly;
3434     var Y = Roo.lib;
3435     var superclass = Y.ColorAnim.superclass;
3436     var proto = Y.ColorAnim.prototype;
3437
3438     proto.toString = function() {
3439         var el = this.getEl();
3440         var id = el.id || el.tagName;
3441         return ("ColorAnim " + id);
3442     };
3443
3444     proto.patterns.color = /color$/i;
3445     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3446     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3447     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3448     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3449
3450
3451     proto.parseColor = function(s) {
3452         if (s.length == 3) {
3453             return s;
3454         }
3455
3456         var c = this.patterns.hex.exec(s);
3457         if (c && c.length == 4) {
3458             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3459         }
3460
3461         c = this.patterns.rgb.exec(s);
3462         if (c && c.length == 4) {
3463             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3464         }
3465
3466         c = this.patterns.hex3.exec(s);
3467         if (c && c.length == 4) {
3468             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3469         }
3470
3471         return null;
3472     };
3473     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3474     proto.getAttribute = function(attr) {
3475         var el = this.getEl();
3476         if (this.patterns.color.test(attr)) {
3477             var val = fly(el).getStyle(attr);
3478
3479             if (this.patterns.transparent.test(val)) {
3480                 var parent = el.parentNode;
3481                 val = fly(parent).getStyle(attr);
3482
3483                 while (parent && this.patterns.transparent.test(val)) {
3484                     parent = parent.parentNode;
3485                     val = fly(parent).getStyle(attr);
3486                     if (parent.tagName.toUpperCase() == 'HTML') {
3487                         val = '#fff';
3488                     }
3489                 }
3490             }
3491         } else {
3492             val = superclass.getAttribute.call(this, attr);
3493         }
3494
3495         return val;
3496     };
3497     proto.getAttribute = function(attr) {
3498         var el = this.getEl();
3499         if (this.patterns.color.test(attr)) {
3500             var val = fly(el).getStyle(attr);
3501
3502             if (this.patterns.transparent.test(val)) {
3503                 var parent = el.parentNode;
3504                 val = fly(parent).getStyle(attr);
3505
3506                 while (parent && this.patterns.transparent.test(val)) {
3507                     parent = parent.parentNode;
3508                     val = fly(parent).getStyle(attr);
3509                     if (parent.tagName.toUpperCase() == 'HTML') {
3510                         val = '#fff';
3511                     }
3512                 }
3513             }
3514         } else {
3515             val = superclass.getAttribute.call(this, attr);
3516         }
3517
3518         return val;
3519     };
3520
3521     proto.doMethod = function(attr, start, end) {
3522         var val;
3523
3524         if (this.patterns.color.test(attr)) {
3525             val = [];
3526             for (var i = 0, len = start.length; i < len; ++i) {
3527                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3528             }
3529
3530             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3531         }
3532         else {
3533             val = superclass.doMethod.call(this, attr, start, end);
3534         }
3535
3536         return val;
3537     };
3538
3539     proto.setRuntimeAttribute = function(attr) {
3540         superclass.setRuntimeAttribute.call(this, attr);
3541
3542         if (this.patterns.color.test(attr)) {
3543             var attributes = this.attributes;
3544             var start = this.parseColor(this.runtimeAttributes[attr].start);
3545             var end = this.parseColor(this.runtimeAttributes[attr].end);
3546
3547             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3548                 end = this.parseColor(attributes[attr].by);
3549
3550                 for (var i = 0, len = start.length; i < len; ++i) {
3551                     end[i] = start[i] + end[i];
3552                 }
3553             }
3554
3555             this.runtimeAttributes[attr].start = start;
3556             this.runtimeAttributes[attr].end = end;
3557         }
3558     };
3559 })();
3560
3561 /*
3562  * Portions of this file are based on pieces of Yahoo User Interface Library
3563  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3564  * YUI licensed under the BSD License:
3565  * http://developer.yahoo.net/yui/license.txt
3566  * <script type="text/javascript">
3567  *
3568  */
3569 Roo.lib.Easing = {
3570
3571
3572     easeNone: function (t, b, c, d) {
3573         return c * t / d + b;
3574     },
3575
3576
3577     easeIn: function (t, b, c, d) {
3578         return c * (t /= d) * t + b;
3579     },
3580
3581
3582     easeOut: function (t, b, c, d) {
3583         return -c * (t /= d) * (t - 2) + b;
3584     },
3585
3586
3587     easeBoth: function (t, b, c, d) {
3588         if ((t /= d / 2) < 1) {
3589             return c / 2 * t * t + b;
3590         }
3591
3592         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3593     },
3594
3595
3596     easeInStrong: function (t, b, c, d) {
3597         return c * (t /= d) * t * t * t + b;
3598     },
3599
3600
3601     easeOutStrong: function (t, b, c, d) {
3602         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3603     },
3604
3605
3606     easeBothStrong: function (t, b, c, d) {
3607         if ((t /= d / 2) < 1) {
3608             return c / 2 * t * t * t * t + b;
3609         }
3610
3611         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3612     },
3613
3614
3615
3616     elasticIn: function (t, b, c, d, a, p) {
3617         if (t == 0) {
3618             return b;
3619         }
3620         if ((t /= d) == 1) {
3621             return b + c;
3622         }
3623         if (!p) {
3624             p = d * .3;
3625         }
3626
3627         if (!a || a < Math.abs(c)) {
3628             a = c;
3629             var s = p / 4;
3630         }
3631         else {
3632             var s = p / (2 * Math.PI) * Math.asin(c / a);
3633         }
3634
3635         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3636     },
3637
3638
3639     elasticOut: function (t, b, c, d, a, p) {
3640         if (t == 0) {
3641             return b;
3642         }
3643         if ((t /= d) == 1) {
3644             return b + c;
3645         }
3646         if (!p) {
3647             p = d * .3;
3648         }
3649
3650         if (!a || a < Math.abs(c)) {
3651             a = c;
3652             var s = p / 4;
3653         }
3654         else {
3655             var s = p / (2 * Math.PI) * Math.asin(c / a);
3656         }
3657
3658         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3659     },
3660
3661
3662     elasticBoth: function (t, b, c, d, a, p) {
3663         if (t == 0) {
3664             return b;
3665         }
3666
3667         if ((t /= d / 2) == 2) {
3668             return b + c;
3669         }
3670
3671         if (!p) {
3672             p = d * (.3 * 1.5);
3673         }
3674
3675         if (!a || a < Math.abs(c)) {
3676             a = c;
3677             var s = p / 4;
3678         }
3679         else {
3680             var s = p / (2 * Math.PI) * Math.asin(c / a);
3681         }
3682
3683         if (t < 1) {
3684             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3685                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3686         }
3687         return a * Math.pow(2, -10 * (t -= 1)) *
3688                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3689     },
3690
3691
3692
3693     backIn: function (t, b, c, d, s) {
3694         if (typeof s == 'undefined') {
3695             s = 1.70158;
3696         }
3697         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3698     },
3699
3700
3701     backOut: function (t, b, c, d, s) {
3702         if (typeof s == 'undefined') {
3703             s = 1.70158;
3704         }
3705         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3706     },
3707
3708
3709     backBoth: function (t, b, c, d, s) {
3710         if (typeof s == 'undefined') {
3711             s = 1.70158;
3712         }
3713
3714         if ((t /= d / 2 ) < 1) {
3715             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3716         }
3717         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3718     },
3719
3720
3721     bounceIn: function (t, b, c, d) {
3722         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3723     },
3724
3725
3726     bounceOut: function (t, b, c, d) {
3727         if ((t /= d) < (1 / 2.75)) {
3728             return c * (7.5625 * t * t) + b;
3729         } else if (t < (2 / 2.75)) {
3730             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3731         } else if (t < (2.5 / 2.75)) {
3732             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3733         }
3734         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3735     },
3736
3737
3738     bounceBoth: function (t, b, c, d) {
3739         if (t < d / 2) {
3740             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3741         }
3742         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3743     }
3744 };/*
3745  * Portions of this file are based on pieces of Yahoo User Interface Library
3746  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3747  * YUI licensed under the BSD License:
3748  * http://developer.yahoo.net/yui/license.txt
3749  * <script type="text/javascript">
3750  *
3751  */
3752     (function() {
3753         Roo.lib.Motion = function(el, attributes, duration, method) {
3754             if (el) {
3755                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3756             }
3757         };
3758
3759         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3760
3761
3762         var Y = Roo.lib;
3763         var superclass = Y.Motion.superclass;
3764         var proto = Y.Motion.prototype;
3765
3766         proto.toString = function() {
3767             var el = this.getEl();
3768             var id = el.id || el.tagName;
3769             return ("Motion " + id);
3770         };
3771
3772         proto.patterns.points = /^points$/i;
3773
3774         proto.setAttribute = function(attr, val, unit) {
3775             if (this.patterns.points.test(attr)) {
3776                 unit = unit || 'px';
3777                 superclass.setAttribute.call(this, 'left', val[0], unit);
3778                 superclass.setAttribute.call(this, 'top', val[1], unit);
3779             } else {
3780                 superclass.setAttribute.call(this, attr, val, unit);
3781             }
3782         };
3783
3784         proto.getAttribute = function(attr) {
3785             if (this.patterns.points.test(attr)) {
3786                 var val = [
3787                         superclass.getAttribute.call(this, 'left'),
3788                         superclass.getAttribute.call(this, 'top')
3789                         ];
3790             } else {
3791                 val = superclass.getAttribute.call(this, attr);
3792             }
3793
3794             return val;
3795         };
3796
3797         proto.doMethod = function(attr, start, end) {
3798             var val = null;
3799
3800             if (this.patterns.points.test(attr)) {
3801                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3802                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3803             } else {
3804                 val = superclass.doMethod.call(this, attr, start, end);
3805             }
3806             return val;
3807         };
3808
3809         proto.setRuntimeAttribute = function(attr) {
3810             if (this.patterns.points.test(attr)) {
3811                 var el = this.getEl();
3812                 var attributes = this.attributes;
3813                 var start;
3814                 var control = attributes['points']['control'] || [];
3815                 var end;
3816                 var i, len;
3817
3818                 if (control.length > 0 && !(control[0] instanceof Array)) {
3819                     control = [control];
3820                 } else {
3821                     var tmp = [];
3822                     for (i = 0,len = control.length; i < len; ++i) {
3823                         tmp[i] = control[i];
3824                     }
3825                     control = tmp;
3826                 }
3827
3828                 Roo.fly(el).position();
3829
3830                 if (isset(attributes['points']['from'])) {
3831                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3832                 }
3833                 else {
3834                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3835                 }
3836
3837                 start = this.getAttribute('points');
3838
3839
3840                 if (isset(attributes['points']['to'])) {
3841                     end = translateValues.call(this, attributes['points']['to'], start);
3842
3843                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3844                     for (i = 0,len = control.length; i < len; ++i) {
3845                         control[i] = translateValues.call(this, control[i], start);
3846                     }
3847
3848
3849                 } else if (isset(attributes['points']['by'])) {
3850                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3851
3852                     for (i = 0,len = control.length; i < len; ++i) {
3853                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3854                     }
3855                 }
3856
3857                 this.runtimeAttributes[attr] = [start];
3858
3859                 if (control.length > 0) {
3860                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3861                 }
3862
3863                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3864             }
3865             else {
3866                 superclass.setRuntimeAttribute.call(this, attr);
3867             }
3868         };
3869
3870         var translateValues = function(val, start) {
3871             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3872             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3873
3874             return val;
3875         };
3876
3877         var isset = function(prop) {
3878             return (typeof prop !== 'undefined');
3879         };
3880     })();
3881 /*
3882  * Portions of this file are based on pieces of Yahoo User Interface Library
3883  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3884  * YUI licensed under the BSD License:
3885  * http://developer.yahoo.net/yui/license.txt
3886  * <script type="text/javascript">
3887  *
3888  */
3889     (function() {
3890         Roo.lib.Scroll = function(el, attributes, duration, method) {
3891             if (el) {
3892                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3893             }
3894         };
3895
3896         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3897
3898
3899         var Y = Roo.lib;
3900         var superclass = Y.Scroll.superclass;
3901         var proto = Y.Scroll.prototype;
3902
3903         proto.toString = function() {
3904             var el = this.getEl();
3905             var id = el.id || el.tagName;
3906             return ("Scroll " + id);
3907         };
3908
3909         proto.doMethod = function(attr, start, end) {
3910             var val = null;
3911
3912             if (attr == 'scroll') {
3913                 val = [
3914                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3915                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3916                         ];
3917
3918             } else {
3919                 val = superclass.doMethod.call(this, attr, start, end);
3920             }
3921             return val;
3922         };
3923
3924         proto.getAttribute = function(attr) {
3925             var val = null;
3926             var el = this.getEl();
3927
3928             if (attr == 'scroll') {
3929                 val = [ el.scrollLeft, el.scrollTop ];
3930             } else {
3931                 val = superclass.getAttribute.call(this, attr);
3932             }
3933
3934             return val;
3935         };
3936
3937         proto.setAttribute = function(attr, val, unit) {
3938             var el = this.getEl();
3939
3940             if (attr == 'scroll') {
3941                 el.scrollLeft = val[0];
3942                 el.scrollTop = val[1];
3943             } else {
3944                 superclass.setAttribute.call(this, attr, val, unit);
3945             }
3946         };
3947     })();
3948 /*
3949  * Based on:
3950  * Ext JS Library 1.1.1
3951  * Copyright(c) 2006-2007, Ext JS, LLC.
3952  *
3953  * Originally Released Under LGPL - original licence link has changed is not relivant.
3954  *
3955  * Fork - LGPL
3956  * <script type="text/javascript">
3957  */
3958  
3959
3960 /**
3961  * @class Roo.DomHelper
3962  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3963  * 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>.
3964  * @singleton
3965  */
3966 Roo.DomHelper = function(){
3967     var tempTableEl = null;
3968     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3969     var tableRe = /^table|tbody|tr|td$/i;
3970     var xmlns = {};
3971     // build as innerHTML where available
3972     /** @ignore */
3973     var createHtml = function(o){
3974         if(typeof o == 'string'){
3975             return o;
3976         }
3977         var b = "";
3978         if(!o.tag){
3979             o.tag = "div";
3980         }
3981         b += "<" + o.tag;
3982         for(var attr in o){
3983             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3984             if(attr == "style"){
3985                 var s = o["style"];
3986                 if(typeof s == "function"){
3987                     s = s.call();
3988                 }
3989                 if(typeof s == "string"){
3990                     b += ' style="' + s + '"';
3991                 }else if(typeof s == "object"){
3992                     b += ' style="';
3993                     for(var key in s){
3994                         if(typeof s[key] != "function"){
3995                             b += key + ":" + s[key] + ";";
3996                         }
3997                     }
3998                     b += '"';
3999                 }
4000             }else{
4001                 if(attr == "cls"){
4002                     b += ' class="' + o["cls"] + '"';
4003                 }else if(attr == "htmlFor"){
4004                     b += ' for="' + o["htmlFor"] + '"';
4005                 }else{
4006                     b += " " + attr + '="' + o[attr] + '"';
4007                 }
4008             }
4009         }
4010         if(emptyTags.test(o.tag)){
4011             b += "/>";
4012         }else{
4013             b += ">";
4014             var cn = o.children || o.cn;
4015             if(cn){
4016                 //http://bugs.kde.org/show_bug.cgi?id=71506
4017                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4018                     for(var i = 0, len = cn.length; i < len; i++) {
4019                         b += createHtml(cn[i], b);
4020                     }
4021                 }else{
4022                     b += createHtml(cn, b);
4023                 }
4024             }
4025             if(o.html){
4026                 b += o.html;
4027             }
4028             b += "</" + o.tag + ">";
4029         }
4030         return b;
4031     };
4032
4033     // build as dom
4034     /** @ignore */
4035     var createDom = function(o, parentNode){
4036          
4037         // defininition craeted..
4038         var ns = false;
4039         if (o.ns && o.ns != 'html') {
4040                
4041             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4042                 xmlns[o.ns] = o.xmlns;
4043                 ns = o.xmlns;
4044             }
4045             if (typeof(xmlns[o.ns]) == 'undefined') {
4046                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4047             }
4048             ns = xmlns[o.ns];
4049         }
4050         
4051         
4052         if (typeof(o) == 'string') {
4053             return parentNode.appendChild(document.createTextNode(o));
4054         }
4055         o.tag = o.tag || div;
4056         if (o.ns && Roo.isIE) {
4057             ns = false;
4058             o.tag = o.ns + ':' + o.tag;
4059             
4060         }
4061         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4062         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4063         for(var attr in o){
4064             
4065             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4066                     attr == "style" || typeof o[attr] == "function") continue;
4067                     
4068             if(attr=="cls" && Roo.isIE){
4069                 el.className = o["cls"];
4070             }else{
4071                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4072                 else el[attr] = o[attr];
4073             }
4074         }
4075         Roo.DomHelper.applyStyles(el, o.style);
4076         var cn = o.children || o.cn;
4077         if(cn){
4078             //http://bugs.kde.org/show_bug.cgi?id=71506
4079              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4080                 for(var i = 0, len = cn.length; i < len; i++) {
4081                     createDom(cn[i], el);
4082                 }
4083             }else{
4084                 createDom(cn, el);
4085             }
4086         }
4087         if(o.html){
4088             el.innerHTML = o.html;
4089         }
4090         if(parentNode){
4091            parentNode.appendChild(el);
4092         }
4093         return el;
4094     };
4095
4096     var ieTable = function(depth, s, h, e){
4097         tempTableEl.innerHTML = [s, h, e].join('');
4098         var i = -1, el = tempTableEl;
4099         while(++i < depth){
4100             el = el.firstChild;
4101         }
4102         return el;
4103     };
4104
4105     // kill repeat to save bytes
4106     var ts = '<table>',
4107         te = '</table>',
4108         tbs = ts+'<tbody>',
4109         tbe = '</tbody>'+te,
4110         trs = tbs + '<tr>',
4111         tre = '</tr>'+tbe;
4112
4113     /**
4114      * @ignore
4115      * Nasty code for IE's broken table implementation
4116      */
4117     var insertIntoTable = function(tag, where, el, html){
4118         if(!tempTableEl){
4119             tempTableEl = document.createElement('div');
4120         }
4121         var node;
4122         var before = null;
4123         if(tag == 'td'){
4124             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4125                 return;
4126             }
4127             if(where == 'beforebegin'){
4128                 before = el;
4129                 el = el.parentNode;
4130             } else{
4131                 before = el.nextSibling;
4132                 el = el.parentNode;
4133             }
4134             node = ieTable(4, trs, html, tre);
4135         }
4136         else if(tag == 'tr'){
4137             if(where == 'beforebegin'){
4138                 before = el;
4139                 el = el.parentNode;
4140                 node = ieTable(3, tbs, html, tbe);
4141             } else if(where == 'afterend'){
4142                 before = el.nextSibling;
4143                 el = el.parentNode;
4144                 node = ieTable(3, tbs, html, tbe);
4145             } else{ // INTO a TR
4146                 if(where == 'afterbegin'){
4147                     before = el.firstChild;
4148                 }
4149                 node = ieTable(4, trs, html, tre);
4150             }
4151         } else if(tag == 'tbody'){
4152             if(where == 'beforebegin'){
4153                 before = el;
4154                 el = el.parentNode;
4155                 node = ieTable(2, ts, html, te);
4156             } else if(where == 'afterend'){
4157                 before = el.nextSibling;
4158                 el = el.parentNode;
4159                 node = ieTable(2, ts, html, te);
4160             } else{
4161                 if(where == 'afterbegin'){
4162                     before = el.firstChild;
4163                 }
4164                 node = ieTable(3, tbs, html, tbe);
4165             }
4166         } else{ // TABLE
4167             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4168                 return;
4169             }
4170             if(where == 'afterbegin'){
4171                 before = el.firstChild;
4172             }
4173             node = ieTable(2, ts, html, te);
4174         }
4175         el.insertBefore(node, before);
4176         return node;
4177     };
4178
4179     return {
4180     /** True to force the use of DOM instead of html fragments @type Boolean */
4181     useDom : false,
4182
4183     /**
4184      * Returns the markup for the passed Element(s) config
4185      * @param {Object} o The Dom object spec (and children)
4186      * @return {String}
4187      */
4188     markup : function(o){
4189         return createHtml(o);
4190     },
4191
4192     /**
4193      * Applies a style specification to an element
4194      * @param {String/HTMLElement} el The element to apply styles to
4195      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4196      * a function which returns such a specification.
4197      */
4198     applyStyles : function(el, styles){
4199         if(styles){
4200            el = Roo.fly(el);
4201            if(typeof styles == "string"){
4202                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4203                var matches;
4204                while ((matches = re.exec(styles)) != null){
4205                    el.setStyle(matches[1], matches[2]);
4206                }
4207            }else if (typeof styles == "object"){
4208                for (var style in styles){
4209                   el.setStyle(style, styles[style]);
4210                }
4211            }else if (typeof styles == "function"){
4212                 Roo.DomHelper.applyStyles(el, styles.call());
4213            }
4214         }
4215     },
4216
4217     /**
4218      * Inserts an HTML fragment into the Dom
4219      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4220      * @param {HTMLElement} el The context element
4221      * @param {String} html The HTML fragmenet
4222      * @return {HTMLElement} The new node
4223      */
4224     insertHtml : function(where, el, html){
4225         where = where.toLowerCase();
4226         if(el.insertAdjacentHTML){
4227             if(tableRe.test(el.tagName)){
4228                 var rs;
4229                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4230                     return rs;
4231                 }
4232             }
4233             switch(where){
4234                 case "beforebegin":
4235                     el.insertAdjacentHTML('BeforeBegin', html);
4236                     return el.previousSibling;
4237                 case "afterbegin":
4238                     el.insertAdjacentHTML('AfterBegin', html);
4239                     return el.firstChild;
4240                 case "beforeend":
4241                     el.insertAdjacentHTML('BeforeEnd', html);
4242                     return el.lastChild;
4243                 case "afterend":
4244                     el.insertAdjacentHTML('AfterEnd', html);
4245                     return el.nextSibling;
4246             }
4247             throw 'Illegal insertion point -> "' + where + '"';
4248         }
4249         var range = el.ownerDocument.createRange();
4250         var frag;
4251         switch(where){
4252              case "beforebegin":
4253                 range.setStartBefore(el);
4254                 frag = range.createContextualFragment(html);
4255                 el.parentNode.insertBefore(frag, el);
4256                 return el.previousSibling;
4257              case "afterbegin":
4258                 if(el.firstChild){
4259                     range.setStartBefore(el.firstChild);
4260                     frag = range.createContextualFragment(html);
4261                     el.insertBefore(frag, el.firstChild);
4262                     return el.firstChild;
4263                 }else{
4264                     el.innerHTML = html;
4265                     return el.firstChild;
4266                 }
4267             case "beforeend":
4268                 if(el.lastChild){
4269                     range.setStartAfter(el.lastChild);
4270                     frag = range.createContextualFragment(html);
4271                     el.appendChild(frag);
4272                     return el.lastChild;
4273                 }else{
4274                     el.innerHTML = html;
4275                     return el.lastChild;
4276                 }
4277             case "afterend":
4278                 range.setStartAfter(el);
4279                 frag = range.createContextualFragment(html);
4280                 el.parentNode.insertBefore(frag, el.nextSibling);
4281                 return el.nextSibling;
4282             }
4283             throw 'Illegal insertion point -> "' + where + '"';
4284     },
4285
4286     /**
4287      * Creates new Dom element(s) and inserts them before el
4288      * @param {String/HTMLElement/Element} el The context element
4289      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4290      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4291      * @return {HTMLElement/Roo.Element} The new node
4292      */
4293     insertBefore : function(el, o, returnElement){
4294         return this.doInsert(el, o, returnElement, "beforeBegin");
4295     },
4296
4297     /**
4298      * Creates new Dom element(s) and inserts them after el
4299      * @param {String/HTMLElement/Element} el The context element
4300      * @param {Object} o The Dom object spec (and children)
4301      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4302      * @return {HTMLElement/Roo.Element} The new node
4303      */
4304     insertAfter : function(el, o, returnElement){
4305         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4306     },
4307
4308     /**
4309      * Creates new Dom element(s) and inserts them as the first child of el
4310      * @param {String/HTMLElement/Element} el The context element
4311      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4312      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4313      * @return {HTMLElement/Roo.Element} The new node
4314      */
4315     insertFirst : function(el, o, returnElement){
4316         return this.doInsert(el, o, returnElement, "afterBegin");
4317     },
4318
4319     // private
4320     doInsert : function(el, o, returnElement, pos, sibling){
4321         el = Roo.getDom(el);
4322         var newNode;
4323         if(this.useDom || o.ns){
4324             newNode = createDom(o, null);
4325             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4326         }else{
4327             var html = createHtml(o);
4328             newNode = this.insertHtml(pos, el, html);
4329         }
4330         return returnElement ? Roo.get(newNode, true) : newNode;
4331     },
4332
4333     /**
4334      * Creates new Dom element(s) and appends them to el
4335      * @param {String/HTMLElement/Element} el The context element
4336      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4337      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4338      * @return {HTMLElement/Roo.Element} The new node
4339      */
4340     append : function(el, o, returnElement){
4341         el = Roo.getDom(el);
4342         var newNode;
4343         if(this.useDom || o.ns){
4344             newNode = createDom(o, null);
4345             el.appendChild(newNode);
4346         }else{
4347             var html = createHtml(o);
4348             newNode = this.insertHtml("beforeEnd", el, html);
4349         }
4350         return returnElement ? Roo.get(newNode, true) : newNode;
4351     },
4352
4353     /**
4354      * Creates new Dom element(s) and overwrites the contents of el with them
4355      * @param {String/HTMLElement/Element} el The context element
4356      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4357      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4358      * @return {HTMLElement/Roo.Element} The new node
4359      */
4360     overwrite : function(el, o, returnElement){
4361         el = Roo.getDom(el);
4362         if (o.ns) {
4363           
4364             while (el.childNodes.length) {
4365                 el.removeChild(el.firstChild);
4366             }
4367             createDom(o, el);
4368         } else {
4369             el.innerHTML = createHtml(o);   
4370         }
4371         
4372         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4373     },
4374
4375     /**
4376      * Creates a new Roo.DomHelper.Template from the Dom object spec
4377      * @param {Object} o The Dom object spec (and children)
4378      * @return {Roo.DomHelper.Template} The new template
4379      */
4380     createTemplate : function(o){
4381         var html = createHtml(o);
4382         return new Roo.Template(html);
4383     }
4384     };
4385 }();
4386 /*
4387  * Based on:
4388  * Ext JS Library 1.1.1
4389  * Copyright(c) 2006-2007, Ext JS, LLC.
4390  *
4391  * Originally Released Under LGPL - original licence link has changed is not relivant.
4392  *
4393  * Fork - LGPL
4394  * <script type="text/javascript">
4395  */
4396  
4397 /**
4398 * @class Roo.Template
4399 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4400 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4401 * Usage:
4402 <pre><code>
4403 var t = new Roo.Template(
4404     '&lt;div name="{id}"&gt;',
4405         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
4406     '&lt;/div&gt;'
4407 );
4408 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4409 </code></pre>
4410 * 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>. 
4411 * @constructor
4412 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4413 */
4414 Roo.Template = function(html){
4415     if(html instanceof Array){
4416         html = html.join("");
4417     }else if(arguments.length > 1){
4418         html = Array.prototype.join.call(arguments, "");
4419     }
4420     /**@private*/
4421     this.html = html;
4422     
4423 };
4424 Roo.Template.prototype = {
4425     /**
4426      * Returns an HTML fragment of this template with the specified values applied.
4427      * @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'})
4428      * @return {String} The HTML fragment
4429      */
4430     applyTemplate : function(values){
4431         try {
4432             
4433             if(this.compiled){
4434                 return this.compiled(values);
4435             }
4436             var useF = this.disableFormats !== true;
4437             var fm = Roo.util.Format, tpl = this;
4438             var fn = function(m, name, format, args){
4439                 if(format && useF){
4440                     if(format.substr(0, 5) == "this."){
4441                         return tpl.call(format.substr(5), values[name], values);
4442                     }else{
4443                         if(args){
4444                             // quoted values are required for strings in compiled templates, 
4445                             // but for non compiled we need to strip them
4446                             // quoted reversed for jsmin
4447                             var re = /^\s*['"](.*)["']\s*$/;
4448                             args = args.split(',');
4449                             for(var i = 0, len = args.length; i < len; i++){
4450                                 args[i] = args[i].replace(re, "$1");
4451                             }
4452                             args = [values[name]].concat(args);
4453                         }else{
4454                             args = [values[name]];
4455                         }
4456                         return fm[format].apply(fm, args);
4457                     }
4458                 }else{
4459                     return values[name] !== undefined ? values[name] : "";
4460                 }
4461             };
4462             return this.html.replace(this.re, fn);
4463         } catch (e) {
4464             Roo.log(e);
4465         }
4466         return '';
4467     },
4468     
4469     /**
4470      * Sets the HTML used as the template and optionally compiles it.
4471      * @param {String} html
4472      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4473      * @return {Roo.Template} this
4474      */
4475     set : function(html, compile){
4476         this.html = html;
4477         this.compiled = null;
4478         if(compile){
4479             this.compile();
4480         }
4481         return this;
4482     },
4483     
4484     /**
4485      * True to disable format functions (defaults to false)
4486      * @type Boolean
4487      */
4488     disableFormats : false,
4489     
4490     /**
4491     * The regular expression used to match template variables 
4492     * @type RegExp
4493     * @property 
4494     */
4495     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4496     
4497     /**
4498      * Compiles the template into an internal function, eliminating the RegEx overhead.
4499      * @return {Roo.Template} this
4500      */
4501     compile : function(){
4502         var fm = Roo.util.Format;
4503         var useF = this.disableFormats !== true;
4504         var sep = Roo.isGecko ? "+" : ",";
4505         var fn = function(m, name, format, args){
4506             if(format && useF){
4507                 args = args ? ',' + args : "";
4508                 if(format.substr(0, 5) != "this."){
4509                     format = "fm." + format + '(';
4510                 }else{
4511                     format = 'this.call("'+ format.substr(5) + '", ';
4512                     args = ", values";
4513                 }
4514             }else{
4515                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4516             }
4517             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4518         };
4519         var body;
4520         // branched to use + in gecko and [].join() in others
4521         if(Roo.isGecko){
4522             body = "this.compiled = function(values){ return '" +
4523                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4524                     "';};";
4525         }else{
4526             body = ["this.compiled = function(values){ return ['"];
4527             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4528             body.push("'].join('');};");
4529             body = body.join('');
4530         }
4531         /**
4532          * eval:var:values
4533          * eval:var:fm
4534          */
4535         eval(body);
4536         return this;
4537     },
4538     
4539     // private function used to call members
4540     call : function(fnName, value, allValues){
4541         return this[fnName](value, allValues);
4542     },
4543     
4544     /**
4545      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4546      * @param {String/HTMLElement/Roo.Element} el The context element
4547      * @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'})
4548      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4549      * @return {HTMLElement/Roo.Element} The new node or Element
4550      */
4551     insertFirst: function(el, values, returnElement){
4552         return this.doInsert('afterBegin', el, values, returnElement);
4553     },
4554
4555     /**
4556      * Applies the supplied values to the template and inserts the new node(s) before el.
4557      * @param {String/HTMLElement/Roo.Element} el The context element
4558      * @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'})
4559      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4560      * @return {HTMLElement/Roo.Element} The new node or Element
4561      */
4562     insertBefore: function(el, values, returnElement){
4563         return this.doInsert('beforeBegin', el, values, returnElement);
4564     },
4565
4566     /**
4567      * Applies the supplied values to the template and inserts the new node(s) after el.
4568      * @param {String/HTMLElement/Roo.Element} el The context element
4569      * @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'})
4570      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4571      * @return {HTMLElement/Roo.Element} The new node or Element
4572      */
4573     insertAfter : function(el, values, returnElement){
4574         return this.doInsert('afterEnd', el, values, returnElement);
4575     },
4576     
4577     /**
4578      * Applies the supplied values to the template and appends the new node(s) to 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     append : function(el, values, returnElement){
4585         return this.doInsert('beforeEnd', el, values, returnElement);
4586     },
4587
4588     doInsert : function(where, el, values, returnEl){
4589         el = Roo.getDom(el);
4590         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4591         return returnEl ? Roo.get(newNode, true) : newNode;
4592     },
4593
4594     /**
4595      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4596      * @param {String/HTMLElement/Roo.Element} el The context element
4597      * @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'})
4598      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4599      * @return {HTMLElement/Roo.Element} The new node or Element
4600      */
4601     overwrite : function(el, values, returnElement){
4602         el = Roo.getDom(el);
4603         el.innerHTML = this.applyTemplate(values);
4604         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4605     }
4606 };
4607 /**
4608  * Alias for {@link #applyTemplate}
4609  * @method
4610  */
4611 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4612
4613 // backwards compat
4614 Roo.DomHelper.Template = Roo.Template;
4615
4616 /**
4617  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4618  * @param {String/HTMLElement} el A DOM element or its id
4619  * @returns {Roo.Template} The created template
4620  * @static
4621  */
4622 Roo.Template.from = function(el){
4623     el = Roo.getDom(el);
4624     return new Roo.Template(el.value || el.innerHTML);
4625 };/*
4626  * Based on:
4627  * Ext JS Library 1.1.1
4628  * Copyright(c) 2006-2007, Ext JS, LLC.
4629  *
4630  * Originally Released Under LGPL - original licence link has changed is not relivant.
4631  *
4632  * Fork - LGPL
4633  * <script type="text/javascript">
4634  */
4635  
4636
4637 /*
4638  * This is code is also distributed under MIT license for use
4639  * with jQuery and prototype JavaScript libraries.
4640  */
4641 /**
4642  * @class Roo.DomQuery
4643 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).
4644 <p>
4645 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>
4646
4647 <p>
4648 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.
4649 </p>
4650 <h4>Element Selectors:</h4>
4651 <ul class="list">
4652     <li> <b>*</b> any element</li>
4653     <li> <b>E</b> an element with the tag E</li>
4654     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4655     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4656     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4657     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4658 </ul>
4659 <h4>Attribute Selectors:</h4>
4660 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4661 <ul class="list">
4662     <li> <b>E[foo]</b> has an attribute "foo"</li>
4663     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4664     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4665     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4666     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4667     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4668     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4669 </ul>
4670 <h4>Pseudo Classes:</h4>
4671 <ul class="list">
4672     <li> <b>E:first-child</b> E is the first child of its parent</li>
4673     <li> <b>E:last-child</b> E is the last child of its parent</li>
4674     <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>
4675     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4676     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4677     <li> <b>E:only-child</b> E is the only child of its parent</li>
4678     <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>
4679     <li> <b>E:first</b> the first E in the resultset</li>
4680     <li> <b>E:last</b> the last E in the resultset</li>
4681     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4682     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4683     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4684     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4685     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4686     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4687     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4688     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4689     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4690 </ul>
4691 <h4>CSS Value Selectors:</h4>
4692 <ul class="list">
4693     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4694     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4695     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4696     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4697     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4698     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4699 </ul>
4700  * @singleton
4701  */
4702 Roo.DomQuery = function(){
4703     var cache = {}, simpleCache = {}, valueCache = {};
4704     var nonSpace = /\S/;
4705     var trimRe = /^\s+|\s+$/g;
4706     var tplRe = /\{(\d+)\}/g;
4707     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4708     var tagTokenRe = /^(#)?([\w-\*]+)/;
4709     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4710
4711     function child(p, index){
4712         var i = 0;
4713         var n = p.firstChild;
4714         while(n){
4715             if(n.nodeType == 1){
4716                if(++i == index){
4717                    return n;
4718                }
4719             }
4720             n = n.nextSibling;
4721         }
4722         return null;
4723     };
4724
4725     function next(n){
4726         while((n = n.nextSibling) && n.nodeType != 1);
4727         return n;
4728     };
4729
4730     function prev(n){
4731         while((n = n.previousSibling) && n.nodeType != 1);
4732         return n;
4733     };
4734
4735     function children(d){
4736         var n = d.firstChild, ni = -1;
4737             while(n){
4738                 var nx = n.nextSibling;
4739                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4740                     d.removeChild(n);
4741                 }else{
4742                     n.nodeIndex = ++ni;
4743                 }
4744                 n = nx;
4745             }
4746             return this;
4747         };
4748
4749     function byClassName(c, a, v){
4750         if(!v){
4751             return c;
4752         }
4753         var r = [], ri = -1, cn;
4754         for(var i = 0, ci; ci = c[i]; i++){
4755             if((' '+ci.className+' ').indexOf(v) != -1){
4756                 r[++ri] = ci;
4757             }
4758         }
4759         return r;
4760     };
4761
4762     function attrValue(n, attr){
4763         if(!n.tagName && typeof n.length != "undefined"){
4764             n = n[0];
4765         }
4766         if(!n){
4767             return null;
4768         }
4769         if(attr == "for"){
4770             return n.htmlFor;
4771         }
4772         if(attr == "class" || attr == "className"){
4773             return n.className;
4774         }
4775         return n.getAttribute(attr) || n[attr];
4776
4777     };
4778
4779     function getNodes(ns, mode, tagName){
4780         var result = [], ri = -1, cs;
4781         if(!ns){
4782             return result;
4783         }
4784         tagName = tagName || "*";
4785         if(typeof ns.getElementsByTagName != "undefined"){
4786             ns = [ns];
4787         }
4788         if(!mode){
4789             for(var i = 0, ni; ni = ns[i]; i++){
4790                 cs = ni.getElementsByTagName(tagName);
4791                 for(var j = 0, ci; ci = cs[j]; j++){
4792                     result[++ri] = ci;
4793                 }
4794             }
4795         }else if(mode == "/" || mode == ">"){
4796             var utag = tagName.toUpperCase();
4797             for(var i = 0, ni, cn; ni = ns[i]; i++){
4798                 cn = ni.children || ni.childNodes;
4799                 for(var j = 0, cj; cj = cn[j]; j++){
4800                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4801                         result[++ri] = cj;
4802                     }
4803                 }
4804             }
4805         }else if(mode == "+"){
4806             var utag = tagName.toUpperCase();
4807             for(var i = 0, n; n = ns[i]; i++){
4808                 while((n = n.nextSibling) && n.nodeType != 1);
4809                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4810                     result[++ri] = n;
4811                 }
4812             }
4813         }else if(mode == "~"){
4814             for(var i = 0, n; n = ns[i]; i++){
4815                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4816                 if(n){
4817                     result[++ri] = n;
4818                 }
4819             }
4820         }
4821         return result;
4822     };
4823
4824     function concat(a, b){
4825         if(b.slice){
4826             return a.concat(b);
4827         }
4828         for(var i = 0, l = b.length; i < l; i++){
4829             a[a.length] = b[i];
4830         }
4831         return a;
4832     }
4833
4834     function byTag(cs, tagName){
4835         if(cs.tagName || cs == document){
4836             cs = [cs];
4837         }
4838         if(!tagName){
4839             return cs;
4840         }
4841         var r = [], ri = -1;
4842         tagName = tagName.toLowerCase();
4843         for(var i = 0, ci; ci = cs[i]; i++){
4844             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4845                 r[++ri] = ci;
4846             }
4847         }
4848         return r;
4849     };
4850
4851     function byId(cs, attr, id){
4852         if(cs.tagName || cs == document){
4853             cs = [cs];
4854         }
4855         if(!id){
4856             return cs;
4857         }
4858         var r = [], ri = -1;
4859         for(var i = 0,ci; ci = cs[i]; i++){
4860             if(ci && ci.id == id){
4861                 r[++ri] = ci;
4862                 return r;
4863             }
4864         }
4865         return r;
4866     };
4867
4868     function byAttribute(cs, attr, value, op, custom){
4869         var r = [], ri = -1, st = custom=="{";
4870         var f = Roo.DomQuery.operators[op];
4871         for(var i = 0, ci; ci = cs[i]; i++){
4872             var a;
4873             if(st){
4874                 a = Roo.DomQuery.getStyle(ci, attr);
4875             }
4876             else if(attr == "class" || attr == "className"){
4877                 a = ci.className;
4878             }else if(attr == "for"){
4879                 a = ci.htmlFor;
4880             }else if(attr == "href"){
4881                 a = ci.getAttribute("href", 2);
4882             }else{
4883                 a = ci.getAttribute(attr);
4884             }
4885             if((f && f(a, value)) || (!f && a)){
4886                 r[++ri] = ci;
4887             }
4888         }
4889         return r;
4890     };
4891
4892     function byPseudo(cs, name, value){
4893         return Roo.DomQuery.pseudos[name](cs, value);
4894     };
4895
4896     // This is for IE MSXML which does not support expandos.
4897     // IE runs the same speed using setAttribute, however FF slows way down
4898     // and Safari completely fails so they need to continue to use expandos.
4899     var isIE = window.ActiveXObject ? true : false;
4900
4901     // this eval is stop the compressor from
4902     // renaming the variable to something shorter
4903     
4904     /** eval:var:batch */
4905     var batch = 30803; 
4906
4907     var key = 30803;
4908
4909     function nodupIEXml(cs){
4910         var d = ++key;
4911         cs[0].setAttribute("_nodup", d);
4912         var r = [cs[0]];
4913         for(var i = 1, len = cs.length; i < len; i++){
4914             var c = cs[i];
4915             if(!c.getAttribute("_nodup") != d){
4916                 c.setAttribute("_nodup", d);
4917                 r[r.length] = c;
4918             }
4919         }
4920         for(var i = 0, len = cs.length; i < len; i++){
4921             cs[i].removeAttribute("_nodup");
4922         }
4923         return r;
4924     }
4925
4926     function nodup(cs){
4927         if(!cs){
4928             return [];
4929         }
4930         var len = cs.length, c, i, r = cs, cj, ri = -1;
4931         if(!len || typeof cs.nodeType != "undefined" || len == 1){
4932             return cs;
4933         }
4934         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4935             return nodupIEXml(cs);
4936         }
4937         var d = ++key;
4938         cs[0]._nodup = d;
4939         for(i = 1; c = cs[i]; i++){
4940             if(c._nodup != d){
4941                 c._nodup = d;
4942             }else{
4943                 r = [];
4944                 for(var j = 0; j < i; j++){
4945                     r[++ri] = cs[j];
4946                 }
4947                 for(j = i+1; cj = cs[j]; j++){
4948                     if(cj._nodup != d){
4949                         cj._nodup = d;
4950                         r[++ri] = cj;
4951                     }
4952                 }
4953                 return r;
4954             }
4955         }
4956         return r;
4957     }
4958
4959     function quickDiffIEXml(c1, c2){
4960         var d = ++key;
4961         for(var i = 0, len = c1.length; i < len; i++){
4962             c1[i].setAttribute("_qdiff", d);
4963         }
4964         var r = [];
4965         for(var i = 0, len = c2.length; i < len; i++){
4966             if(c2[i].getAttribute("_qdiff") != d){
4967                 r[r.length] = c2[i];
4968             }
4969         }
4970         for(var i = 0, len = c1.length; i < len; i++){
4971            c1[i].removeAttribute("_qdiff");
4972         }
4973         return r;
4974     }
4975
4976     function quickDiff(c1, c2){
4977         var len1 = c1.length;
4978         if(!len1){
4979             return c2;
4980         }
4981         if(isIE && c1[0].selectSingleNode){
4982             return quickDiffIEXml(c1, c2);
4983         }
4984         var d = ++key;
4985         for(var i = 0; i < len1; i++){
4986             c1[i]._qdiff = d;
4987         }
4988         var r = [];
4989         for(var i = 0, len = c2.length; i < len; i++){
4990             if(c2[i]._qdiff != d){
4991                 r[r.length] = c2[i];
4992             }
4993         }
4994         return r;
4995     }
4996
4997     function quickId(ns, mode, root, id){
4998         if(ns == root){
4999            var d = root.ownerDocument || root;
5000            return d.getElementById(id);
5001         }
5002         ns = getNodes(ns, mode, "*");
5003         return byId(ns, null, id);
5004     }
5005
5006     return {
5007         getStyle : function(el, name){
5008             return Roo.fly(el).getStyle(name);
5009         },
5010         /**
5011          * Compiles a selector/xpath query into a reusable function. The returned function
5012          * takes one parameter "root" (optional), which is the context node from where the query should start.
5013          * @param {String} selector The selector/xpath query
5014          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5015          * @return {Function}
5016          */
5017         compile : function(path, type){
5018             type = type || "select";
5019             
5020             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5021             var q = path, mode, lq;
5022             var tk = Roo.DomQuery.matchers;
5023             var tklen = tk.length;
5024             var mm;
5025
5026             // accept leading mode switch
5027             var lmode = q.match(modeRe);
5028             if(lmode && lmode[1]){
5029                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5030                 q = q.replace(lmode[1], "");
5031             }
5032             // strip leading slashes
5033             while(path.substr(0, 1)=="/"){
5034                 path = path.substr(1);
5035             }
5036
5037             while(q && lq != q){
5038                 lq = q;
5039                 var tm = q.match(tagTokenRe);
5040                 if(type == "select"){
5041                     if(tm){
5042                         if(tm[1] == "#"){
5043                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5044                         }else{
5045                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5046                         }
5047                         q = q.replace(tm[0], "");
5048                     }else if(q.substr(0, 1) != '@'){
5049                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5050                     }
5051                 }else{
5052                     if(tm){
5053                         if(tm[1] == "#"){
5054                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5055                         }else{
5056                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5057                         }
5058                         q = q.replace(tm[0], "");
5059                     }
5060                 }
5061                 while(!(mm = q.match(modeRe))){
5062                     var matched = false;
5063                     for(var j = 0; j < tklen; j++){
5064                         var t = tk[j];
5065                         var m = q.match(t.re);
5066                         if(m){
5067                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5068                                                     return m[i];
5069                                                 });
5070                             q = q.replace(m[0], "");
5071                             matched = true;
5072                             break;
5073                         }
5074                     }
5075                     // prevent infinite loop on bad selector
5076                     if(!matched){
5077                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5078                     }
5079                 }
5080                 if(mm[1]){
5081                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5082                     q = q.replace(mm[1], "");
5083                 }
5084             }
5085             fn[fn.length] = "return nodup(n);\n}";
5086             
5087              /** 
5088               * list of variables that need from compression as they are used by eval.
5089              *  eval:var:batch 
5090              *  eval:var:nodup
5091              *  eval:var:byTag
5092              *  eval:var:ById
5093              *  eval:var:getNodes
5094              *  eval:var:quickId
5095              *  eval:var:mode
5096              *  eval:var:root
5097              *  eval:var:n
5098              *  eval:var:byClassName
5099              *  eval:var:byPseudo
5100              *  eval:var:byAttribute
5101              *  eval:var:attrValue
5102              * 
5103              **/ 
5104             eval(fn.join(""));
5105             return f;
5106         },
5107
5108         /**
5109          * Selects a group of elements.
5110          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5111          * @param {Node} root (optional) The start of the query (defaults to document).
5112          * @return {Array}
5113          */
5114         select : function(path, root, type){
5115             if(!root || root == document){
5116                 root = document;
5117             }
5118             if(typeof root == "string"){
5119                 root = document.getElementById(root);
5120             }
5121             var paths = path.split(",");
5122             var results = [];
5123             for(var i = 0, len = paths.length; i < len; i++){
5124                 var p = paths[i].replace(trimRe, "");
5125                 if(!cache[p]){
5126                     cache[p] = Roo.DomQuery.compile(p);
5127                     if(!cache[p]){
5128                         throw p + " is not a valid selector";
5129                     }
5130                 }
5131                 var result = cache[p](root);
5132                 if(result && result != document){
5133                     results = results.concat(result);
5134                 }
5135             }
5136             if(paths.length > 1){
5137                 return nodup(results);
5138             }
5139             return results;
5140         },
5141
5142         /**
5143          * Selects a single element.
5144          * @param {String} selector The selector/xpath query
5145          * @param {Node} root (optional) The start of the query (defaults to document).
5146          * @return {Element}
5147          */
5148         selectNode : function(path, root){
5149             return Roo.DomQuery.select(path, root)[0];
5150         },
5151
5152         /**
5153          * Selects the value of a node, optionally replacing null with the defaultValue.
5154          * @param {String} selector The selector/xpath query
5155          * @param {Node} root (optional) The start of the query (defaults to document).
5156          * @param {String} defaultValue
5157          */
5158         selectValue : function(path, root, defaultValue){
5159             path = path.replace(trimRe, "");
5160             if(!valueCache[path]){
5161                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5162             }
5163             var n = valueCache[path](root);
5164             n = n[0] ? n[0] : n;
5165             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5166             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5167         },
5168
5169         /**
5170          * Selects the value of a node, parsing integers and floats.
5171          * @param {String} selector The selector/xpath query
5172          * @param {Node} root (optional) The start of the query (defaults to document).
5173          * @param {Number} defaultValue
5174          * @return {Number}
5175          */
5176         selectNumber : function(path, root, defaultValue){
5177             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5178             return parseFloat(v);
5179         },
5180
5181         /**
5182          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5183          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5184          * @param {String} selector The simple selector to test
5185          * @return {Boolean}
5186          */
5187         is : function(el, ss){
5188             if(typeof el == "string"){
5189                 el = document.getElementById(el);
5190             }
5191             var isArray = (el instanceof Array);
5192             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5193             return isArray ? (result.length == el.length) : (result.length > 0);
5194         },
5195
5196         /**
5197          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5198          * @param {Array} el An array of elements to filter
5199          * @param {String} selector The simple selector to test
5200          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5201          * the selector instead of the ones that match
5202          * @return {Array}
5203          */
5204         filter : function(els, ss, nonMatches){
5205             ss = ss.replace(trimRe, "");
5206             if(!simpleCache[ss]){
5207                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5208             }
5209             var result = simpleCache[ss](els);
5210             return nonMatches ? quickDiff(result, els) : result;
5211         },
5212
5213         /**
5214          * Collection of matching regular expressions and code snippets.
5215          */
5216         matchers : [{
5217                 re: /^\.([\w-]+)/,
5218                 select: 'n = byClassName(n, null, " {1} ");'
5219             }, {
5220                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5221                 select: 'n = byPseudo(n, "{1}", "{2}");'
5222             },{
5223                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5224                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5225             }, {
5226                 re: /^#([\w-]+)/,
5227                 select: 'n = byId(n, null, "{1}");'
5228             },{
5229                 re: /^@([\w-]+)/,
5230                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5231             }
5232         ],
5233
5234         /**
5235          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5236          * 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;.
5237          */
5238         operators : {
5239             "=" : function(a, v){
5240                 return a == v;
5241             },
5242             "!=" : function(a, v){
5243                 return a != v;
5244             },
5245             "^=" : function(a, v){
5246                 return a && a.substr(0, v.length) == v;
5247             },
5248             "$=" : function(a, v){
5249                 return a && a.substr(a.length-v.length) == v;
5250             },
5251             "*=" : function(a, v){
5252                 return a && a.indexOf(v) !== -1;
5253             },
5254             "%=" : function(a, v){
5255                 return (a % v) == 0;
5256             },
5257             "|=" : function(a, v){
5258                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5259             },
5260             "~=" : function(a, v){
5261                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5262             }
5263         },
5264
5265         /**
5266          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5267          * and the argument (if any) supplied in the selector.
5268          */
5269         pseudos : {
5270             "first-child" : function(c){
5271                 var r = [], ri = -1, n;
5272                 for(var i = 0, ci; ci = n = c[i]; i++){
5273                     while((n = n.previousSibling) && n.nodeType != 1);
5274                     if(!n){
5275                         r[++ri] = ci;
5276                     }
5277                 }
5278                 return r;
5279             },
5280
5281             "last-child" : function(c){
5282                 var r = [], ri = -1, n;
5283                 for(var i = 0, ci; ci = n = c[i]; i++){
5284                     while((n = n.nextSibling) && n.nodeType != 1);
5285                     if(!n){
5286                         r[++ri] = ci;
5287                     }
5288                 }
5289                 return r;
5290             },
5291
5292             "nth-child" : function(c, a) {
5293                 var r = [], ri = -1;
5294                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5295                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5296                 for(var i = 0, n; n = c[i]; i++){
5297                     var pn = n.parentNode;
5298                     if (batch != pn._batch) {
5299                         var j = 0;
5300                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5301                             if(cn.nodeType == 1){
5302                                cn.nodeIndex = ++j;
5303                             }
5304                         }
5305                         pn._batch = batch;
5306                     }
5307                     if (f == 1) {
5308                         if (l == 0 || n.nodeIndex == l){
5309                             r[++ri] = n;
5310                         }
5311                     } else if ((n.nodeIndex + l) % f == 0){
5312                         r[++ri] = n;
5313                     }
5314                 }
5315
5316                 return r;
5317             },
5318
5319             "only-child" : function(c){
5320                 var r = [], ri = -1;;
5321                 for(var i = 0, ci; ci = c[i]; i++){
5322                     if(!prev(ci) && !next(ci)){
5323                         r[++ri] = ci;
5324                     }
5325                 }
5326                 return r;
5327             },
5328
5329             "empty" : function(c){
5330                 var r = [], ri = -1;
5331                 for(var i = 0, ci; ci = c[i]; i++){
5332                     var cns = ci.childNodes, j = 0, cn, empty = true;
5333                     while(cn = cns[j]){
5334                         ++j;
5335                         if(cn.nodeType == 1 || cn.nodeType == 3){
5336                             empty = false;
5337                             break;
5338                         }
5339                     }
5340                     if(empty){
5341                         r[++ri] = ci;
5342                     }
5343                 }
5344                 return r;
5345             },
5346
5347             "contains" : function(c, v){
5348                 var r = [], ri = -1;
5349                 for(var i = 0, ci; ci = c[i]; i++){
5350                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5351                         r[++ri] = ci;
5352                     }
5353                 }
5354                 return r;
5355             },
5356
5357             "nodeValue" : function(c, v){
5358                 var r = [], ri = -1;
5359                 for(var i = 0, ci; ci = c[i]; i++){
5360                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5361                         r[++ri] = ci;
5362                     }
5363                 }
5364                 return r;
5365             },
5366
5367             "checked" : function(c){
5368                 var r = [], ri = -1;
5369                 for(var i = 0, ci; ci = c[i]; i++){
5370                     if(ci.checked == true){
5371                         r[++ri] = ci;
5372                     }
5373                 }
5374                 return r;
5375             },
5376
5377             "not" : function(c, ss){
5378                 return Roo.DomQuery.filter(c, ss, true);
5379             },
5380
5381             "odd" : function(c){
5382                 return this["nth-child"](c, "odd");
5383             },
5384
5385             "even" : function(c){
5386                 return this["nth-child"](c, "even");
5387             },
5388
5389             "nth" : function(c, a){
5390                 return c[a-1] || [];
5391             },
5392
5393             "first" : function(c){
5394                 return c[0] || [];
5395             },
5396
5397             "last" : function(c){
5398                 return c[c.length-1] || [];
5399             },
5400
5401             "has" : function(c, ss){
5402                 var s = Roo.DomQuery.select;
5403                 var r = [], ri = -1;
5404                 for(var i = 0, ci; ci = c[i]; i++){
5405                     if(s(ss, ci).length > 0){
5406                         r[++ri] = ci;
5407                     }
5408                 }
5409                 return r;
5410             },
5411
5412             "next" : function(c, ss){
5413                 var is = Roo.DomQuery.is;
5414                 var r = [], ri = -1;
5415                 for(var i = 0, ci; ci = c[i]; i++){
5416                     var n = next(ci);
5417                     if(n && is(n, ss)){
5418                         r[++ri] = ci;
5419                     }
5420                 }
5421                 return r;
5422             },
5423
5424             "prev" : function(c, ss){
5425                 var is = Roo.DomQuery.is;
5426                 var r = [], ri = -1;
5427                 for(var i = 0, ci; ci = c[i]; i++){
5428                     var n = prev(ci);
5429                     if(n && is(n, ss)){
5430                         r[++ri] = ci;
5431                     }
5432                 }
5433                 return r;
5434             }
5435         }
5436     };
5437 }();
5438
5439 /**
5440  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5441  * @param {String} path The selector/xpath query
5442  * @param {Node} root (optional) The start of the query (defaults to document).
5443  * @return {Array}
5444  * @member Roo
5445  * @method query
5446  */
5447 Roo.query = Roo.DomQuery.select;
5448 /*
5449  * Based on:
5450  * Ext JS Library 1.1.1
5451  * Copyright(c) 2006-2007, Ext JS, LLC.
5452  *
5453  * Originally Released Under LGPL - original licence link has changed is not relivant.
5454  *
5455  * Fork - LGPL
5456  * <script type="text/javascript">
5457  */
5458
5459 /**
5460  * @class Roo.util.Observable
5461  * Base class that provides a common interface for publishing events. Subclasses are expected to
5462  * to have a property "events" with all the events defined.<br>
5463  * For example:
5464  * <pre><code>
5465  Employee = function(name){
5466     this.name = name;
5467     this.addEvents({
5468         "fired" : true,
5469         "quit" : true
5470     });
5471  }
5472  Roo.extend(Employee, Roo.util.Observable);
5473 </code></pre>
5474  * @param {Object} config properties to use (incuding events / listeners)
5475  */
5476
5477 Roo.util.Observable = function(cfg){
5478     
5479     cfg = cfg|| {};
5480     this.addEvents(cfg.events || {});
5481     if (cfg.events) {
5482         delete cfg.events; // make sure
5483     }
5484      
5485     Roo.apply(this, cfg);
5486     
5487     if(this.listeners){
5488         this.on(this.listeners);
5489         delete this.listeners;
5490     }
5491 };
5492 Roo.util.Observable.prototype = {
5493     /** 
5494  * @cfg {Object} listeners  list of events and functions to call for this object, 
5495  * For example :
5496  * <pre><code>
5497     listeners :  { 
5498        'click' : function(e) {
5499            ..... 
5500         } ,
5501         .... 
5502     } 
5503   </code></pre>
5504  */
5505     
5506     
5507     /**
5508      * Fires the specified event with the passed parameters (minus the event name).
5509      * @param {String} eventName
5510      * @param {Object...} args Variable number of parameters are passed to handlers
5511      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5512      */
5513     fireEvent : function(){
5514         var ce = this.events[arguments[0].toLowerCase()];
5515         if(typeof ce == "object"){
5516             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5517         }else{
5518             return true;
5519         }
5520     },
5521
5522     // private
5523     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5524
5525     /**
5526      * Appends an event handler to this component
5527      * @param {String}   eventName The type of event to listen for
5528      * @param {Function} handler The method the event invokes
5529      * @param {Object}   scope (optional) The scope in which to execute the handler
5530      * function. The handler function's "this" context.
5531      * @param {Object}   options (optional) An object containing handler configuration
5532      * properties. This may contain any of the following properties:<ul>
5533      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5534      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5535      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5536      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5537      * by the specified number of milliseconds. If the event fires again within that time, the original
5538      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5539      * </ul><br>
5540      * <p>
5541      * <b>Combining Options</b><br>
5542      * Using the options argument, it is possible to combine different types of listeners:<br>
5543      * <br>
5544      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5545                 <pre><code>
5546                 el.on('click', this.onClick, this, {
5547                         single: true,
5548                 delay: 100,
5549                 forumId: 4
5550                 });
5551                 </code></pre>
5552      * <p>
5553      * <b>Attaching multiple handlers in 1 call</b><br>
5554      * The method also allows for a single argument to be passed which is a config object containing properties
5555      * which specify multiple handlers.
5556      * <pre><code>
5557                 el.on({
5558                         'click': {
5559                         fn: this.onClick,
5560                         scope: this,
5561                         delay: 100
5562                 }, 
5563                 'mouseover': {
5564                         fn: this.onMouseOver,
5565                         scope: this
5566                 },
5567                 'mouseout': {
5568                         fn: this.onMouseOut,
5569                         scope: this
5570                 }
5571                 });
5572                 </code></pre>
5573      * <p>
5574      * Or a shorthand syntax which passes the same scope object to all handlers:
5575         <pre><code>
5576                 el.on({
5577                         'click': this.onClick,
5578                 'mouseover': this.onMouseOver,
5579                 'mouseout': this.onMouseOut,
5580                 scope: this
5581                 });
5582                 </code></pre>
5583      */
5584     addListener : function(eventName, fn, scope, o){
5585         if(typeof eventName == "object"){
5586             o = eventName;
5587             for(var e in o){
5588                 if(this.filterOptRe.test(e)){
5589                     continue;
5590                 }
5591                 if(typeof o[e] == "function"){
5592                     // shared options
5593                     this.addListener(e, o[e], o.scope,  o);
5594                 }else{
5595                     // individual options
5596                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5597                 }
5598             }
5599             return;
5600         }
5601         o = (!o || typeof o == "boolean") ? {} : o;
5602         eventName = eventName.toLowerCase();
5603         var ce = this.events[eventName] || true;
5604         if(typeof ce == "boolean"){
5605             ce = new Roo.util.Event(this, eventName);
5606             this.events[eventName] = ce;
5607         }
5608         ce.addListener(fn, scope, o);
5609     },
5610
5611     /**
5612      * Removes a listener
5613      * @param {String}   eventName     The type of event to listen for
5614      * @param {Function} handler        The handler to remove
5615      * @param {Object}   scope  (optional) The scope (this object) for the handler
5616      */
5617     removeListener : function(eventName, fn, scope){
5618         var ce = this.events[eventName.toLowerCase()];
5619         if(typeof ce == "object"){
5620             ce.removeListener(fn, scope);
5621         }
5622     },
5623
5624     /**
5625      * Removes all listeners for this object
5626      */
5627     purgeListeners : function(){
5628         for(var evt in this.events){
5629             if(typeof this.events[evt] == "object"){
5630                  this.events[evt].clearListeners();
5631             }
5632         }
5633     },
5634
5635     relayEvents : function(o, events){
5636         var createHandler = function(ename){
5637             return function(){
5638                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5639             };
5640         };
5641         for(var i = 0, len = events.length; i < len; i++){
5642             var ename = events[i];
5643             if(!this.events[ename]){ this.events[ename] = true; };
5644             o.on(ename, createHandler(ename), this);
5645         }
5646     },
5647
5648     /**
5649      * Used to define events on this Observable
5650      * @param {Object} object The object with the events defined
5651      */
5652     addEvents : function(o){
5653         if(!this.events){
5654             this.events = {};
5655         }
5656         Roo.applyIf(this.events, o);
5657     },
5658
5659     /**
5660      * Checks to see if this object has any listeners for a specified event
5661      * @param {String} eventName The name of the event to check for
5662      * @return {Boolean} True if the event is being listened for, else false
5663      */
5664     hasListener : function(eventName){
5665         var e = this.events[eventName];
5666         return typeof e == "object" && e.listeners.length > 0;
5667     }
5668 };
5669 /**
5670  * Appends an event handler to this element (shorthand for addListener)
5671  * @param {String}   eventName     The type of event to listen for
5672  * @param {Function} handler        The method the event invokes
5673  * @param {Object}   scope (optional) The scope in which to execute the handler
5674  * function. The handler function's "this" context.
5675  * @param {Object}   options  (optional)
5676  * @method
5677  */
5678 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5679 /**
5680  * Removes a listener (shorthand for removeListener)
5681  * @param {String}   eventName     The type of event to listen for
5682  * @param {Function} handler        The handler to remove
5683  * @param {Object}   scope  (optional) The scope (this object) for the handler
5684  * @method
5685  */
5686 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5687
5688 /**
5689  * Starts capture on the specified Observable. All events will be passed
5690  * to the supplied function with the event name + standard signature of the event
5691  * <b>before</b> the event is fired. If the supplied function returns false,
5692  * the event will not fire.
5693  * @param {Observable} o The Observable to capture
5694  * @param {Function} fn The function to call
5695  * @param {Object} scope (optional) The scope (this object) for the fn
5696  * @static
5697  */
5698 Roo.util.Observable.capture = function(o, fn, scope){
5699     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5700 };
5701
5702 /**
5703  * Removes <b>all</b> added captures from the Observable.
5704  * @param {Observable} o The Observable to release
5705  * @static
5706  */
5707 Roo.util.Observable.releaseCapture = function(o){
5708     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5709 };
5710
5711 (function(){
5712
5713     var createBuffered = function(h, o, scope){
5714         var task = new Roo.util.DelayedTask();
5715         return function(){
5716             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5717         };
5718     };
5719
5720     var createSingle = function(h, e, fn, scope){
5721         return function(){
5722             e.removeListener(fn, scope);
5723             return h.apply(scope, arguments);
5724         };
5725     };
5726
5727     var createDelayed = function(h, o, scope){
5728         return function(){
5729             var args = Array.prototype.slice.call(arguments, 0);
5730             setTimeout(function(){
5731                 h.apply(scope, args);
5732             }, o.delay || 10);
5733         };
5734     };
5735
5736     Roo.util.Event = function(obj, name){
5737         this.name = name;
5738         this.obj = obj;
5739         this.listeners = [];
5740     };
5741
5742     Roo.util.Event.prototype = {
5743         addListener : function(fn, scope, options){
5744             var o = options || {};
5745             scope = scope || this.obj;
5746             if(!this.isListening(fn, scope)){
5747                 var l = {fn: fn, scope: scope, options: o};
5748                 var h = fn;
5749                 if(o.delay){
5750                     h = createDelayed(h, o, scope);
5751                 }
5752                 if(o.single){
5753                     h = createSingle(h, this, fn, scope);
5754                 }
5755                 if(o.buffer){
5756                     h = createBuffered(h, o, scope);
5757                 }
5758                 l.fireFn = h;
5759                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5760                     this.listeners.push(l);
5761                 }else{
5762                     this.listeners = this.listeners.slice(0);
5763                     this.listeners.push(l);
5764                 }
5765             }
5766         },
5767
5768         findListener : function(fn, scope){
5769             scope = scope || this.obj;
5770             var ls = this.listeners;
5771             for(var i = 0, len = ls.length; i < len; i++){
5772                 var l = ls[i];
5773                 if(l.fn == fn && l.scope == scope){
5774                     return i;
5775                 }
5776             }
5777             return -1;
5778         },
5779
5780         isListening : function(fn, scope){
5781             return this.findListener(fn, scope) != -1;
5782         },
5783
5784         removeListener : function(fn, scope){
5785             var index;
5786             if((index = this.findListener(fn, scope)) != -1){
5787                 if(!this.firing){
5788                     this.listeners.splice(index, 1);
5789                 }else{
5790                     this.listeners = this.listeners.slice(0);
5791                     this.listeners.splice(index, 1);
5792                 }
5793                 return true;
5794             }
5795             return false;
5796         },
5797
5798         clearListeners : function(){
5799             this.listeners = [];
5800         },
5801
5802         fire : function(){
5803             var ls = this.listeners, scope, len = ls.length;
5804             if(len > 0){
5805                 this.firing = true;
5806                 var args = Array.prototype.slice.call(arguments, 0);
5807                 for(var i = 0; i < len; i++){
5808                     var l = ls[i];
5809                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5810                         this.firing = false;
5811                         return false;
5812                     }
5813                 }
5814                 this.firing = false;
5815             }
5816             return true;
5817         }
5818     };
5819 })();/*
5820  * Based on:
5821  * Ext JS Library 1.1.1
5822  * Copyright(c) 2006-2007, Ext JS, LLC.
5823  *
5824  * Originally Released Under LGPL - original licence link has changed is not relivant.
5825  *
5826  * Fork - LGPL
5827  * <script type="text/javascript">
5828  */
5829
5830 /**
5831  * @class Roo.EventManager
5832  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5833  * several useful events directly.
5834  * See {@link Roo.EventObject} for more details on normalized event objects.
5835  * @singleton
5836  */
5837 Roo.EventManager = function(){
5838     var docReadyEvent, docReadyProcId, docReadyState = false;
5839     var resizeEvent, resizeTask, textEvent, textSize;
5840     var E = Roo.lib.Event;
5841     var D = Roo.lib.Dom;
5842
5843
5844     var fireDocReady = function(){
5845         if(!docReadyState){
5846             docReadyState = true;
5847             Roo.isReady = true;
5848             if(docReadyProcId){
5849                 clearInterval(docReadyProcId);
5850             }
5851             if(Roo.isGecko || Roo.isOpera) {
5852                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5853             }
5854             if(Roo.isIE){
5855                 var defer = document.getElementById("ie-deferred-loader");
5856                 if(defer){
5857                     defer.onreadystatechange = null;
5858                     defer.parentNode.removeChild(defer);
5859                 }
5860             }
5861             if(docReadyEvent){
5862                 docReadyEvent.fire();
5863                 docReadyEvent.clearListeners();
5864             }
5865         }
5866     };
5867     
5868     var initDocReady = function(){
5869         docReadyEvent = new Roo.util.Event();
5870         if(Roo.isGecko || Roo.isOpera) {
5871             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5872         }else if(Roo.isIE){
5873             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5874             var defer = document.getElementById("ie-deferred-loader");
5875             defer.onreadystatechange = function(){
5876                 if(this.readyState == "complete"){
5877                     fireDocReady();
5878                 }
5879             };
5880         }else if(Roo.isSafari){ 
5881             docReadyProcId = setInterval(function(){
5882                 var rs = document.readyState;
5883                 if(rs == "complete") {
5884                     fireDocReady();     
5885                  }
5886             }, 10);
5887         }
5888         // no matter what, make sure it fires on load
5889         E.on(window, "load", fireDocReady);
5890     };
5891
5892     var createBuffered = function(h, o){
5893         var task = new Roo.util.DelayedTask(h);
5894         return function(e){
5895             // create new event object impl so new events don't wipe out properties
5896             e = new Roo.EventObjectImpl(e);
5897             task.delay(o.buffer, h, null, [e]);
5898         };
5899     };
5900
5901     var createSingle = function(h, el, ename, fn){
5902         return function(e){
5903             Roo.EventManager.removeListener(el, ename, fn);
5904             h(e);
5905         };
5906     };
5907
5908     var createDelayed = function(h, o){
5909         return function(e){
5910             // create new event object impl so new events don't wipe out properties
5911             e = new Roo.EventObjectImpl(e);
5912             setTimeout(function(){
5913                 h(e);
5914             }, o.delay || 10);
5915         };
5916     };
5917
5918     var listen = function(element, ename, opt, fn, scope){
5919         var o = (!opt || typeof opt == "boolean") ? {} : opt;
5920         fn = fn || o.fn; scope = scope || o.scope;
5921         var el = Roo.getDom(element);
5922         if(!el){
5923             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5924         }
5925         var h = function(e){
5926             e = Roo.EventObject.setEvent(e);
5927             var t;
5928             if(o.delegate){
5929                 t = e.getTarget(o.delegate, el);
5930                 if(!t){
5931                     return;
5932                 }
5933             }else{
5934                 t = e.target;
5935             }
5936             if(o.stopEvent === true){
5937                 e.stopEvent();
5938             }
5939             if(o.preventDefault === true){
5940                e.preventDefault();
5941             }
5942             if(o.stopPropagation === true){
5943                 e.stopPropagation();
5944             }
5945
5946             if(o.normalized === false){
5947                 e = e.browserEvent;
5948             }
5949
5950             fn.call(scope || el, e, t, o);
5951         };
5952         if(o.delay){
5953             h = createDelayed(h, o);
5954         }
5955         if(o.single){
5956             h = createSingle(h, el, ename, fn);
5957         }
5958         if(o.buffer){
5959             h = createBuffered(h, o);
5960         }
5961         fn._handlers = fn._handlers || [];
5962         fn._handlers.push([Roo.id(el), ename, h]);
5963
5964         E.on(el, ename, h);
5965         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5966             el.addEventListener("DOMMouseScroll", h, false);
5967             E.on(window, 'unload', function(){
5968                 el.removeEventListener("DOMMouseScroll", h, false);
5969             });
5970         }
5971         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5972             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5973         }
5974         return h;
5975     };
5976
5977     var stopListening = function(el, ename, fn){
5978         var id = Roo.id(el), hds = fn._handlers, hd = fn;
5979         if(hds){
5980             for(var i = 0, len = hds.length; i < len; i++){
5981                 var h = hds[i];
5982                 if(h[0] == id && h[1] == ename){
5983                     hd = h[2];
5984                     hds.splice(i, 1);
5985                     break;
5986                 }
5987             }
5988         }
5989         E.un(el, ename, hd);
5990         el = Roo.getDom(el);
5991         if(ename == "mousewheel" && el.addEventListener){
5992             el.removeEventListener("DOMMouseScroll", hd, false);
5993         }
5994         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5995             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5996         }
5997     };
5998
5999     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6000     
6001     var pub = {
6002         
6003         
6004         /** 
6005          * Fix for doc tools
6006          * @scope Roo.EventManager
6007          */
6008         
6009         
6010         /** 
6011          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6012          * object with a Roo.EventObject
6013          * @param {Function} fn        The method the event invokes
6014          * @param {Object}   scope    An object that becomes the scope of the handler
6015          * @param {boolean}  override If true, the obj passed in becomes
6016          *                             the execution scope of the listener
6017          * @return {Function} The wrapped function
6018          * @deprecated
6019          */
6020         wrap : function(fn, scope, override){
6021             return function(e){
6022                 Roo.EventObject.setEvent(e);
6023                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6024             };
6025         },
6026         
6027         /**
6028      * Appends an event handler to an element (shorthand for addListener)
6029      * @param {String/HTMLElement}   element        The html element or id to assign the
6030      * @param {String}   eventName The type of event to listen for
6031      * @param {Function} handler The method the event invokes
6032      * @param {Object}   scope (optional) The scope in which to execute the handler
6033      * function. The handler function's "this" context.
6034      * @param {Object}   options (optional) An object containing handler configuration
6035      * properties. This may contain any of the following properties:<ul>
6036      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6037      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6038      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6039      * <li>preventDefault {Boolean} True to prevent the default action</li>
6040      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6041      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6042      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6043      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6044      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6045      * by the specified number of milliseconds. If the event fires again within that time, the original
6046      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6047      * </ul><br>
6048      * <p>
6049      * <b>Combining Options</b><br>
6050      * Using the options argument, it is possible to combine different types of listeners:<br>
6051      * <br>
6052      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6053      * Code:<pre><code>
6054 el.on('click', this.onClick, this, {
6055     single: true,
6056     delay: 100,
6057     stopEvent : true,
6058     forumId: 4
6059 });</code></pre>
6060      * <p>
6061      * <b>Attaching multiple handlers in 1 call</b><br>
6062       * The method also allows for a single argument to be passed which is a config object containing properties
6063      * which specify multiple handlers.
6064      * <p>
6065      * Code:<pre><code>
6066 el.on({
6067     'click' : {
6068         fn: this.onClick
6069         scope: this,
6070         delay: 100
6071     },
6072     'mouseover' : {
6073         fn: this.onMouseOver
6074         scope: this
6075     },
6076     'mouseout' : {
6077         fn: this.onMouseOut
6078         scope: this
6079     }
6080 });</code></pre>
6081      * <p>
6082      * Or a shorthand syntax:<br>
6083      * Code:<pre><code>
6084 el.on({
6085     'click' : this.onClick,
6086     'mouseover' : this.onMouseOver,
6087     'mouseout' : this.onMouseOut
6088     scope: this
6089 });</code></pre>
6090      */
6091         addListener : function(element, eventName, fn, scope, options){
6092             if(typeof eventName == "object"){
6093                 var o = eventName;
6094                 for(var e in o){
6095                     if(propRe.test(e)){
6096                         continue;
6097                     }
6098                     if(typeof o[e] == "function"){
6099                         // shared options
6100                         listen(element, e, o, o[e], o.scope);
6101                     }else{
6102                         // individual options
6103                         listen(element, e, o[e]);
6104                     }
6105                 }
6106                 return;
6107             }
6108             return listen(element, eventName, options, fn, scope);
6109         },
6110         
6111         /**
6112          * Removes an event handler
6113          *
6114          * @param {String/HTMLElement}   element        The id or html element to remove the 
6115          *                             event from
6116          * @param {String}   eventName     The type of event
6117          * @param {Function} fn
6118          * @return {Boolean} True if a listener was actually removed
6119          */
6120         removeListener : function(element, eventName, fn){
6121             return stopListening(element, eventName, fn);
6122         },
6123         
6124         /**
6125          * Fires when the document is ready (before onload and before images are loaded). Can be 
6126          * accessed shorthanded Roo.onReady().
6127          * @param {Function} fn        The method the event invokes
6128          * @param {Object}   scope    An  object that becomes the scope of the handler
6129          * @param {boolean}  options
6130          */
6131         onDocumentReady : function(fn, scope, options){
6132             if(docReadyState){ // if it already fired
6133                 docReadyEvent.addListener(fn, scope, options);
6134                 docReadyEvent.fire();
6135                 docReadyEvent.clearListeners();
6136                 return;
6137             }
6138             if(!docReadyEvent){
6139                 initDocReady();
6140             }
6141             docReadyEvent.addListener(fn, scope, options);
6142         },
6143         
6144         /**
6145          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6146          * @param {Function} fn        The method the event invokes
6147          * @param {Object}   scope    An object that becomes the scope of the handler
6148          * @param {boolean}  options
6149          */
6150         onWindowResize : function(fn, scope, options){
6151             if(!resizeEvent){
6152                 resizeEvent = new Roo.util.Event();
6153                 resizeTask = new Roo.util.DelayedTask(function(){
6154                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6155                 });
6156                 E.on(window, "resize", function(){
6157                     if(Roo.isIE){
6158                         resizeTask.delay(50);
6159                     }else{
6160                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6161                     }
6162                 });
6163             }
6164             resizeEvent.addListener(fn, scope, options);
6165         },
6166
6167         /**
6168          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6169          * @param {Function} fn        The method the event invokes
6170          * @param {Object}   scope    An object that becomes the scope of the handler
6171          * @param {boolean}  options
6172          */
6173         onTextResize : function(fn, scope, options){
6174             if(!textEvent){
6175                 textEvent = new Roo.util.Event();
6176                 var textEl = new Roo.Element(document.createElement('div'));
6177                 textEl.dom.className = 'x-text-resize';
6178                 textEl.dom.innerHTML = 'X';
6179                 textEl.appendTo(document.body);
6180                 textSize = textEl.dom.offsetHeight;
6181                 setInterval(function(){
6182                     if(textEl.dom.offsetHeight != textSize){
6183                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6184                     }
6185                 }, this.textResizeInterval);
6186             }
6187             textEvent.addListener(fn, scope, options);
6188         },
6189
6190         /**
6191          * Removes the passed window resize listener.
6192          * @param {Function} fn        The method the event invokes
6193          * @param {Object}   scope    The scope of handler
6194          */
6195         removeResizeListener : function(fn, scope){
6196             if(resizeEvent){
6197                 resizeEvent.removeListener(fn, scope);
6198             }
6199         },
6200
6201         // private
6202         fireResize : function(){
6203             if(resizeEvent){
6204                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6205             }   
6206         },
6207         /**
6208          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6209          */
6210         ieDeferSrc : false,
6211         /**
6212          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6213          */
6214         textResizeInterval : 50
6215     };
6216     
6217     /**
6218      * Fix for doc tools
6219      * @scopeAlias pub=Roo.EventManager
6220      */
6221     
6222      /**
6223      * Appends an event handler to an element (shorthand for addListener)
6224      * @param {String/HTMLElement}   element        The html element or id to assign the
6225      * @param {String}   eventName The type of event to listen for
6226      * @param {Function} handler The method the event invokes
6227      * @param {Object}   scope (optional) The scope in which to execute the handler
6228      * function. The handler function's "this" context.
6229      * @param {Object}   options (optional) An object containing handler configuration
6230      * properties. This may contain any of the following properties:<ul>
6231      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6232      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6233      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6234      * <li>preventDefault {Boolean} True to prevent the default action</li>
6235      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6236      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6237      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6238      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6239      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6240      * by the specified number of milliseconds. If the event fires again within that time, the original
6241      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6242      * </ul><br>
6243      * <p>
6244      * <b>Combining Options</b><br>
6245      * Using the options argument, it is possible to combine different types of listeners:<br>
6246      * <br>
6247      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6248      * Code:<pre><code>
6249 el.on('click', this.onClick, this, {
6250     single: true,
6251     delay: 100,
6252     stopEvent : true,
6253     forumId: 4
6254 });</code></pre>
6255      * <p>
6256      * <b>Attaching multiple handlers in 1 call</b><br>
6257       * The method also allows for a single argument to be passed which is a config object containing properties
6258      * which specify multiple handlers.
6259      * <p>
6260      * Code:<pre><code>
6261 el.on({
6262     'click' : {
6263         fn: this.onClick
6264         scope: this,
6265         delay: 100
6266     },
6267     'mouseover' : {
6268         fn: this.onMouseOver
6269         scope: this
6270     },
6271     'mouseout' : {
6272         fn: this.onMouseOut
6273         scope: this
6274     }
6275 });</code></pre>
6276      * <p>
6277      * Or a shorthand syntax:<br>
6278      * Code:<pre><code>
6279 el.on({
6280     'click' : this.onClick,
6281     'mouseover' : this.onMouseOver,
6282     'mouseout' : this.onMouseOut
6283     scope: this
6284 });</code></pre>
6285      */
6286     pub.on = pub.addListener;
6287     pub.un = pub.removeListener;
6288
6289     pub.stoppedMouseDownEvent = new Roo.util.Event();
6290     return pub;
6291 }();
6292 /**
6293   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6294   * @param {Function} fn        The method the event invokes
6295   * @param {Object}   scope    An  object that becomes the scope of the handler
6296   * @param {boolean}  override If true, the obj passed in becomes
6297   *                             the execution scope of the listener
6298   * @member Roo
6299   * @method onReady
6300  */
6301 Roo.onReady = Roo.EventManager.onDocumentReady;
6302
6303 Roo.onReady(function(){
6304     var bd = Roo.get(document.body);
6305     if(!bd){ return; }
6306
6307     var cls = [
6308             Roo.isIE ? "roo-ie"
6309             : Roo.isGecko ? "roo-gecko"
6310             : Roo.isOpera ? "roo-opera"
6311             : Roo.isSafari ? "roo-safari" : ""];
6312
6313     if(Roo.isMac){
6314         cls.push("roo-mac");
6315     }
6316     if(Roo.isLinux){
6317         cls.push("roo-linux");
6318     }
6319     if(Roo.isBorderBox){
6320         cls.push('roo-border-box');
6321     }
6322     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6323         var p = bd.dom.parentNode;
6324         if(p){
6325             p.className += ' roo-strict';
6326         }
6327     }
6328     bd.addClass(cls.join(' '));
6329 });
6330
6331 /**
6332  * @class Roo.EventObject
6333  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6334  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6335  * Example:
6336  * <pre><code>
6337  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6338     e.preventDefault();
6339     var target = e.getTarget();
6340     ...
6341  }
6342  var myDiv = Roo.get("myDiv");
6343  myDiv.on("click", handleClick);
6344  //or
6345  Roo.EventManager.on("myDiv", 'click', handleClick);
6346  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6347  </code></pre>
6348  * @singleton
6349  */
6350 Roo.EventObject = function(){
6351     
6352     var E = Roo.lib.Event;
6353     
6354     // safari keypress events for special keys return bad keycodes
6355     var safariKeys = {
6356         63234 : 37, // left
6357         63235 : 39, // right
6358         63232 : 38, // up
6359         63233 : 40, // down
6360         63276 : 33, // page up
6361         63277 : 34, // page down
6362         63272 : 46, // delete
6363         63273 : 36, // home
6364         63275 : 35  // end
6365     };
6366
6367     // normalize button clicks
6368     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6369                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6370
6371     Roo.EventObjectImpl = function(e){
6372         if(e){
6373             this.setEvent(e.browserEvent || e);
6374         }
6375     };
6376     Roo.EventObjectImpl.prototype = {
6377         /**
6378          * Used to fix doc tools.
6379          * @scope Roo.EventObject.prototype
6380          */
6381             
6382
6383         
6384         
6385         /** The normal browser event */
6386         browserEvent : null,
6387         /** The button pressed in a mouse event */
6388         button : -1,
6389         /** True if the shift key was down during the event */
6390         shiftKey : false,
6391         /** True if the control key was down during the event */
6392         ctrlKey : false,
6393         /** True if the alt key was down during the event */
6394         altKey : false,
6395
6396         /** Key constant 
6397         * @type Number */
6398         BACKSPACE : 8,
6399         /** Key constant 
6400         * @type Number */
6401         TAB : 9,
6402         /** Key constant 
6403         * @type Number */
6404         RETURN : 13,
6405         /** Key constant 
6406         * @type Number */
6407         ENTER : 13,
6408         /** Key constant 
6409         * @type Number */
6410         SHIFT : 16,
6411         /** Key constant 
6412         * @type Number */
6413         CONTROL : 17,
6414         /** Key constant 
6415         * @type Number */
6416         ESC : 27,
6417         /** Key constant 
6418         * @type Number */
6419         SPACE : 32,
6420         /** Key constant 
6421         * @type Number */
6422         PAGEUP : 33,
6423         /** Key constant 
6424         * @type Number */
6425         PAGEDOWN : 34,
6426         /** Key constant 
6427         * @type Number */
6428         END : 35,
6429         /** Key constant 
6430         * @type Number */
6431         HOME : 36,
6432         /** Key constant 
6433         * @type Number */
6434         LEFT : 37,
6435         /** Key constant 
6436         * @type Number */
6437         UP : 38,
6438         /** Key constant 
6439         * @type Number */
6440         RIGHT : 39,
6441         /** Key constant 
6442         * @type Number */
6443         DOWN : 40,
6444         /** Key constant 
6445         * @type Number */
6446         DELETE : 46,
6447         /** Key constant 
6448         * @type Number */
6449         F5 : 116,
6450
6451            /** @private */
6452         setEvent : function(e){
6453             if(e == this || (e && e.browserEvent)){ // already wrapped
6454                 return e;
6455             }
6456             this.browserEvent = e;
6457             if(e){
6458                 // normalize buttons
6459                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6460                 if(e.type == 'click' && this.button == -1){
6461                     this.button = 0;
6462                 }
6463                 this.type = e.type;
6464                 this.shiftKey = e.shiftKey;
6465                 // mac metaKey behaves like ctrlKey
6466                 this.ctrlKey = e.ctrlKey || e.metaKey;
6467                 this.altKey = e.altKey;
6468                 // in getKey these will be normalized for the mac
6469                 this.keyCode = e.keyCode;
6470                 // keyup warnings on firefox.
6471                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6472                 // cache the target for the delayed and or buffered events
6473                 this.target = E.getTarget(e);
6474                 // same for XY
6475                 this.xy = E.getXY(e);
6476             }else{
6477                 this.button = -1;
6478                 this.shiftKey = false;
6479                 this.ctrlKey = false;
6480                 this.altKey = false;
6481                 this.keyCode = 0;
6482                 this.charCode =0;
6483                 this.target = null;
6484                 this.xy = [0, 0];
6485             }
6486             return this;
6487         },
6488
6489         /**
6490          * Stop the event (preventDefault and stopPropagation)
6491          */
6492         stopEvent : function(){
6493             if(this.browserEvent){
6494                 if(this.browserEvent.type == 'mousedown'){
6495                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6496                 }
6497                 E.stopEvent(this.browserEvent);
6498             }
6499         },
6500
6501         /**
6502          * Prevents the browsers default handling of the event.
6503          */
6504         preventDefault : function(){
6505             if(this.browserEvent){
6506                 E.preventDefault(this.browserEvent);
6507             }
6508         },
6509
6510         /** @private */
6511         isNavKeyPress : function(){
6512             var k = this.keyCode;
6513             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6514             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6515         },
6516
6517         isSpecialKey : function(){
6518             var k = this.keyCode;
6519             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6520             (k == 16) || (k == 17) ||
6521             (k >= 18 && k <= 20) ||
6522             (k >= 33 && k <= 35) ||
6523             (k >= 36 && k <= 39) ||
6524             (k >= 44 && k <= 45);
6525         },
6526         /**
6527          * Cancels bubbling of the event.
6528          */
6529         stopPropagation : function(){
6530             if(this.browserEvent){
6531                 if(this.type == 'mousedown'){
6532                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6533                 }
6534                 E.stopPropagation(this.browserEvent);
6535             }
6536         },
6537
6538         /**
6539          * Gets the key code for the event.
6540          * @return {Number}
6541          */
6542         getCharCode : function(){
6543             return this.charCode || this.keyCode;
6544         },
6545
6546         /**
6547          * Returns a normalized keyCode for the event.
6548          * @return {Number} The key code
6549          */
6550         getKey : function(){
6551             var k = this.keyCode || this.charCode;
6552             return Roo.isSafari ? (safariKeys[k] || k) : k;
6553         },
6554
6555         /**
6556          * Gets the x coordinate of the event.
6557          * @return {Number}
6558          */
6559         getPageX : function(){
6560             return this.xy[0];
6561         },
6562
6563         /**
6564          * Gets the y coordinate of the event.
6565          * @return {Number}
6566          */
6567         getPageY : function(){
6568             return this.xy[1];
6569         },
6570
6571         /**
6572          * Gets the time of the event.
6573          * @return {Number}
6574          */
6575         getTime : function(){
6576             if(this.browserEvent){
6577                 return E.getTime(this.browserEvent);
6578             }
6579             return null;
6580         },
6581
6582         /**
6583          * Gets the page coordinates of the event.
6584          * @return {Array} The xy values like [x, y]
6585          */
6586         getXY : function(){
6587             return this.xy;
6588         },
6589
6590         /**
6591          * Gets the target for the event.
6592          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6593          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6594                 search as a number or element (defaults to 10 || document.body)
6595          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6596          * @return {HTMLelement}
6597          */
6598         getTarget : function(selector, maxDepth, returnEl){
6599             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6600         },
6601         /**
6602          * Gets the related target.
6603          * @return {HTMLElement}
6604          */
6605         getRelatedTarget : function(){
6606             if(this.browserEvent){
6607                 return E.getRelatedTarget(this.browserEvent);
6608             }
6609             return null;
6610         },
6611
6612         /**
6613          * Normalizes mouse wheel delta across browsers
6614          * @return {Number} The delta
6615          */
6616         getWheelDelta : function(){
6617             var e = this.browserEvent;
6618             var delta = 0;
6619             if(e.wheelDelta){ /* IE/Opera. */
6620                 delta = e.wheelDelta/120;
6621             }else if(e.detail){ /* Mozilla case. */
6622                 delta = -e.detail/3;
6623             }
6624             return delta;
6625         },
6626
6627         /**
6628          * Returns true if the control, meta, shift or alt key was pressed during this event.
6629          * @return {Boolean}
6630          */
6631         hasModifier : function(){
6632             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6633         },
6634
6635         /**
6636          * Returns true if the target of this event equals el or is a child of el
6637          * @param {String/HTMLElement/Element} el
6638          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6639          * @return {Boolean}
6640          */
6641         within : function(el, related){
6642             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6643             return t && Roo.fly(el).contains(t);
6644         },
6645
6646         getPoint : function(){
6647             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6648         }
6649     };
6650
6651     return new Roo.EventObjectImpl();
6652 }();
6653             
6654     /*
6655  * Based on:
6656  * Ext JS Library 1.1.1
6657  * Copyright(c) 2006-2007, Ext JS, LLC.
6658  *
6659  * Originally Released Under LGPL - original licence link has changed is not relivant.
6660  *
6661  * Fork - LGPL
6662  * <script type="text/javascript">
6663  */
6664
6665  
6666 // was in Composite Element!??!?!
6667  
6668 (function(){
6669     var D = Roo.lib.Dom;
6670     var E = Roo.lib.Event;
6671     var A = Roo.lib.Anim;
6672
6673     // local style camelizing for speed
6674     var propCache = {};
6675     var camelRe = /(-[a-z])/gi;
6676     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6677     var view = document.defaultView;
6678
6679 /**
6680  * @class Roo.Element
6681  * Represents an Element in the DOM.<br><br>
6682  * Usage:<br>
6683 <pre><code>
6684 var el = Roo.get("my-div");
6685
6686 // or with getEl
6687 var el = getEl("my-div");
6688
6689 // or with a DOM element
6690 var el = Roo.get(myDivElement);
6691 </code></pre>
6692  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6693  * each call instead of constructing a new one.<br><br>
6694  * <b>Animations</b><br />
6695  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6696  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6697 <pre>
6698 Option    Default   Description
6699 --------- --------  ---------------------------------------------
6700 duration  .35       The duration of the animation in seconds
6701 easing    easeOut   The YUI easing method
6702 callback  none      A function to execute when the anim completes
6703 scope     this      The scope (this) of the callback function
6704 </pre>
6705 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6706 * manipulate the animation. Here's an example:
6707 <pre><code>
6708 var el = Roo.get("my-div");
6709
6710 // no animation
6711 el.setWidth(100);
6712
6713 // default animation
6714 el.setWidth(100, true);
6715
6716 // animation with some options set
6717 el.setWidth(100, {
6718     duration: 1,
6719     callback: this.foo,
6720     scope: this
6721 });
6722
6723 // using the "anim" property to get the Anim object
6724 var opt = {
6725     duration: 1,
6726     callback: this.foo,
6727     scope: this
6728 };
6729 el.setWidth(100, opt);
6730 ...
6731 if(opt.anim.isAnimated()){
6732     opt.anim.stop();
6733 }
6734 </code></pre>
6735 * <b> Composite (Collections of) Elements</b><br />
6736  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6737  * @constructor Create a new Element directly.
6738  * @param {String/HTMLElement} element
6739  * @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).
6740  */
6741     Roo.Element = function(element, forceNew){
6742         var dom = typeof element == "string" ?
6743                 document.getElementById(element) : element;
6744         if(!dom){ // invalid id/element
6745             return null;
6746         }
6747         var id = dom.id;
6748         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6749             return Roo.Element.cache[id];
6750         }
6751
6752         /**
6753          * The DOM element
6754          * @type HTMLElement
6755          */
6756         this.dom = dom;
6757
6758         /**
6759          * The DOM element ID
6760          * @type String
6761          */
6762         this.id = id || Roo.id(dom);
6763     };
6764
6765     var El = Roo.Element;
6766
6767     El.prototype = {
6768         /**
6769          * The element's default display mode  (defaults to "")
6770          * @type String
6771          */
6772         originalDisplay : "",
6773
6774         visibilityMode : 1,
6775         /**
6776          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6777          * @type String
6778          */
6779         defaultUnit : "px",
6780         /**
6781          * Sets the element's visibility mode. When setVisible() is called it
6782          * will use this to determine whether to set the visibility or the display property.
6783          * @param visMode Element.VISIBILITY or Element.DISPLAY
6784          * @return {Roo.Element} this
6785          */
6786         setVisibilityMode : function(visMode){
6787             this.visibilityMode = visMode;
6788             return this;
6789         },
6790         /**
6791          * Convenience method for setVisibilityMode(Element.DISPLAY)
6792          * @param {String} display (optional) What to set display to when visible
6793          * @return {Roo.Element} this
6794          */
6795         enableDisplayMode : function(display){
6796             this.setVisibilityMode(El.DISPLAY);
6797             if(typeof display != "undefined") this.originalDisplay = display;
6798             return this;
6799         },
6800
6801         /**
6802          * 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)
6803          * @param {String} selector The simple selector to test
6804          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6805                 search as a number or element (defaults to 10 || document.body)
6806          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6807          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6808          */
6809         findParent : function(simpleSelector, maxDepth, returnEl){
6810             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6811             maxDepth = maxDepth || 50;
6812             if(typeof maxDepth != "number"){
6813                 stopEl = Roo.getDom(maxDepth);
6814                 maxDepth = 10;
6815             }
6816             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6817                 if(dq.is(p, simpleSelector)){
6818                     return returnEl ? Roo.get(p) : p;
6819                 }
6820                 depth++;
6821                 p = p.parentNode;
6822             }
6823             return null;
6824         },
6825
6826
6827         /**
6828          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6829          * @param {String} selector The simple selector to test
6830          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6831                 search as a number or element (defaults to 10 || document.body)
6832          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6833          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6834          */
6835         findParentNode : function(simpleSelector, maxDepth, returnEl){
6836             var p = Roo.fly(this.dom.parentNode, '_internal');
6837             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6838         },
6839
6840         /**
6841          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6842          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6843          * @param {String} selector The simple selector to test
6844          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6845                 search as a number or element (defaults to 10 || document.body)
6846          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6847          */
6848         up : function(simpleSelector, maxDepth){
6849             return this.findParentNode(simpleSelector, maxDepth, true);
6850         },
6851
6852
6853
6854         /**
6855          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6856          * @param {String} selector The simple selector to test
6857          * @return {Boolean} True if this element matches the selector, else false
6858          */
6859         is : function(simpleSelector){
6860             return Roo.DomQuery.is(this.dom, simpleSelector);
6861         },
6862
6863         /**
6864          * Perform animation on this element.
6865          * @param {Object} args The YUI animation control args
6866          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6867          * @param {Function} onComplete (optional) Function to call when animation completes
6868          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6869          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6870          * @return {Roo.Element} this
6871          */
6872         animate : function(args, duration, onComplete, easing, animType){
6873             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6874             return this;
6875         },
6876
6877         /*
6878          * @private Internal animation call
6879          */
6880         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6881             animType = animType || 'run';
6882             opt = opt || {};
6883             var anim = Roo.lib.Anim[animType](
6884                 this.dom, args,
6885                 (opt.duration || defaultDur) || .35,
6886                 (opt.easing || defaultEase) || 'easeOut',
6887                 function(){
6888                     Roo.callback(cb, this);
6889                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6890                 },
6891                 this
6892             );
6893             opt.anim = anim;
6894             return anim;
6895         },
6896
6897         // private legacy anim prep
6898         preanim : function(a, i){
6899             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6900         },
6901
6902         /**
6903          * Removes worthless text nodes
6904          * @param {Boolean} forceReclean (optional) By default the element
6905          * keeps track if it has been cleaned already so
6906          * you can call this over and over. However, if you update the element and
6907          * need to force a reclean, you can pass true.
6908          */
6909         clean : function(forceReclean){
6910             if(this.isCleaned && forceReclean !== true){
6911                 return this;
6912             }
6913             var ns = /\S/;
6914             var d = this.dom, n = d.firstChild, ni = -1;
6915             while(n){
6916                 var nx = n.nextSibling;
6917                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6918                     d.removeChild(n);
6919                 }else{
6920                     n.nodeIndex = ++ni;
6921                 }
6922                 n = nx;
6923             }
6924             this.isCleaned = true;
6925             return this;
6926         },
6927
6928         // private
6929         calcOffsetsTo : function(el){
6930             el = Roo.get(el);
6931             var d = el.dom;
6932             var restorePos = false;
6933             if(el.getStyle('position') == 'static'){
6934                 el.position('relative');
6935                 restorePos = true;
6936             }
6937             var x = 0, y =0;
6938             var op = this.dom;
6939             while(op && op != d && op.tagName != 'HTML'){
6940                 x+= op.offsetLeft;
6941                 y+= op.offsetTop;
6942                 op = op.offsetParent;
6943             }
6944             if(restorePos){
6945                 el.position('static');
6946             }
6947             return [x, y];
6948         },
6949
6950         /**
6951          * Scrolls this element into view within the passed container.
6952          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6953          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6954          * @return {Roo.Element} this
6955          */
6956         scrollIntoView : function(container, hscroll){
6957             var c = Roo.getDom(container) || document.body;
6958             var el = this.dom;
6959
6960             var o = this.calcOffsetsTo(c),
6961                 l = o[0],
6962                 t = o[1],
6963                 b = t+el.offsetHeight,
6964                 r = l+el.offsetWidth;
6965
6966             var ch = c.clientHeight;
6967             var ct = parseInt(c.scrollTop, 10);
6968             var cl = parseInt(c.scrollLeft, 10);
6969             var cb = ct + ch;
6970             var cr = cl + c.clientWidth;
6971
6972             if(t < ct){
6973                 c.scrollTop = t;
6974             }else if(b > cb){
6975                 c.scrollTop = b-ch;
6976             }
6977
6978             if(hscroll !== false){
6979                 if(l < cl){
6980                     c.scrollLeft = l;
6981                 }else if(r > cr){
6982                     c.scrollLeft = r-c.clientWidth;
6983                 }
6984             }
6985             return this;
6986         },
6987
6988         // private
6989         scrollChildIntoView : function(child, hscroll){
6990             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6991         },
6992
6993         /**
6994          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6995          * the new height may not be available immediately.
6996          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6997          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6998          * @param {Function} onComplete (optional) Function to call when animation completes
6999          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7000          * @return {Roo.Element} this
7001          */
7002         autoHeight : function(animate, duration, onComplete, easing){
7003             var oldHeight = this.getHeight();
7004             this.clip();
7005             this.setHeight(1); // force clipping
7006             setTimeout(function(){
7007                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7008                 if(!animate){
7009                     this.setHeight(height);
7010                     this.unclip();
7011                     if(typeof onComplete == "function"){
7012                         onComplete();
7013                     }
7014                 }else{
7015                     this.setHeight(oldHeight); // restore original height
7016                     this.setHeight(height, animate, duration, function(){
7017                         this.unclip();
7018                         if(typeof onComplete == "function") onComplete();
7019                     }.createDelegate(this), easing);
7020                 }
7021             }.createDelegate(this), 0);
7022             return this;
7023         },
7024
7025         /**
7026          * Returns true if this element is an ancestor of the passed element
7027          * @param {HTMLElement/String} el The element to check
7028          * @return {Boolean} True if this element is an ancestor of el, else false
7029          */
7030         contains : function(el){
7031             if(!el){return false;}
7032             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7033         },
7034
7035         /**
7036          * Checks whether the element is currently visible using both visibility and display properties.
7037          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7038          * @return {Boolean} True if the element is currently visible, else false
7039          */
7040         isVisible : function(deep) {
7041             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7042             if(deep !== true || !vis){
7043                 return vis;
7044             }
7045             var p = this.dom.parentNode;
7046             while(p && p.tagName.toLowerCase() != "body"){
7047                 if(!Roo.fly(p, '_isVisible').isVisible()){
7048                     return false;
7049                 }
7050                 p = p.parentNode;
7051             }
7052             return true;
7053         },
7054
7055         /**
7056          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7057          * @param {String} selector The CSS selector
7058          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7059          * @return {CompositeElement/CompositeElementLite} The composite element
7060          */
7061         select : function(selector, unique){
7062             return El.select(selector, unique, this.dom);
7063         },
7064
7065         /**
7066          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7067          * @param {String} selector The CSS selector
7068          * @return {Array} An array of the matched nodes
7069          */
7070         query : function(selector, unique){
7071             return Roo.DomQuery.select(selector, this.dom);
7072         },
7073
7074         /**
7075          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7076          * @param {String} selector The CSS selector
7077          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7078          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7079          */
7080         child : function(selector, returnDom){
7081             var n = Roo.DomQuery.selectNode(selector, this.dom);
7082             return returnDom ? n : Roo.get(n);
7083         },
7084
7085         /**
7086          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7087          * @param {String} selector The CSS selector
7088          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7089          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7090          */
7091         down : function(selector, returnDom){
7092             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7093             return returnDom ? n : Roo.get(n);
7094         },
7095
7096         /**
7097          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7098          * @param {String} group The group the DD object is member of
7099          * @param {Object} config The DD config object
7100          * @param {Object} overrides An object containing methods to override/implement on the DD object
7101          * @return {Roo.dd.DD} The DD object
7102          */
7103         initDD : function(group, config, overrides){
7104             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7105             return Roo.apply(dd, overrides);
7106         },
7107
7108         /**
7109          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7110          * @param {String} group The group the DDProxy object is member of
7111          * @param {Object} config The DDProxy config object
7112          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7113          * @return {Roo.dd.DDProxy} The DDProxy object
7114          */
7115         initDDProxy : function(group, config, overrides){
7116             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7117             return Roo.apply(dd, overrides);
7118         },
7119
7120         /**
7121          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7122          * @param {String} group The group the DDTarget object is member of
7123          * @param {Object} config The DDTarget config object
7124          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7125          * @return {Roo.dd.DDTarget} The DDTarget object
7126          */
7127         initDDTarget : function(group, config, overrides){
7128             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7129             return Roo.apply(dd, overrides);
7130         },
7131
7132         /**
7133          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7134          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7135          * @param {Boolean} visible Whether the element is visible
7136          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7137          * @return {Roo.Element} this
7138          */
7139          setVisible : function(visible, animate){
7140             if(!animate || !A){
7141                 if(this.visibilityMode == El.DISPLAY){
7142                     this.setDisplayed(visible);
7143                 }else{
7144                     this.fixDisplay();
7145                     this.dom.style.visibility = visible ? "visible" : "hidden";
7146                 }
7147             }else{
7148                 // closure for composites
7149                 var dom = this.dom;
7150                 var visMode = this.visibilityMode;
7151                 if(visible){
7152                     this.setOpacity(.01);
7153                     this.setVisible(true);
7154                 }
7155                 this.anim({opacity: { to: (visible?1:0) }},
7156                       this.preanim(arguments, 1),
7157                       null, .35, 'easeIn', function(){
7158                          if(!visible){
7159                              if(visMode == El.DISPLAY){
7160                                  dom.style.display = "none";
7161                              }else{
7162                                  dom.style.visibility = "hidden";
7163                              }
7164                              Roo.get(dom).setOpacity(1);
7165                          }
7166                      });
7167             }
7168             return this;
7169         },
7170
7171         /**
7172          * Returns true if display is not "none"
7173          * @return {Boolean}
7174          */
7175         isDisplayed : function() {
7176             return this.getStyle("display") != "none";
7177         },
7178
7179         /**
7180          * Toggles the element's visibility or display, depending on visibility mode.
7181          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7182          * @return {Roo.Element} this
7183          */
7184         toggle : function(animate){
7185             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7186             return this;
7187         },
7188
7189         /**
7190          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7191          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7192          * @return {Roo.Element} this
7193          */
7194         setDisplayed : function(value) {
7195             if(typeof value == "boolean"){
7196                value = value ? this.originalDisplay : "none";
7197             }
7198             this.setStyle("display", value);
7199             return this;
7200         },
7201
7202         /**
7203          * Tries to focus the element. Any exceptions are caught and ignored.
7204          * @return {Roo.Element} this
7205          */
7206         focus : function() {
7207             try{
7208                 this.dom.focus();
7209             }catch(e){}
7210             return this;
7211         },
7212
7213         /**
7214          * Tries to blur the element. Any exceptions are caught and ignored.
7215          * @return {Roo.Element} this
7216          */
7217         blur : function() {
7218             try{
7219                 this.dom.blur();
7220             }catch(e){}
7221             return this;
7222         },
7223
7224         /**
7225          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7226          * @param {String/Array} className The CSS class to add, or an array of classes
7227          * @return {Roo.Element} this
7228          */
7229         addClass : function(className){
7230             if(className instanceof Array){
7231                 for(var i = 0, len = className.length; i < len; i++) {
7232                     this.addClass(className[i]);
7233                 }
7234             }else{
7235                 if(className && !this.hasClass(className)){
7236                     this.dom.className = this.dom.className + " " + className;
7237                 }
7238             }
7239             return this;
7240         },
7241
7242         /**
7243          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7244          * @param {String/Array} className The CSS class to add, or an array of classes
7245          * @return {Roo.Element} this
7246          */
7247         radioClass : function(className){
7248             var siblings = this.dom.parentNode.childNodes;
7249             for(var i = 0; i < siblings.length; i++) {
7250                 var s = siblings[i];
7251                 if(s.nodeType == 1){
7252                     Roo.get(s).removeClass(className);
7253                 }
7254             }
7255             this.addClass(className);
7256             return this;
7257         },
7258
7259         /**
7260          * Removes one or more CSS classes from the element.
7261          * @param {String/Array} className The CSS class to remove, or an array of classes
7262          * @return {Roo.Element} this
7263          */
7264         removeClass : function(className){
7265             if(!className || !this.dom.className){
7266                 return this;
7267             }
7268             if(className instanceof Array){
7269                 for(var i = 0, len = className.length; i < len; i++) {
7270                     this.removeClass(className[i]);
7271                 }
7272             }else{
7273                 if(this.hasClass(className)){
7274                     var re = this.classReCache[className];
7275                     if (!re) {
7276                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7277                        this.classReCache[className] = re;
7278                     }
7279                     this.dom.className =
7280                         this.dom.className.replace(re, " ");
7281                 }
7282             }
7283             return this;
7284         },
7285
7286         // private
7287         classReCache: {},
7288
7289         /**
7290          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7291          * @param {String} className The CSS class to toggle
7292          * @return {Roo.Element} this
7293          */
7294         toggleClass : function(className){
7295             if(this.hasClass(className)){
7296                 this.removeClass(className);
7297             }else{
7298                 this.addClass(className);
7299             }
7300             return this;
7301         },
7302
7303         /**
7304          * Checks if the specified CSS class exists on this element's DOM node.
7305          * @param {String} className The CSS class to check for
7306          * @return {Boolean} True if the class exists, else false
7307          */
7308         hasClass : function(className){
7309             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7310         },
7311
7312         /**
7313          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7314          * @param {String} oldClassName The CSS class to replace
7315          * @param {String} newClassName The replacement CSS class
7316          * @return {Roo.Element} this
7317          */
7318         replaceClass : function(oldClassName, newClassName){
7319             this.removeClass(oldClassName);
7320             this.addClass(newClassName);
7321             return this;
7322         },
7323
7324         /**
7325          * Returns an object with properties matching the styles requested.
7326          * For example, el.getStyles('color', 'font-size', 'width') might return
7327          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7328          * @param {String} style1 A style name
7329          * @param {String} style2 A style name
7330          * @param {String} etc.
7331          * @return {Object} The style object
7332          */
7333         getStyles : function(){
7334             var a = arguments, len = a.length, r = {};
7335             for(var i = 0; i < len; i++){
7336                 r[a[i]] = this.getStyle(a[i]);
7337             }
7338             return r;
7339         },
7340
7341         /**
7342          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7343          * @param {String} property The style property whose value is returned.
7344          * @return {String} The current value of the style property for this element.
7345          */
7346         getStyle : function(){
7347             return view && view.getComputedStyle ?
7348                 function(prop){
7349                     var el = this.dom, v, cs, camel;
7350                     if(prop == 'float'){
7351                         prop = "cssFloat";
7352                     }
7353                     if(el.style && (v = el.style[prop])){
7354                         return v;
7355                     }
7356                     if(cs = view.getComputedStyle(el, "")){
7357                         if(!(camel = propCache[prop])){
7358                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7359                         }
7360                         return cs[camel];
7361                     }
7362                     return null;
7363                 } :
7364                 function(prop){
7365                     var el = this.dom, v, cs, camel;
7366                     if(prop == 'opacity'){
7367                         if(typeof el.style.filter == 'string'){
7368                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7369                             if(m){
7370                                 var fv = parseFloat(m[1]);
7371                                 if(!isNaN(fv)){
7372                                     return fv ? fv / 100 : 0;
7373                                 }
7374                             }
7375                         }
7376                         return 1;
7377                     }else if(prop == 'float'){
7378                         prop = "styleFloat";
7379                     }
7380                     if(!(camel = propCache[prop])){
7381                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7382                     }
7383                     if(v = el.style[camel]){
7384                         return v;
7385                     }
7386                     if(cs = el.currentStyle){
7387                         return cs[camel];
7388                     }
7389                     return null;
7390                 };
7391         }(),
7392
7393         /**
7394          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7395          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7396          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7397          * @return {Roo.Element} this
7398          */
7399         setStyle : function(prop, value){
7400             if(typeof prop == "string"){
7401                 
7402                 if (prop == 'float') {
7403                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7404                     return this;
7405                 }
7406                 
7407                 var camel;
7408                 if(!(camel = propCache[prop])){
7409                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7410                 }
7411                 
7412                 if(camel == 'opacity') {
7413                     this.setOpacity(value);
7414                 }else{
7415                     this.dom.style[camel] = value;
7416                 }
7417             }else{
7418                 for(var style in prop){
7419                     if(typeof prop[style] != "function"){
7420                        this.setStyle(style, prop[style]);
7421                     }
7422                 }
7423             }
7424             return this;
7425         },
7426
7427         /**
7428          * More flexible version of {@link #setStyle} for setting style properties.
7429          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7430          * a function which returns such a specification.
7431          * @return {Roo.Element} this
7432          */
7433         applyStyles : function(style){
7434             Roo.DomHelper.applyStyles(this.dom, style);
7435             return this;
7436         },
7437
7438         /**
7439           * 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).
7440           * @return {Number} The X position of the element
7441           */
7442         getX : function(){
7443             return D.getX(this.dom);
7444         },
7445
7446         /**
7447           * 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).
7448           * @return {Number} The Y position of the element
7449           */
7450         getY : function(){
7451             return D.getY(this.dom);
7452         },
7453
7454         /**
7455           * 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).
7456           * @return {Array} The XY position of the element
7457           */
7458         getXY : function(){
7459             return D.getXY(this.dom);
7460         },
7461
7462         /**
7463          * 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).
7464          * @param {Number} The X position of the element
7465          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7466          * @return {Roo.Element} this
7467          */
7468         setX : function(x, animate){
7469             if(!animate || !A){
7470                 D.setX(this.dom, x);
7471             }else{
7472                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7473             }
7474             return this;
7475         },
7476
7477         /**
7478          * 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).
7479          * @param {Number} The Y position of the element
7480          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7481          * @return {Roo.Element} this
7482          */
7483         setY : function(y, animate){
7484             if(!animate || !A){
7485                 D.setY(this.dom, y);
7486             }else{
7487                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7488             }
7489             return this;
7490         },
7491
7492         /**
7493          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7494          * @param {String} left The left CSS property value
7495          * @return {Roo.Element} this
7496          */
7497         setLeft : function(left){
7498             this.setStyle("left", this.addUnits(left));
7499             return this;
7500         },
7501
7502         /**
7503          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7504          * @param {String} top The top CSS property value
7505          * @return {Roo.Element} this
7506          */
7507         setTop : function(top){
7508             this.setStyle("top", this.addUnits(top));
7509             return this;
7510         },
7511
7512         /**
7513          * Sets the element's CSS right style.
7514          * @param {String} right The right CSS property value
7515          * @return {Roo.Element} this
7516          */
7517         setRight : function(right){
7518             this.setStyle("right", this.addUnits(right));
7519             return this;
7520         },
7521
7522         /**
7523          * Sets the element's CSS bottom style.
7524          * @param {String} bottom The bottom CSS property value
7525          * @return {Roo.Element} this
7526          */
7527         setBottom : function(bottom){
7528             this.setStyle("bottom", this.addUnits(bottom));
7529             return this;
7530         },
7531
7532         /**
7533          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7534          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7535          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7536          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7537          * @return {Roo.Element} this
7538          */
7539         setXY : function(pos, animate){
7540             if(!animate || !A){
7541                 D.setXY(this.dom, pos);
7542             }else{
7543                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7544             }
7545             return this;
7546         },
7547
7548         /**
7549          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7550          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7551          * @param {Number} x X value for new position (coordinates are page-based)
7552          * @param {Number} y Y value for new position (coordinates are page-based)
7553          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7554          * @return {Roo.Element} this
7555          */
7556         setLocation : function(x, y, animate){
7557             this.setXY([x, y], this.preanim(arguments, 2));
7558             return this;
7559         },
7560
7561         /**
7562          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7563          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7564          * @param {Number} x X value for new position (coordinates are page-based)
7565          * @param {Number} y Y value for new position (coordinates are page-based)
7566          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7567          * @return {Roo.Element} this
7568          */
7569         moveTo : function(x, y, animate){
7570             this.setXY([x, y], this.preanim(arguments, 2));
7571             return this;
7572         },
7573
7574         /**
7575          * Returns the region of the given element.
7576          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7577          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7578          */
7579         getRegion : function(){
7580             return D.getRegion(this.dom);
7581         },
7582
7583         /**
7584          * Returns the offset height of the element
7585          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7586          * @return {Number} The element's height
7587          */
7588         getHeight : function(contentHeight){
7589             var h = this.dom.offsetHeight || 0;
7590             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7591         },
7592
7593         /**
7594          * Returns the offset width of the element
7595          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7596          * @return {Number} The element's width
7597          */
7598         getWidth : function(contentWidth){
7599             var w = this.dom.offsetWidth || 0;
7600             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7601         },
7602
7603         /**
7604          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7605          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7606          * if a height has not been set using CSS.
7607          * @return {Number}
7608          */
7609         getComputedHeight : function(){
7610             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7611             if(!h){
7612                 h = parseInt(this.getStyle('height'), 10) || 0;
7613                 if(!this.isBorderBox()){
7614                     h += this.getFrameWidth('tb');
7615                 }
7616             }
7617             return h;
7618         },
7619
7620         /**
7621          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7622          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7623          * if a width has not been set using CSS.
7624          * @return {Number}
7625          */
7626         getComputedWidth : function(){
7627             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7628             if(!w){
7629                 w = parseInt(this.getStyle('width'), 10) || 0;
7630                 if(!this.isBorderBox()){
7631                     w += this.getFrameWidth('lr');
7632                 }
7633             }
7634             return w;
7635         },
7636
7637         /**
7638          * Returns the size of the element.
7639          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7640          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7641          */
7642         getSize : function(contentSize){
7643             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7644         },
7645
7646         /**
7647          * Returns the width and height of the viewport.
7648          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7649          */
7650         getViewSize : function(){
7651             var d = this.dom, doc = document, aw = 0, ah = 0;
7652             if(d == doc || d == doc.body){
7653                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7654             }else{
7655                 return {
7656                     width : d.clientWidth,
7657                     height: d.clientHeight
7658                 };
7659             }
7660         },
7661
7662         /**
7663          * Returns the value of the "value" attribute
7664          * @param {Boolean} asNumber true to parse the value as a number
7665          * @return {String/Number}
7666          */
7667         getValue : function(asNumber){
7668             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7669         },
7670
7671         // private
7672         adjustWidth : function(width){
7673             if(typeof width == "number"){
7674                 if(this.autoBoxAdjust && !this.isBorderBox()){
7675                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7676                 }
7677                 if(width < 0){
7678                     width = 0;
7679                 }
7680             }
7681             return width;
7682         },
7683
7684         // private
7685         adjustHeight : function(height){
7686             if(typeof height == "number"){
7687                if(this.autoBoxAdjust && !this.isBorderBox()){
7688                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7689                }
7690                if(height < 0){
7691                    height = 0;
7692                }
7693             }
7694             return height;
7695         },
7696
7697         /**
7698          * Set the width of the element
7699          * @param {Number} width The new width
7700          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7701          * @return {Roo.Element} this
7702          */
7703         setWidth : function(width, animate){
7704             width = this.adjustWidth(width);
7705             if(!animate || !A){
7706                 this.dom.style.width = this.addUnits(width);
7707             }else{
7708                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7709             }
7710             return this;
7711         },
7712
7713         /**
7714          * Set the height of the element
7715          * @param {Number} height The new height
7716          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7717          * @return {Roo.Element} this
7718          */
7719          setHeight : function(height, animate){
7720             height = this.adjustHeight(height);
7721             if(!animate || !A){
7722                 this.dom.style.height = this.addUnits(height);
7723             }else{
7724                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7725             }
7726             return this;
7727         },
7728
7729         /**
7730          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7731          * @param {Number} width The new width
7732          * @param {Number} height The new height
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          setSize : function(width, height, animate){
7737             if(typeof width == "object"){ // in case of object from getSize()
7738                 height = width.height; width = width.width;
7739             }
7740             width = this.adjustWidth(width); height = this.adjustHeight(height);
7741             if(!animate || !A){
7742                 this.dom.style.width = this.addUnits(width);
7743                 this.dom.style.height = this.addUnits(height);
7744             }else{
7745                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7746             }
7747             return this;
7748         },
7749
7750         /**
7751          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7752          * @param {Number} x X value for new position (coordinates are page-based)
7753          * @param {Number} y Y value for new position (coordinates are page-based)
7754          * @param {Number} width The new width
7755          * @param {Number} height The new height
7756          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7757          * @return {Roo.Element} this
7758          */
7759         setBounds : function(x, y, width, height, animate){
7760             if(!animate || !A){
7761                 this.setSize(width, height);
7762                 this.setLocation(x, y);
7763             }else{
7764                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7765                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7766                               this.preanim(arguments, 4), 'motion');
7767             }
7768             return this;
7769         },
7770
7771         /**
7772          * 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.
7773          * @param {Roo.lib.Region} region The region to fill
7774          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7775          * @return {Roo.Element} this
7776          */
7777         setRegion : function(region, animate){
7778             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7779             return this;
7780         },
7781
7782         /**
7783          * Appends an event handler
7784          *
7785          * @param {String}   eventName     The type of event to append
7786          * @param {Function} fn        The method the event invokes
7787          * @param {Object} scope       (optional) The scope (this object) of the fn
7788          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7789          */
7790         addListener : function(eventName, fn, scope, options){
7791             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7792         },
7793
7794         /**
7795          * Removes an event handler from this element
7796          * @param {String} eventName the type of event to remove
7797          * @param {Function} fn the method the event invokes
7798          * @return {Roo.Element} this
7799          */
7800         removeListener : function(eventName, fn){
7801             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7802             return this;
7803         },
7804
7805         /**
7806          * Removes all previous added listeners from this element
7807          * @return {Roo.Element} this
7808          */
7809         removeAllListeners : function(){
7810             E.purgeElement(this.dom);
7811             return this;
7812         },
7813
7814         relayEvent : function(eventName, observable){
7815             this.on(eventName, function(e){
7816                 observable.fireEvent(eventName, e);
7817             });
7818         },
7819
7820         /**
7821          * Set the opacity of the element
7822          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7823          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7824          * @return {Roo.Element} this
7825          */
7826          setOpacity : function(opacity, animate){
7827             if(!animate || !A){
7828                 var s = this.dom.style;
7829                 if(Roo.isIE){
7830                     s.zoom = 1;
7831                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7832                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7833                 }else{
7834                     s.opacity = opacity;
7835                 }
7836             }else{
7837                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7838             }
7839             return this;
7840         },
7841
7842         /**
7843          * Gets the left X coordinate
7844          * @param {Boolean} local True to get the local css position instead of page coordinate
7845          * @return {Number}
7846          */
7847         getLeft : function(local){
7848             if(!local){
7849                 return this.getX();
7850             }else{
7851                 return parseInt(this.getStyle("left"), 10) || 0;
7852             }
7853         },
7854
7855         /**
7856          * Gets the right X coordinate of the element (element X position + element width)
7857          * @param {Boolean} local True to get the local css position instead of page coordinate
7858          * @return {Number}
7859          */
7860         getRight : function(local){
7861             if(!local){
7862                 return this.getX() + this.getWidth();
7863             }else{
7864                 return (this.getLeft(true) + this.getWidth()) || 0;
7865             }
7866         },
7867
7868         /**
7869          * Gets the top Y coordinate
7870          * @param {Boolean} local True to get the local css position instead of page coordinate
7871          * @return {Number}
7872          */
7873         getTop : function(local) {
7874             if(!local){
7875                 return this.getY();
7876             }else{
7877                 return parseInt(this.getStyle("top"), 10) || 0;
7878             }
7879         },
7880
7881         /**
7882          * Gets the bottom Y coordinate of the element (element Y position + element height)
7883          * @param {Boolean} local True to get the local css position instead of page coordinate
7884          * @return {Number}
7885          */
7886         getBottom : function(local){
7887             if(!local){
7888                 return this.getY() + this.getHeight();
7889             }else{
7890                 return (this.getTop(true) + this.getHeight()) || 0;
7891             }
7892         },
7893
7894         /**
7895         * Initializes positioning on this element. If a desired position is not passed, it will make the
7896         * the element positioned relative IF it is not already positioned.
7897         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7898         * @param {Number} zIndex (optional) The zIndex to apply
7899         * @param {Number} x (optional) Set the page X position
7900         * @param {Number} y (optional) Set the page Y position
7901         */
7902         position : function(pos, zIndex, x, y){
7903             if(!pos){
7904                if(this.getStyle('position') == 'static'){
7905                    this.setStyle('position', 'relative');
7906                }
7907             }else{
7908                 this.setStyle("position", pos);
7909             }
7910             if(zIndex){
7911                 this.setStyle("z-index", zIndex);
7912             }
7913             if(x !== undefined && y !== undefined){
7914                 this.setXY([x, y]);
7915             }else if(x !== undefined){
7916                 this.setX(x);
7917             }else if(y !== undefined){
7918                 this.setY(y);
7919             }
7920         },
7921
7922         /**
7923         * Clear positioning back to the default when the document was loaded
7924         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7925         * @return {Roo.Element} this
7926          */
7927         clearPositioning : function(value){
7928             value = value ||'';
7929             this.setStyle({
7930                 "left": value,
7931                 "right": value,
7932                 "top": value,
7933                 "bottom": value,
7934                 "z-index": "",
7935                 "position" : "static"
7936             });
7937             return this;
7938         },
7939
7940         /**
7941         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7942         * snapshot before performing an update and then restoring the element.
7943         * @return {Object}
7944         */
7945         getPositioning : function(){
7946             var l = this.getStyle("left");
7947             var t = this.getStyle("top");
7948             return {
7949                 "position" : this.getStyle("position"),
7950                 "left" : l,
7951                 "right" : l ? "" : this.getStyle("right"),
7952                 "top" : t,
7953                 "bottom" : t ? "" : this.getStyle("bottom"),
7954                 "z-index" : this.getStyle("z-index")
7955             };
7956         },
7957
7958         /**
7959          * Gets the width of the border(s) for the specified side(s)
7960          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7961          * passing lr would get the border (l)eft width + the border (r)ight width.
7962          * @return {Number} The width of the sides passed added together
7963          */
7964         getBorderWidth : function(side){
7965             return this.addStyles(side, El.borders);
7966         },
7967
7968         /**
7969          * Gets the width of the padding(s) for the specified side(s)
7970          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7971          * passing lr would get the padding (l)eft + the padding (r)ight.
7972          * @return {Number} The padding of the sides passed added together
7973          */
7974         getPadding : function(side){
7975             return this.addStyles(side, El.paddings);
7976         },
7977
7978         /**
7979         * Set positioning with an object returned by getPositioning().
7980         * @param {Object} posCfg
7981         * @return {Roo.Element} this
7982          */
7983         setPositioning : function(pc){
7984             this.applyStyles(pc);
7985             if(pc.right == "auto"){
7986                 this.dom.style.right = "";
7987             }
7988             if(pc.bottom == "auto"){
7989                 this.dom.style.bottom = "";
7990             }
7991             return this;
7992         },
7993
7994         // private
7995         fixDisplay : function(){
7996             if(this.getStyle("display") == "none"){
7997                 this.setStyle("visibility", "hidden");
7998                 this.setStyle("display", this.originalDisplay); // first try reverting to default
7999                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8000                     this.setStyle("display", "block");
8001                 }
8002             }
8003         },
8004
8005         /**
8006          * Quick set left and top adding default units
8007          * @param {String} left The left CSS property value
8008          * @param {String} top The top CSS property value
8009          * @return {Roo.Element} this
8010          */
8011          setLeftTop : function(left, top){
8012             this.dom.style.left = this.addUnits(left);
8013             this.dom.style.top = this.addUnits(top);
8014             return this;
8015         },
8016
8017         /**
8018          * Move this element relative to its current position.
8019          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8020          * @param {Number} distance How far to move the element in pixels
8021          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8022          * @return {Roo.Element} this
8023          */
8024          move : function(direction, distance, animate){
8025             var xy = this.getXY();
8026             direction = direction.toLowerCase();
8027             switch(direction){
8028                 case "l":
8029                 case "left":
8030                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8031                     break;
8032                case "r":
8033                case "right":
8034                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8035                     break;
8036                case "t":
8037                case "top":
8038                case "up":
8039                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8040                     break;
8041                case "b":
8042                case "bottom":
8043                case "down":
8044                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8045                     break;
8046             }
8047             return this;
8048         },
8049
8050         /**
8051          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8052          * @return {Roo.Element} this
8053          */
8054         clip : function(){
8055             if(!this.isClipped){
8056                this.isClipped = true;
8057                this.originalClip = {
8058                    "o": this.getStyle("overflow"),
8059                    "x": this.getStyle("overflow-x"),
8060                    "y": this.getStyle("overflow-y")
8061                };
8062                this.setStyle("overflow", "hidden");
8063                this.setStyle("overflow-x", "hidden");
8064                this.setStyle("overflow-y", "hidden");
8065             }
8066             return this;
8067         },
8068
8069         /**
8070          *  Return clipping (overflow) to original clipping before clip() was called
8071          * @return {Roo.Element} this
8072          */
8073         unclip : function(){
8074             if(this.isClipped){
8075                 this.isClipped = false;
8076                 var o = this.originalClip;
8077                 if(o.o){this.setStyle("overflow", o.o);}
8078                 if(o.x){this.setStyle("overflow-x", o.x);}
8079                 if(o.y){this.setStyle("overflow-y", o.y);}
8080             }
8081             return this;
8082         },
8083
8084
8085         /**
8086          * Gets the x,y coordinates specified by the anchor position on the element.
8087          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8088          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8089          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8090          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8091          * @return {Array} [x, y] An array containing the element's x and y coordinates
8092          */
8093         getAnchorXY : function(anchor, local, s){
8094             //Passing a different size is useful for pre-calculating anchors,
8095             //especially for anchored animations that change the el size.
8096
8097             var w, h, vp = false;
8098             if(!s){
8099                 var d = this.dom;
8100                 if(d == document.body || d == document){
8101                     vp = true;
8102                     w = D.getViewWidth(); h = D.getViewHeight();
8103                 }else{
8104                     w = this.getWidth(); h = this.getHeight();
8105                 }
8106             }else{
8107                 w = s.width;  h = s.height;
8108             }
8109             var x = 0, y = 0, r = Math.round;
8110             switch((anchor || "tl").toLowerCase()){
8111                 case "c":
8112                     x = r(w*.5);
8113                     y = r(h*.5);
8114                 break;
8115                 case "t":
8116                     x = r(w*.5);
8117                     y = 0;
8118                 break;
8119                 case "l":
8120                     x = 0;
8121                     y = r(h*.5);
8122                 break;
8123                 case "r":
8124                     x = w;
8125                     y = r(h*.5);
8126                 break;
8127                 case "b":
8128                     x = r(w*.5);
8129                     y = h;
8130                 break;
8131                 case "tl":
8132                     x = 0;
8133                     y = 0;
8134                 break;
8135                 case "bl":
8136                     x = 0;
8137                     y = h;
8138                 break;
8139                 case "br":
8140                     x = w;
8141                     y = h;
8142                 break;
8143                 case "tr":
8144                     x = w;
8145                     y = 0;
8146                 break;
8147             }
8148             if(local === true){
8149                 return [x, y];
8150             }
8151             if(vp){
8152                 var sc = this.getScroll();
8153                 return [x + sc.left, y + sc.top];
8154             }
8155             //Add the element's offset xy
8156             var o = this.getXY();
8157             return [x+o[0], y+o[1]];
8158         },
8159
8160         /**
8161          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8162          * supported position values.
8163          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8164          * @param {String} position The position to align to.
8165          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8166          * @return {Array} [x, y]
8167          */
8168         getAlignToXY : function(el, p, o){
8169             el = Roo.get(el);
8170             var d = this.dom;
8171             if(!el.dom){
8172                 throw "Element.alignTo with an element that doesn't exist";
8173             }
8174             var c = false; //constrain to viewport
8175             var p1 = "", p2 = "";
8176             o = o || [0,0];
8177
8178             if(!p){
8179                 p = "tl-bl";
8180             }else if(p == "?"){
8181                 p = "tl-bl?";
8182             }else if(p.indexOf("-") == -1){
8183                 p = "tl-" + p;
8184             }
8185             p = p.toLowerCase();
8186             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8187             if(!m){
8188                throw "Element.alignTo with an invalid alignment " + p;
8189             }
8190             p1 = m[1]; p2 = m[2]; c = !!m[3];
8191
8192             //Subtract the aligned el's internal xy from the target's offset xy
8193             //plus custom offset to get the aligned el's new offset xy
8194             var a1 = this.getAnchorXY(p1, true);
8195             var a2 = el.getAnchorXY(p2, false);
8196             var x = a2[0] - a1[0] + o[0];
8197             var y = a2[1] - a1[1] + o[1];
8198             if(c){
8199                 //constrain the aligned el to viewport if necessary
8200                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8201                 // 5px of margin for ie
8202                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8203
8204                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8205                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8206                 //otherwise swap the aligned el to the opposite border of the target.
8207                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8208                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8209                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8210                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8211
8212                var doc = document;
8213                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8214                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8215
8216                if((x+w) > dw + scrollX){
8217                     x = swapX ? r.left-w : dw+scrollX-w;
8218                 }
8219                if(x < scrollX){
8220                    x = swapX ? r.right : scrollX;
8221                }
8222                if((y+h) > dh + scrollY){
8223                     y = swapY ? r.top-h : dh+scrollY-h;
8224                 }
8225                if (y < scrollY){
8226                    y = swapY ? r.bottom : scrollY;
8227                }
8228             }
8229             return [x,y];
8230         },
8231
8232         // private
8233         getConstrainToXY : function(){
8234             var os = {top:0, left:0, bottom:0, right: 0};
8235
8236             return function(el, local, offsets, proposedXY){
8237                 el = Roo.get(el);
8238                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8239
8240                 var vw, vh, vx = 0, vy = 0;
8241                 if(el.dom == document.body || el.dom == document){
8242                     vw = Roo.lib.Dom.getViewWidth();
8243                     vh = Roo.lib.Dom.getViewHeight();
8244                 }else{
8245                     vw = el.dom.clientWidth;
8246                     vh = el.dom.clientHeight;
8247                     if(!local){
8248                         var vxy = el.getXY();
8249                         vx = vxy[0];
8250                         vy = vxy[1];
8251                     }
8252                 }
8253
8254                 var s = el.getScroll();
8255
8256                 vx += offsets.left + s.left;
8257                 vy += offsets.top + s.top;
8258
8259                 vw -= offsets.right;
8260                 vh -= offsets.bottom;
8261
8262                 var vr = vx+vw;
8263                 var vb = vy+vh;
8264
8265                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8266                 var x = xy[0], y = xy[1];
8267                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8268
8269                 // only move it if it needs it
8270                 var moved = false;
8271
8272                 // first validate right/bottom
8273                 if((x + w) > vr){
8274                     x = vr - w;
8275                     moved = true;
8276                 }
8277                 if((y + h) > vb){
8278                     y = vb - h;
8279                     moved = true;
8280                 }
8281                 // then make sure top/left isn't negative
8282                 if(x < vx){
8283                     x = vx;
8284                     moved = true;
8285                 }
8286                 if(y < vy){
8287                     y = vy;
8288                     moved = true;
8289                 }
8290                 return moved ? [x, y] : false;
8291             };
8292         }(),
8293
8294         // private
8295         adjustForConstraints : function(xy, parent, offsets){
8296             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8297         },
8298
8299         /**
8300          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8301          * document it aligns it to the viewport.
8302          * The position parameter is optional, and can be specified in any one of the following formats:
8303          * <ul>
8304          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8305          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8306          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8307          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8308          *   <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
8309          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8310          * </ul>
8311          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8312          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8313          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8314          * that specified in order to enforce the viewport constraints.
8315          * Following are all of the supported anchor positions:
8316     <pre>
8317     Value  Description
8318     -----  -----------------------------
8319     tl     The top left corner (default)
8320     t      The center of the top edge
8321     tr     The top right corner
8322     l      The center of the left edge
8323     c      In the center of the element
8324     r      The center of the right edge
8325     bl     The bottom left corner
8326     b      The center of the bottom edge
8327     br     The bottom right corner
8328     </pre>
8329     Example Usage:
8330     <pre><code>
8331     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8332     el.alignTo("other-el");
8333
8334     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8335     el.alignTo("other-el", "tr?");
8336
8337     // align the bottom right corner of el with the center left edge of other-el
8338     el.alignTo("other-el", "br-l?");
8339
8340     // align the center of el with the bottom left corner of other-el and
8341     // adjust the x position by -6 pixels (and the y position by 0)
8342     el.alignTo("other-el", "c-bl", [-6, 0]);
8343     </code></pre>
8344          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8345          * @param {String} position The position to align to.
8346          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8347          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8348          * @return {Roo.Element} this
8349          */
8350         alignTo : function(element, position, offsets, animate){
8351             var xy = this.getAlignToXY(element, position, offsets);
8352             this.setXY(xy, this.preanim(arguments, 3));
8353             return this;
8354         },
8355
8356         /**
8357          * Anchors an element to another element and realigns it when the window is resized.
8358          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8359          * @param {String} position The position to align to.
8360          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8361          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8362          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8363          * is a number, it is used as the buffer delay (defaults to 50ms).
8364          * @param {Function} callback The function to call after the animation finishes
8365          * @return {Roo.Element} this
8366          */
8367         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8368             var action = function(){
8369                 this.alignTo(el, alignment, offsets, animate);
8370                 Roo.callback(callback, this);
8371             };
8372             Roo.EventManager.onWindowResize(action, this);
8373             var tm = typeof monitorScroll;
8374             if(tm != 'undefined'){
8375                 Roo.EventManager.on(window, 'scroll', action, this,
8376                     {buffer: tm == 'number' ? monitorScroll : 50});
8377             }
8378             action.call(this); // align immediately
8379             return this;
8380         },
8381         /**
8382          * Clears any opacity settings from this element. Required in some cases for IE.
8383          * @return {Roo.Element} this
8384          */
8385         clearOpacity : function(){
8386             if (window.ActiveXObject) {
8387                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8388                     this.dom.style.filter = "";
8389                 }
8390             } else {
8391                 this.dom.style.opacity = "";
8392                 this.dom.style["-moz-opacity"] = "";
8393                 this.dom.style["-khtml-opacity"] = "";
8394             }
8395             return this;
8396         },
8397
8398         /**
8399          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8400          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8401          * @return {Roo.Element} this
8402          */
8403         hide : function(animate){
8404             this.setVisible(false, this.preanim(arguments, 0));
8405             return this;
8406         },
8407
8408         /**
8409         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8410         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8411          * @return {Roo.Element} this
8412          */
8413         show : function(animate){
8414             this.setVisible(true, this.preanim(arguments, 0));
8415             return this;
8416         },
8417
8418         /**
8419          * @private Test if size has a unit, otherwise appends the default
8420          */
8421         addUnits : function(size){
8422             return Roo.Element.addUnits(size, this.defaultUnit);
8423         },
8424
8425         /**
8426          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8427          * @return {Roo.Element} this
8428          */
8429         beginMeasure : function(){
8430             var el = this.dom;
8431             if(el.offsetWidth || el.offsetHeight){
8432                 return this; // offsets work already
8433             }
8434             var changed = [];
8435             var p = this.dom, b = document.body; // start with this element
8436             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8437                 var pe = Roo.get(p);
8438                 if(pe.getStyle('display') == 'none'){
8439                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8440                     p.style.visibility = "hidden";
8441                     p.style.display = "block";
8442                 }
8443                 p = p.parentNode;
8444             }
8445             this._measureChanged = changed;
8446             return this;
8447
8448         },
8449
8450         /**
8451          * Restores displays to before beginMeasure was called
8452          * @return {Roo.Element} this
8453          */
8454         endMeasure : function(){
8455             var changed = this._measureChanged;
8456             if(changed){
8457                 for(var i = 0, len = changed.length; i < len; i++) {
8458                     var r = changed[i];
8459                     r.el.style.visibility = r.visibility;
8460                     r.el.style.display = "none";
8461                 }
8462                 this._measureChanged = null;
8463             }
8464             return this;
8465         },
8466
8467         /**
8468         * Update the innerHTML of this element, optionally searching for and processing scripts
8469         * @param {String} html The new HTML
8470         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8471         * @param {Function} callback For async script loading you can be noticed when the update completes
8472         * @return {Roo.Element} this
8473          */
8474         update : function(html, loadScripts, callback){
8475             if(typeof html == "undefined"){
8476                 html = "";
8477             }
8478             if(loadScripts !== true){
8479                 this.dom.innerHTML = html;
8480                 if(typeof callback == "function"){
8481                     callback();
8482                 }
8483                 return this;
8484             }
8485             var id = Roo.id();
8486             var dom = this.dom;
8487
8488             html += '<span id="' + id + '"></span>';
8489
8490             E.onAvailable(id, function(){
8491                 var hd = document.getElementsByTagName("head")[0];
8492                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8493                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8494                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8495
8496                 var match;
8497                 while(match = re.exec(html)){
8498                     var attrs = match[1];
8499                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8500                     if(srcMatch && srcMatch[2]){
8501                        var s = document.createElement("script");
8502                        s.src = srcMatch[2];
8503                        var typeMatch = attrs.match(typeRe);
8504                        if(typeMatch && typeMatch[2]){
8505                            s.type = typeMatch[2];
8506                        }
8507                        hd.appendChild(s);
8508                     }else if(match[2] && match[2].length > 0){
8509                         if(window.execScript) {
8510                            window.execScript(match[2]);
8511                         } else {
8512                             /**
8513                              * eval:var:id
8514                              * eval:var:dom
8515                              * eval:var:html
8516                              * 
8517                              */
8518                            window.eval(match[2]);
8519                         }
8520                     }
8521                 }
8522                 var el = document.getElementById(id);
8523                 if(el){el.parentNode.removeChild(el);}
8524                 if(typeof callback == "function"){
8525                     callback();
8526                 }
8527             });
8528             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8529             return this;
8530         },
8531
8532         /**
8533          * Direct access to the UpdateManager update() method (takes the same parameters).
8534          * @param {String/Function} url The url for this request or a function to call to get the url
8535          * @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}
8536          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8537          * @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.
8538          * @return {Roo.Element} this
8539          */
8540         load : function(){
8541             var um = this.getUpdateManager();
8542             um.update.apply(um, arguments);
8543             return this;
8544         },
8545
8546         /**
8547         * Gets this element's UpdateManager
8548         * @return {Roo.UpdateManager} The UpdateManager
8549         */
8550         getUpdateManager : function(){
8551             if(!this.updateManager){
8552                 this.updateManager = new Roo.UpdateManager(this);
8553             }
8554             return this.updateManager;
8555         },
8556
8557         /**
8558          * Disables text selection for this element (normalized across browsers)
8559          * @return {Roo.Element} this
8560          */
8561         unselectable : function(){
8562             this.dom.unselectable = "on";
8563             this.swallowEvent("selectstart", true);
8564             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8565             this.addClass("x-unselectable");
8566             return this;
8567         },
8568
8569         /**
8570         * Calculates the x, y to center this element on the screen
8571         * @return {Array} The x, y values [x, y]
8572         */
8573         getCenterXY : function(){
8574             return this.getAlignToXY(document, 'c-c');
8575         },
8576
8577         /**
8578         * Centers the Element in either the viewport, or another Element.
8579         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8580         */
8581         center : function(centerIn){
8582             this.alignTo(centerIn || document, 'c-c');
8583             return this;
8584         },
8585
8586         /**
8587          * Tests various css rules/browsers to determine if this element uses a border box
8588          * @return {Boolean}
8589          */
8590         isBorderBox : function(){
8591             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8592         },
8593
8594         /**
8595          * Return a box {x, y, width, height} that can be used to set another elements
8596          * size/location to match this element.
8597          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8598          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8599          * @return {Object} box An object in the format {x, y, width, height}
8600          */
8601         getBox : function(contentBox, local){
8602             var xy;
8603             if(!local){
8604                 xy = this.getXY();
8605             }else{
8606                 var left = parseInt(this.getStyle("left"), 10) || 0;
8607                 var top = parseInt(this.getStyle("top"), 10) || 0;
8608                 xy = [left, top];
8609             }
8610             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8611             if(!contentBox){
8612                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8613             }else{
8614                 var l = this.getBorderWidth("l")+this.getPadding("l");
8615                 var r = this.getBorderWidth("r")+this.getPadding("r");
8616                 var t = this.getBorderWidth("t")+this.getPadding("t");
8617                 var b = this.getBorderWidth("b")+this.getPadding("b");
8618                 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)};
8619             }
8620             bx.right = bx.x + bx.width;
8621             bx.bottom = bx.y + bx.height;
8622             return bx;
8623         },
8624
8625         /**
8626          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8627          for more information about the sides.
8628          * @param {String} sides
8629          * @return {Number}
8630          */
8631         getFrameWidth : function(sides, onlyContentBox){
8632             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8633         },
8634
8635         /**
8636          * 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.
8637          * @param {Object} box The box to fill {x, y, width, height}
8638          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8639          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8640          * @return {Roo.Element} this
8641          */
8642         setBox : function(box, adjust, animate){
8643             var w = box.width, h = box.height;
8644             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8645                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8646                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8647             }
8648             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8649             return this;
8650         },
8651
8652         /**
8653          * Forces the browser to repaint this element
8654          * @return {Roo.Element} this
8655          */
8656          repaint : function(){
8657             var dom = this.dom;
8658             this.addClass("x-repaint");
8659             setTimeout(function(){
8660                 Roo.get(dom).removeClass("x-repaint");
8661             }, 1);
8662             return this;
8663         },
8664
8665         /**
8666          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8667          * then it returns the calculated width of the sides (see getPadding)
8668          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8669          * @return {Object/Number}
8670          */
8671         getMargins : function(side){
8672             if(!side){
8673                 return {
8674                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8675                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8676                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8677                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8678                 };
8679             }else{
8680                 return this.addStyles(side, El.margins);
8681              }
8682         },
8683
8684         // private
8685         addStyles : function(sides, styles){
8686             var val = 0, v, w;
8687             for(var i = 0, len = sides.length; i < len; i++){
8688                 v = this.getStyle(styles[sides.charAt(i)]);
8689                 if(v){
8690                      w = parseInt(v, 10);
8691                      if(w){ val += w; }
8692                 }
8693             }
8694             return val;
8695         },
8696
8697         /**
8698          * Creates a proxy element of this element
8699          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8700          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8701          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8702          * @return {Roo.Element} The new proxy element
8703          */
8704         createProxy : function(config, renderTo, matchBox){
8705             if(renderTo){
8706                 renderTo = Roo.getDom(renderTo);
8707             }else{
8708                 renderTo = document.body;
8709             }
8710             config = typeof config == "object" ?
8711                 config : {tag : "div", cls: config};
8712             var proxy = Roo.DomHelper.append(renderTo, config, true);
8713             if(matchBox){
8714                proxy.setBox(this.getBox());
8715             }
8716             return proxy;
8717         },
8718
8719         /**
8720          * Puts a mask over this element to disable user interaction. Requires core.css.
8721          * This method can only be applied to elements which accept child nodes.
8722          * @param {String} msg (optional) A message to display in the mask
8723          * @param {String} msgCls (optional) A css class to apply to the msg element
8724          * @return {Element} The mask  element
8725          */
8726         mask : function(msg, msgCls){
8727             if(this.getStyle("position") == "static"){
8728                 this.setStyle("position", "relative");
8729             }
8730             if(!this._mask){
8731                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8732             }
8733             this.addClass("x-masked");
8734             this._mask.setDisplayed(true);
8735             if(typeof msg == 'string'){
8736                 if(!this._maskMsg){
8737                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8738                 }
8739                 var mm = this._maskMsg;
8740                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8741                 mm.dom.firstChild.innerHTML = msg;
8742                 mm.setDisplayed(true);
8743                 mm.center(this);
8744             }
8745             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8746                 this._mask.setHeight(this.getHeight());
8747             }
8748             return this._mask;
8749         },
8750
8751         /**
8752          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8753          * it is cached for reuse.
8754          */
8755         unmask : function(removeEl){
8756             if(this._mask){
8757                 if(removeEl === true){
8758                     this._mask.remove();
8759                     delete this._mask;
8760                     if(this._maskMsg){
8761                         this._maskMsg.remove();
8762                         delete this._maskMsg;
8763                     }
8764                 }else{
8765                     this._mask.setDisplayed(false);
8766                     if(this._maskMsg){
8767                         this._maskMsg.setDisplayed(false);
8768                     }
8769                 }
8770             }
8771             this.removeClass("x-masked");
8772         },
8773
8774         /**
8775          * Returns true if this element is masked
8776          * @return {Boolean}
8777          */
8778         isMasked : function(){
8779             return this._mask && this._mask.isVisible();
8780         },
8781
8782         /**
8783          * Creates an iframe shim for this element to keep selects and other windowed objects from
8784          * showing through.
8785          * @return {Roo.Element} The new shim element
8786          */
8787         createShim : function(){
8788             var el = document.createElement('iframe');
8789             el.frameBorder = 'no';
8790             el.className = 'roo-shim';
8791             if(Roo.isIE && Roo.isSecure){
8792                 el.src = Roo.SSL_SECURE_URL;
8793             }
8794             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8795             shim.autoBoxAdjust = false;
8796             return shim;
8797         },
8798
8799         /**
8800          * Removes this element from the DOM and deletes it from the cache
8801          */
8802         remove : function(){
8803             if(this.dom.parentNode){
8804                 this.dom.parentNode.removeChild(this.dom);
8805             }
8806             delete El.cache[this.dom.id];
8807         },
8808
8809         /**
8810          * Sets up event handlers to add and remove a css class when the mouse is over this element
8811          * @param {String} className
8812          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8813          * mouseout events for children elements
8814          * @return {Roo.Element} this
8815          */
8816         addClassOnOver : function(className, preventFlicker){
8817             this.on("mouseover", function(){
8818                 Roo.fly(this, '_internal').addClass(className);
8819             }, this.dom);
8820             var removeFn = function(e){
8821                 if(preventFlicker !== true || !e.within(this, true)){
8822                     Roo.fly(this, '_internal').removeClass(className);
8823                 }
8824             };
8825             this.on("mouseout", removeFn, this.dom);
8826             return this;
8827         },
8828
8829         /**
8830          * Sets up event handlers to add and remove a css class when this element has the focus
8831          * @param {String} className
8832          * @return {Roo.Element} this
8833          */
8834         addClassOnFocus : function(className){
8835             this.on("focus", function(){
8836                 Roo.fly(this, '_internal').addClass(className);
8837             }, this.dom);
8838             this.on("blur", function(){
8839                 Roo.fly(this, '_internal').removeClass(className);
8840             }, this.dom);
8841             return this;
8842         },
8843         /**
8844          * 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)
8845          * @param {String} className
8846          * @return {Roo.Element} this
8847          */
8848         addClassOnClick : function(className){
8849             var dom = this.dom;
8850             this.on("mousedown", function(){
8851                 Roo.fly(dom, '_internal').addClass(className);
8852                 var d = Roo.get(document);
8853                 var fn = function(){
8854                     Roo.fly(dom, '_internal').removeClass(className);
8855                     d.removeListener("mouseup", fn);
8856                 };
8857                 d.on("mouseup", fn);
8858             });
8859             return this;
8860         },
8861
8862         /**
8863          * Stops the specified event from bubbling and optionally prevents the default action
8864          * @param {String} eventName
8865          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8866          * @return {Roo.Element} this
8867          */
8868         swallowEvent : function(eventName, preventDefault){
8869             var fn = function(e){
8870                 e.stopPropagation();
8871                 if(preventDefault){
8872                     e.preventDefault();
8873                 }
8874             };
8875             if(eventName instanceof Array){
8876                 for(var i = 0, len = eventName.length; i < len; i++){
8877                      this.on(eventName[i], fn);
8878                 }
8879                 return this;
8880             }
8881             this.on(eventName, fn);
8882             return this;
8883         },
8884
8885         /**
8886          * @private
8887          */
8888       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8889
8890         /**
8891          * Sizes this element to its parent element's dimensions performing
8892          * neccessary box adjustments.
8893          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8894          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8895          * @return {Roo.Element} this
8896          */
8897         fitToParent : function(monitorResize, targetParent) {
8898           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8899           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8900           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8901             return;
8902           }
8903           var p = Roo.get(targetParent || this.dom.parentNode);
8904           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8905           if (monitorResize === true) {
8906             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8907             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8908           }
8909           return this;
8910         },
8911
8912         /**
8913          * Gets the next sibling, skipping text nodes
8914          * @return {HTMLElement} The next sibling or null
8915          */
8916         getNextSibling : function(){
8917             var n = this.dom.nextSibling;
8918             while(n && n.nodeType != 1){
8919                 n = n.nextSibling;
8920             }
8921             return n;
8922         },
8923
8924         /**
8925          * Gets the previous sibling, skipping text nodes
8926          * @return {HTMLElement} The previous sibling or null
8927          */
8928         getPrevSibling : function(){
8929             var n = this.dom.previousSibling;
8930             while(n && n.nodeType != 1){
8931                 n = n.previousSibling;
8932             }
8933             return n;
8934         },
8935
8936
8937         /**
8938          * Appends the passed element(s) to this element
8939          * @param {String/HTMLElement/Array/Element/CompositeElement} el
8940          * @return {Roo.Element} this
8941          */
8942         appendChild: function(el){
8943             el = Roo.get(el);
8944             el.appendTo(this);
8945             return this;
8946         },
8947
8948         /**
8949          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8950          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
8951          * automatically generated with the specified attributes.
8952          * @param {HTMLElement} insertBefore (optional) a child element of this element
8953          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8954          * @return {Roo.Element} The new child element
8955          */
8956         createChild: function(config, insertBefore, returnDom){
8957             config = config || {tag:'div'};
8958             if(insertBefore){
8959                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8960             }
8961             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
8962         },
8963
8964         /**
8965          * Appends this element to the passed element
8966          * @param {String/HTMLElement/Element} el The new parent element
8967          * @return {Roo.Element} this
8968          */
8969         appendTo: function(el){
8970             el = Roo.getDom(el);
8971             el.appendChild(this.dom);
8972             return this;
8973         },
8974
8975         /**
8976          * Inserts this element before the passed element in the DOM
8977          * @param {String/HTMLElement/Element} el The element to insert before
8978          * @return {Roo.Element} this
8979          */
8980         insertBefore: function(el){
8981             el = Roo.getDom(el);
8982             el.parentNode.insertBefore(this.dom, el);
8983             return this;
8984         },
8985
8986         /**
8987          * Inserts this element after the passed element in the DOM
8988          * @param {String/HTMLElement/Element} el The element to insert after
8989          * @return {Roo.Element} this
8990          */
8991         insertAfter: function(el){
8992             el = Roo.getDom(el);
8993             el.parentNode.insertBefore(this.dom, el.nextSibling);
8994             return this;
8995         },
8996
8997         /**
8998          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8999          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9000          * @return {Roo.Element} The new child
9001          */
9002         insertFirst: function(el, returnDom){
9003             el = el || {};
9004             if(typeof el == 'object' && !el.nodeType){ // dh config
9005                 return this.createChild(el, this.dom.firstChild, returnDom);
9006             }else{
9007                 el = Roo.getDom(el);
9008                 this.dom.insertBefore(el, this.dom.firstChild);
9009                 return !returnDom ? Roo.get(el) : el;
9010             }
9011         },
9012
9013         /**
9014          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9015          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9016          * @param {String} where (optional) 'before' or 'after' defaults to before
9017          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9018          * @return {Roo.Element} the inserted Element
9019          */
9020         insertSibling: function(el, where, returnDom){
9021             where = where ? where.toLowerCase() : 'before';
9022             el = el || {};
9023             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9024
9025             if(typeof el == 'object' && !el.nodeType){ // dh config
9026                 if(where == 'after' && !this.dom.nextSibling){
9027                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9028                 }else{
9029                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9030                 }
9031
9032             }else{
9033                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9034                             where == 'before' ? this.dom : this.dom.nextSibling);
9035                 if(!returnDom){
9036                     rt = Roo.get(rt);
9037                 }
9038             }
9039             return rt;
9040         },
9041
9042         /**
9043          * Creates and wraps this element with another element
9044          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9045          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9046          * @return {HTMLElement/Element} The newly created wrapper element
9047          */
9048         wrap: function(config, returnDom){
9049             if(!config){
9050                 config = {tag: "div"};
9051             }
9052             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9053             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9054             return newEl;
9055         },
9056
9057         /**
9058          * Replaces the passed element with this element
9059          * @param {String/HTMLElement/Element} el The element to replace
9060          * @return {Roo.Element} this
9061          */
9062         replace: function(el){
9063             el = Roo.get(el);
9064             this.insertBefore(el);
9065             el.remove();
9066             return this;
9067         },
9068
9069         /**
9070          * Inserts an html fragment into this element
9071          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9072          * @param {String} html The HTML fragment
9073          * @param {Boolean} returnEl True to return an Roo.Element
9074          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9075          */
9076         insertHtml : function(where, html, returnEl){
9077             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9078             return returnEl ? Roo.get(el) : el;
9079         },
9080
9081         /**
9082          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9083          * @param {Object} o The object with the attributes
9084          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9085          * @return {Roo.Element} this
9086          */
9087         set : function(o, useSet){
9088             var el = this.dom;
9089             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9090             for(var attr in o){
9091                 if(attr == "style" || typeof o[attr] == "function") continue;
9092                 if(attr=="cls"){
9093                     el.className = o["cls"];
9094                 }else{
9095                     if(useSet) el.setAttribute(attr, o[attr]);
9096                     else el[attr] = o[attr];
9097                 }
9098             }
9099             if(o.style){
9100                 Roo.DomHelper.applyStyles(el, o.style);
9101             }
9102             return this;
9103         },
9104
9105         /**
9106          * Convenience method for constructing a KeyMap
9107          * @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:
9108          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9109          * @param {Function} fn The function to call
9110          * @param {Object} scope (optional) The scope of the function
9111          * @return {Roo.KeyMap} The KeyMap created
9112          */
9113         addKeyListener : function(key, fn, scope){
9114             var config;
9115             if(typeof key != "object" || key instanceof Array){
9116                 config = {
9117                     key: key,
9118                     fn: fn,
9119                     scope: scope
9120                 };
9121             }else{
9122                 config = {
9123                     key : key.key,
9124                     shift : key.shift,
9125                     ctrl : key.ctrl,
9126                     alt : key.alt,
9127                     fn: fn,
9128                     scope: scope
9129                 };
9130             }
9131             return new Roo.KeyMap(this, config);
9132         },
9133
9134         /**
9135          * Creates a KeyMap for this element
9136          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9137          * @return {Roo.KeyMap} The KeyMap created
9138          */
9139         addKeyMap : function(config){
9140             return new Roo.KeyMap(this, config);
9141         },
9142
9143         /**
9144          * Returns true if this element is scrollable.
9145          * @return {Boolean}
9146          */
9147          isScrollable : function(){
9148             var dom = this.dom;
9149             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9150         },
9151
9152         /**
9153          * 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().
9154          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9155          * @param {Number} value The new scroll value
9156          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9157          * @return {Element} this
9158          */
9159
9160         scrollTo : function(side, value, animate){
9161             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9162             if(!animate || !A){
9163                 this.dom[prop] = value;
9164             }else{
9165                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9166                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9167             }
9168             return this;
9169         },
9170
9171         /**
9172          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9173          * within this element's scrollable range.
9174          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9175          * @param {Number} distance How far to scroll the element in pixels
9176          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9177          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9178          * was scrolled as far as it could go.
9179          */
9180          scroll : function(direction, distance, animate){
9181              if(!this.isScrollable()){
9182                  return;
9183              }
9184              var el = this.dom;
9185              var l = el.scrollLeft, t = el.scrollTop;
9186              var w = el.scrollWidth, h = el.scrollHeight;
9187              var cw = el.clientWidth, ch = el.clientHeight;
9188              direction = direction.toLowerCase();
9189              var scrolled = false;
9190              var a = this.preanim(arguments, 2);
9191              switch(direction){
9192                  case "l":
9193                  case "left":
9194                      if(w - l > cw){
9195                          var v = Math.min(l + distance, w-cw);
9196                          this.scrollTo("left", v, a);
9197                          scrolled = true;
9198                      }
9199                      break;
9200                 case "r":
9201                 case "right":
9202                      if(l > 0){
9203                          var v = Math.max(l - distance, 0);
9204                          this.scrollTo("left", v, a);
9205                          scrolled = true;
9206                      }
9207                      break;
9208                 case "t":
9209                 case "top":
9210                 case "up":
9211                      if(t > 0){
9212                          var v = Math.max(t - distance, 0);
9213                          this.scrollTo("top", v, a);
9214                          scrolled = true;
9215                      }
9216                      break;
9217                 case "b":
9218                 case "bottom":
9219                 case "down":
9220                      if(h - t > ch){
9221                          var v = Math.min(t + distance, h-ch);
9222                          this.scrollTo("top", v, a);
9223                          scrolled = true;
9224                      }
9225                      break;
9226              }
9227              return scrolled;
9228         },
9229
9230         /**
9231          * Translates the passed page coordinates into left/top css values for this element
9232          * @param {Number/Array} x The page x or an array containing [x, y]
9233          * @param {Number} y The page y
9234          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9235          */
9236         translatePoints : function(x, y){
9237             if(typeof x == 'object' || x instanceof Array){
9238                 y = x[1]; x = x[0];
9239             }
9240             var p = this.getStyle('position');
9241             var o = this.getXY();
9242
9243             var l = parseInt(this.getStyle('left'), 10);
9244             var t = parseInt(this.getStyle('top'), 10);
9245
9246             if(isNaN(l)){
9247                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9248             }
9249             if(isNaN(t)){
9250                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9251             }
9252
9253             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9254         },
9255
9256         /**
9257          * Returns the current scroll position of the element.
9258          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9259          */
9260         getScroll : function(){
9261             var d = this.dom, doc = document;
9262             if(d == doc || d == doc.body){
9263                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9264                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9265                 return {left: l, top: t};
9266             }else{
9267                 return {left: d.scrollLeft, top: d.scrollTop};
9268             }
9269         },
9270
9271         /**
9272          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9273          * are convert to standard 6 digit hex color.
9274          * @param {String} attr The css attribute
9275          * @param {String} defaultValue The default value to use when a valid color isn't found
9276          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9277          * YUI color anims.
9278          */
9279         getColor : function(attr, defaultValue, prefix){
9280             var v = this.getStyle(attr);
9281             if(!v || v == "transparent" || v == "inherit") {
9282                 return defaultValue;
9283             }
9284             var color = typeof prefix == "undefined" ? "#" : prefix;
9285             if(v.substr(0, 4) == "rgb("){
9286                 var rvs = v.slice(4, v.length -1).split(",");
9287                 for(var i = 0; i < 3; i++){
9288                     var h = parseInt(rvs[i]).toString(16);
9289                     if(h < 16){
9290                         h = "0" + h;
9291                     }
9292                     color += h;
9293                 }
9294             } else {
9295                 if(v.substr(0, 1) == "#"){
9296                     if(v.length == 4) {
9297                         for(var i = 1; i < 4; i++){
9298                             var c = v.charAt(i);
9299                             color +=  c + c;
9300                         }
9301                     }else if(v.length == 7){
9302                         color += v.substr(1);
9303                     }
9304                 }
9305             }
9306             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9307         },
9308
9309         /**
9310          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9311          * gradient background, rounded corners and a 4-way shadow.
9312          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9313          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9314          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9315          * @return {Roo.Element} this
9316          */
9317         boxWrap : function(cls){
9318             cls = cls || 'x-box';
9319             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9320             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9321             return el;
9322         },
9323
9324         /**
9325          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9326          * @param {String} namespace The namespace in which to look for the attribute
9327          * @param {String} name The attribute name
9328          * @return {String} The attribute value
9329          */
9330         getAttributeNS : Roo.isIE ? function(ns, name){
9331             var d = this.dom;
9332             var type = typeof d[ns+":"+name];
9333             if(type != 'undefined' && type != 'unknown'){
9334                 return d[ns+":"+name];
9335             }
9336             return d[name];
9337         } : function(ns, name){
9338             var d = this.dom;
9339             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9340         }
9341     };
9342
9343     var ep = El.prototype;
9344
9345     /**
9346      * Appends an event handler (Shorthand for addListener)
9347      * @param {String}   eventName     The type of event to append
9348      * @param {Function} fn        The method the event invokes
9349      * @param {Object} scope       (optional) The scope (this object) of the fn
9350      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9351      * @method
9352      */
9353     ep.on = ep.addListener;
9354         // backwards compat
9355     ep.mon = ep.addListener;
9356
9357     /**
9358      * Removes an event handler from this element (shorthand for removeListener)
9359      * @param {String} eventName the type of event to remove
9360      * @param {Function} fn the method the event invokes
9361      * @return {Roo.Element} this
9362      * @method
9363      */
9364     ep.un = ep.removeListener;
9365
9366     /**
9367      * true to automatically adjust width and height settings for box-model issues (default to true)
9368      */
9369     ep.autoBoxAdjust = true;
9370
9371     // private
9372     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9373
9374     // private
9375     El.addUnits = function(v, defaultUnit){
9376         if(v === "" || v == "auto"){
9377             return v;
9378         }
9379         if(v === undefined){
9380             return '';
9381         }
9382         if(typeof v == "number" || !El.unitPattern.test(v)){
9383             return v + (defaultUnit || 'px');
9384         }
9385         return v;
9386     };
9387
9388     // special markup used throughout Roo when box wrapping elements
9389     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>';
9390     /**
9391      * Visibility mode constant - Use visibility to hide element
9392      * @static
9393      * @type Number
9394      */
9395     El.VISIBILITY = 1;
9396     /**
9397      * Visibility mode constant - Use display to hide element
9398      * @static
9399      * @type Number
9400      */
9401     El.DISPLAY = 2;
9402
9403     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9404     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9405     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9406
9407
9408
9409     /**
9410      * @private
9411      */
9412     El.cache = {};
9413
9414     var docEl;
9415
9416     /**
9417      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9418      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9419      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9420      * @return {Element} The Element object
9421      * @static
9422      */
9423     El.get = function(el){
9424         var ex, elm, id;
9425         if(!el){ return null; }
9426         if(typeof el == "string"){ // element id
9427             if(!(elm = document.getElementById(el))){
9428                 return null;
9429             }
9430             if(ex = El.cache[el]){
9431                 ex.dom = elm;
9432             }else{
9433                 ex = El.cache[el] = new El(elm);
9434             }
9435             return ex;
9436         }else if(el.tagName){ // dom element
9437             if(!(id = el.id)){
9438                 id = Roo.id(el);
9439             }
9440             if(ex = El.cache[id]){
9441                 ex.dom = el;
9442             }else{
9443                 ex = El.cache[id] = new El(el);
9444             }
9445             return ex;
9446         }else if(el instanceof El){
9447             if(el != docEl){
9448                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9449                                                               // catch case where it hasn't been appended
9450                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9451             }
9452             return el;
9453         }else if(el.isComposite){
9454             return el;
9455         }else if(el instanceof Array){
9456             return El.select(el);
9457         }else if(el == document){
9458             // create a bogus element object representing the document object
9459             if(!docEl){
9460                 var f = function(){};
9461                 f.prototype = El.prototype;
9462                 docEl = new f();
9463                 docEl.dom = document;
9464             }
9465             return docEl;
9466         }
9467         return null;
9468     };
9469
9470     // private
9471     El.uncache = function(el){
9472         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9473             if(a[i]){
9474                 delete El.cache[a[i].id || a[i]];
9475             }
9476         }
9477     };
9478
9479     // private
9480     // Garbage collection - uncache elements/purge listeners on orphaned elements
9481     // so we don't hold a reference and cause the browser to retain them
9482     El.garbageCollect = function(){
9483         if(!Roo.enableGarbageCollector){
9484             clearInterval(El.collectorThread);
9485             return;
9486         }
9487         for(var eid in El.cache){
9488             var el = El.cache[eid], d = el.dom;
9489             // -------------------------------------------------------
9490             // Determining what is garbage:
9491             // -------------------------------------------------------
9492             // !d
9493             // dom node is null, definitely garbage
9494             // -------------------------------------------------------
9495             // !d.parentNode
9496             // no parentNode == direct orphan, definitely garbage
9497             // -------------------------------------------------------
9498             // !d.offsetParent && !document.getElementById(eid)
9499             // display none elements have no offsetParent so we will
9500             // also try to look it up by it's id. However, check
9501             // offsetParent first so we don't do unneeded lookups.
9502             // This enables collection of elements that are not orphans
9503             // directly, but somewhere up the line they have an orphan
9504             // parent.
9505             // -------------------------------------------------------
9506             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9507                 delete El.cache[eid];
9508                 if(d && Roo.enableListenerCollection){
9509                     E.purgeElement(d);
9510                 }
9511             }
9512         }
9513     }
9514     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9515
9516
9517     // dom is optional
9518     El.Flyweight = function(dom){
9519         this.dom = dom;
9520     };
9521     El.Flyweight.prototype = El.prototype;
9522
9523     El._flyweights = {};
9524     /**
9525      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9526      * the dom node can be overwritten by other code.
9527      * @param {String/HTMLElement} el The dom node or id
9528      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9529      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9530      * @static
9531      * @return {Element} The shared Element object
9532      */
9533     El.fly = function(el, named){
9534         named = named || '_global';
9535         el = Roo.getDom(el);
9536         if(!el){
9537             return null;
9538         }
9539         if(!El._flyweights[named]){
9540             El._flyweights[named] = new El.Flyweight();
9541         }
9542         El._flyweights[named].dom = el;
9543         return El._flyweights[named];
9544     };
9545
9546     /**
9547      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9548      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9549      * Shorthand of {@link Roo.Element#get}
9550      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9551      * @return {Element} The Element object
9552      * @member Roo
9553      * @method get
9554      */
9555     Roo.get = El.get;
9556     /**
9557      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9558      * the dom node can be overwritten by other code.
9559      * Shorthand of {@link Roo.Element#fly}
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      * @member Roo
9566      * @method fly
9567      */
9568     Roo.fly = El.fly;
9569
9570     // speedy lookup for elements never to box adjust
9571     var noBoxAdjust = Roo.isStrict ? {
9572         select:1
9573     } : {
9574         input:1, select:1, textarea:1
9575     };
9576     if(Roo.isIE || Roo.isGecko){
9577         noBoxAdjust['button'] = 1;
9578     }
9579
9580
9581     Roo.EventManager.on(window, 'unload', function(){
9582         delete El.cache;
9583         delete El._flyweights;
9584     });
9585 })();
9586
9587
9588
9589
9590 if(Roo.DomQuery){
9591     Roo.Element.selectorFunction = Roo.DomQuery.select;
9592 }
9593
9594 Roo.Element.select = function(selector, unique, root){
9595     var els;
9596     if(typeof selector == "string"){
9597         els = Roo.Element.selectorFunction(selector, root);
9598     }else if(selector.length !== undefined){
9599         els = selector;
9600     }else{
9601         throw "Invalid selector";
9602     }
9603     if(unique === true){
9604         return new Roo.CompositeElement(els);
9605     }else{
9606         return new Roo.CompositeElementLite(els);
9607     }
9608 };
9609 /**
9610  * Selects elements based on the passed CSS selector to enable working on them as 1.
9611  * @param {String/Array} selector The CSS selector or an array of elements
9612  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9613  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9614  * @return {CompositeElementLite/CompositeElement}
9615  * @member Roo
9616  * @method select
9617  */
9618 Roo.select = Roo.Element.select;
9619
9620
9621
9622
9623
9624
9625
9626
9627
9628
9629
9630
9631
9632
9633 /*
9634  * Based on:
9635  * Ext JS Library 1.1.1
9636  * Copyright(c) 2006-2007, Ext JS, LLC.
9637  *
9638  * Originally Released Under LGPL - original licence link has changed is not relivant.
9639  *
9640  * Fork - LGPL
9641  * <script type="text/javascript">
9642  */
9643
9644
9645
9646 //Notifies Element that fx methods are available
9647 Roo.enableFx = true;
9648
9649 /**
9650  * @class Roo.Fx
9651  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9652  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9653  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9654  * Element effects to work.</p><br/>
9655  *
9656  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9657  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9658  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9659  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9660  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9661  * expected results and should be done with care.</p><br/>
9662  *
9663  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9664  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9665 <pre>
9666 Value  Description
9667 -----  -----------------------------
9668 tl     The top left corner
9669 t      The center of the top edge
9670 tr     The top right corner
9671 l      The center of the left edge
9672 r      The center of the right edge
9673 bl     The bottom left corner
9674 b      The center of the bottom edge
9675 br     The bottom right corner
9676 </pre>
9677  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9678  * below are common options that can be passed to any Fx method.</b>
9679  * @cfg {Function} callback A function called when the effect is finished
9680  * @cfg {Object} scope The scope of the effect function
9681  * @cfg {String} easing A valid Easing value for the effect
9682  * @cfg {String} afterCls A css class to apply after the effect
9683  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9684  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9685  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9686  * effects that end with the element being visually hidden, ignored otherwise)
9687  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9688  * a function which returns such a specification that will be applied to the Element after the effect finishes
9689  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9690  * @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
9691  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9692  */
9693 Roo.Fx = {
9694         /**
9695          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9696          * origin for the slide effect.  This function automatically handles wrapping the element with
9697          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9698          * Usage:
9699          *<pre><code>
9700 // default: slide the element in from the top
9701 el.slideIn();
9702
9703 // custom: slide the element in from the right with a 2-second duration
9704 el.slideIn('r', { duration: 2 });
9705
9706 // common config options shown with default values
9707 el.slideIn('t', {
9708     easing: 'easeOut',
9709     duration: .5
9710 });
9711 </code></pre>
9712          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9713          * @param {Object} options (optional) Object literal with any of the Fx config options
9714          * @return {Roo.Element} The Element
9715          */
9716     slideIn : function(anchor, o){
9717         var el = this.getFxEl();
9718         o = o || {};
9719
9720         el.queueFx(o, function(){
9721
9722             anchor = anchor || "t";
9723
9724             // fix display to visibility
9725             this.fixDisplay();
9726
9727             // restore values after effect
9728             var r = this.getFxRestore();
9729             var b = this.getBox();
9730             // fixed size for slide
9731             this.setSize(b);
9732
9733             // wrap if needed
9734             var wrap = this.fxWrap(r.pos, o, "hidden");
9735
9736             var st = this.dom.style;
9737             st.visibility = "visible";
9738             st.position = "absolute";
9739
9740             // clear out temp styles after slide and unwrap
9741             var after = function(){
9742                 el.fxUnwrap(wrap, r.pos, o);
9743                 st.width = r.width;
9744                 st.height = r.height;
9745                 el.afterFx(o);
9746             };
9747             // time to calc the positions
9748             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9749
9750             switch(anchor.toLowerCase()){
9751                 case "t":
9752                     wrap.setSize(b.width, 0);
9753                     st.left = st.bottom = "0";
9754                     a = {height: bh};
9755                 break;
9756                 case "l":
9757                     wrap.setSize(0, b.height);
9758                     st.right = st.top = "0";
9759                     a = {width: bw};
9760                 break;
9761                 case "r":
9762                     wrap.setSize(0, b.height);
9763                     wrap.setX(b.right);
9764                     st.left = st.top = "0";
9765                     a = {width: bw, points: pt};
9766                 break;
9767                 case "b":
9768                     wrap.setSize(b.width, 0);
9769                     wrap.setY(b.bottom);
9770                     st.left = st.top = "0";
9771                     a = {height: bh, points: pt};
9772                 break;
9773                 case "tl":
9774                     wrap.setSize(0, 0);
9775                     st.right = st.bottom = "0";
9776                     a = {width: bw, height: bh};
9777                 break;
9778                 case "bl":
9779                     wrap.setSize(0, 0);
9780                     wrap.setY(b.y+b.height);
9781                     st.right = st.top = "0";
9782                     a = {width: bw, height: bh, points: pt};
9783                 break;
9784                 case "br":
9785                     wrap.setSize(0, 0);
9786                     wrap.setXY([b.right, b.bottom]);
9787                     st.left = st.top = "0";
9788                     a = {width: bw, height: bh, points: pt};
9789                 break;
9790                 case "tr":
9791                     wrap.setSize(0, 0);
9792                     wrap.setX(b.x+b.width);
9793                     st.left = st.bottom = "0";
9794                     a = {width: bw, height: bh, points: pt};
9795                 break;
9796             }
9797             this.dom.style.visibility = "visible";
9798             wrap.show();
9799
9800             arguments.callee.anim = wrap.fxanim(a,
9801                 o,
9802                 'motion',
9803                 .5,
9804                 'easeOut', after);
9805         });
9806         return this;
9807     },
9808     
9809         /**
9810          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9811          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9812          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9813          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9814          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9815          * Usage:
9816          *<pre><code>
9817 // default: slide the element out to the top
9818 el.slideOut();
9819
9820 // custom: slide the element out to the right with a 2-second duration
9821 el.slideOut('r', { duration: 2 });
9822
9823 // common config options shown with default values
9824 el.slideOut('t', {
9825     easing: 'easeOut',
9826     duration: .5,
9827     remove: false,
9828     useDisplay: false
9829 });
9830 </code></pre>
9831          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9832          * @param {Object} options (optional) Object literal with any of the Fx config options
9833          * @return {Roo.Element} The Element
9834          */
9835     slideOut : function(anchor, o){
9836         var el = this.getFxEl();
9837         o = o || {};
9838
9839         el.queueFx(o, function(){
9840
9841             anchor = anchor || "t";
9842
9843             // restore values after effect
9844             var r = this.getFxRestore();
9845             
9846             var b = this.getBox();
9847             // fixed size for slide
9848             this.setSize(b);
9849
9850             // wrap if needed
9851             var wrap = this.fxWrap(r.pos, o, "visible");
9852
9853             var st = this.dom.style;
9854             st.visibility = "visible";
9855             st.position = "absolute";
9856
9857             wrap.setSize(b);
9858
9859             var after = function(){
9860                 if(o.useDisplay){
9861                     el.setDisplayed(false);
9862                 }else{
9863                     el.hide();
9864                 }
9865
9866                 el.fxUnwrap(wrap, r.pos, o);
9867
9868                 st.width = r.width;
9869                 st.height = r.height;
9870
9871                 el.afterFx(o);
9872             };
9873
9874             var a, zero = {to: 0};
9875             switch(anchor.toLowerCase()){
9876                 case "t":
9877                     st.left = st.bottom = "0";
9878                     a = {height: zero};
9879                 break;
9880                 case "l":
9881                     st.right = st.top = "0";
9882                     a = {width: zero};
9883                 break;
9884                 case "r":
9885                     st.left = st.top = "0";
9886                     a = {width: zero, points: {to:[b.right, b.y]}};
9887                 break;
9888                 case "b":
9889                     st.left = st.top = "0";
9890                     a = {height: zero, points: {to:[b.x, b.bottom]}};
9891                 break;
9892                 case "tl":
9893                     st.right = st.bottom = "0";
9894                     a = {width: zero, height: zero};
9895                 break;
9896                 case "bl":
9897                     st.right = st.top = "0";
9898                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9899                 break;
9900                 case "br":
9901                     st.left = st.top = "0";
9902                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9903                 break;
9904                 case "tr":
9905                     st.left = st.bottom = "0";
9906                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9907                 break;
9908             }
9909
9910             arguments.callee.anim = wrap.fxanim(a,
9911                 o,
9912                 'motion',
9913                 .5,
9914                 "easeOut", after);
9915         });
9916         return this;
9917     },
9918
9919         /**
9920          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
9921          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
9922          * The element must be removed from the DOM using the 'remove' config option if desired.
9923          * Usage:
9924          *<pre><code>
9925 // default
9926 el.puff();
9927
9928 // common config options shown with default values
9929 el.puff({
9930     easing: 'easeOut',
9931     duration: .5,
9932     remove: false,
9933     useDisplay: false
9934 });
9935 </code></pre>
9936          * @param {Object} options (optional) Object literal with any of the Fx config options
9937          * @return {Roo.Element} The Element
9938          */
9939     puff : function(o){
9940         var el = this.getFxEl();
9941         o = o || {};
9942
9943         el.queueFx(o, function(){
9944             this.clearOpacity();
9945             this.show();
9946
9947             // restore values after effect
9948             var r = this.getFxRestore();
9949             var st = this.dom.style;
9950
9951             var after = function(){
9952                 if(o.useDisplay){
9953                     el.setDisplayed(false);
9954                 }else{
9955                     el.hide();
9956                 }
9957
9958                 el.clearOpacity();
9959
9960                 el.setPositioning(r.pos);
9961                 st.width = r.width;
9962                 st.height = r.height;
9963                 st.fontSize = '';
9964                 el.afterFx(o);
9965             };
9966
9967             var width = this.getWidth();
9968             var height = this.getHeight();
9969
9970             arguments.callee.anim = this.fxanim({
9971                     width : {to: this.adjustWidth(width * 2)},
9972                     height : {to: this.adjustHeight(height * 2)},
9973                     points : {by: [-(width * .5), -(height * .5)]},
9974                     opacity : {to: 0},
9975                     fontSize: {to:200, unit: "%"}
9976                 },
9977                 o,
9978                 'motion',
9979                 .5,
9980                 "easeOut", after);
9981         });
9982         return this;
9983     },
9984
9985         /**
9986          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9987          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
9988          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9989          * Usage:
9990          *<pre><code>
9991 // default
9992 el.switchOff();
9993
9994 // all config options shown with default values
9995 el.switchOff({
9996     easing: 'easeIn',
9997     duration: .3,
9998     remove: false,
9999     useDisplay: false
10000 });
10001 </code></pre>
10002          * @param {Object} options (optional) Object literal with any of the Fx config options
10003          * @return {Roo.Element} The Element
10004          */
10005     switchOff : function(o){
10006         var el = this.getFxEl();
10007         o = o || {};
10008
10009         el.queueFx(o, function(){
10010             this.clearOpacity();
10011             this.clip();
10012
10013             // restore values after effect
10014             var r = this.getFxRestore();
10015             var st = this.dom.style;
10016
10017             var after = function(){
10018                 if(o.useDisplay){
10019                     el.setDisplayed(false);
10020                 }else{
10021                     el.hide();
10022                 }
10023
10024                 el.clearOpacity();
10025                 el.setPositioning(r.pos);
10026                 st.width = r.width;
10027                 st.height = r.height;
10028
10029                 el.afterFx(o);
10030             };
10031
10032             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10033                 this.clearOpacity();
10034                 (function(){
10035                     this.fxanim({
10036                         height:{to:1},
10037                         points:{by:[0, this.getHeight() * .5]}
10038                     }, o, 'motion', 0.3, 'easeIn', after);
10039                 }).defer(100, this);
10040             });
10041         });
10042         return this;
10043     },
10044
10045     /**
10046      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10047      * changed using the "attr" config option) and then fading back to the original color. If no original
10048      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10049      * Usage:
10050 <pre><code>
10051 // default: highlight background to yellow
10052 el.highlight();
10053
10054 // custom: highlight foreground text to blue for 2 seconds
10055 el.highlight("0000ff", { attr: 'color', duration: 2 });
10056
10057 // common config options shown with default values
10058 el.highlight("ffff9c", {
10059     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10060     endColor: (current color) or "ffffff",
10061     easing: 'easeIn',
10062     duration: 1
10063 });
10064 </code></pre>
10065      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10066      * @param {Object} options (optional) Object literal with any of the Fx config options
10067      * @return {Roo.Element} The Element
10068      */ 
10069     highlight : function(color, o){
10070         var el = this.getFxEl();
10071         o = o || {};
10072
10073         el.queueFx(o, function(){
10074             color = color || "ffff9c";
10075             attr = o.attr || "backgroundColor";
10076
10077             this.clearOpacity();
10078             this.show();
10079
10080             var origColor = this.getColor(attr);
10081             var restoreColor = this.dom.style[attr];
10082             endColor = (o.endColor || origColor) || "ffffff";
10083
10084             var after = function(){
10085                 el.dom.style[attr] = restoreColor;
10086                 el.afterFx(o);
10087             };
10088
10089             var a = {};
10090             a[attr] = {from: color, to: endColor};
10091             arguments.callee.anim = this.fxanim(a,
10092                 o,
10093                 'color',
10094                 1,
10095                 'easeIn', after);
10096         });
10097         return this;
10098     },
10099
10100    /**
10101     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10102     * Usage:
10103 <pre><code>
10104 // default: a single light blue ripple
10105 el.frame();
10106
10107 // custom: 3 red ripples lasting 3 seconds total
10108 el.frame("ff0000", 3, { duration: 3 });
10109
10110 // common config options shown with default values
10111 el.frame("C3DAF9", 1, {
10112     duration: 1 //duration of entire animation (not each individual ripple)
10113     // Note: Easing is not configurable and will be ignored if included
10114 });
10115 </code></pre>
10116     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10117     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10118     * @param {Object} options (optional) Object literal with any of the Fx config options
10119     * @return {Roo.Element} The Element
10120     */
10121     frame : function(color, count, o){
10122         var el = this.getFxEl();
10123         o = o || {};
10124
10125         el.queueFx(o, function(){
10126             color = color || "#C3DAF9";
10127             if(color.length == 6){
10128                 color = "#" + color;
10129             }
10130             count = count || 1;
10131             duration = o.duration || 1;
10132             this.show();
10133
10134             var b = this.getBox();
10135             var animFn = function(){
10136                 var proxy = this.createProxy({
10137
10138                      style:{
10139                         visbility:"hidden",
10140                         position:"absolute",
10141                         "z-index":"35000", // yee haw
10142                         border:"0px solid " + color
10143                      }
10144                   });
10145                 var scale = Roo.isBorderBox ? 2 : 1;
10146                 proxy.animate({
10147                     top:{from:b.y, to:b.y - 20},
10148                     left:{from:b.x, to:b.x - 20},
10149                     borderWidth:{from:0, to:10},
10150                     opacity:{from:1, to:0},
10151                     height:{from:b.height, to:(b.height + (20*scale))},
10152                     width:{from:b.width, to:(b.width + (20*scale))}
10153                 }, duration, function(){
10154                     proxy.remove();
10155                 });
10156                 if(--count > 0){
10157                      animFn.defer((duration/2)*1000, this);
10158                 }else{
10159                     el.afterFx(o);
10160                 }
10161             };
10162             animFn.call(this);
10163         });
10164         return this;
10165     },
10166
10167    /**
10168     * Creates a pause before any subsequent queued effects begin.  If there are
10169     * no effects queued after the pause it will have no effect.
10170     * Usage:
10171 <pre><code>
10172 el.pause(1);
10173 </code></pre>
10174     * @param {Number} seconds The length of time to pause (in seconds)
10175     * @return {Roo.Element} The Element
10176     */
10177     pause : function(seconds){
10178         var el = this.getFxEl();
10179         var o = {};
10180
10181         el.queueFx(o, function(){
10182             setTimeout(function(){
10183                 el.afterFx(o);
10184             }, seconds * 1000);
10185         });
10186         return this;
10187     },
10188
10189    /**
10190     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10191     * using the "endOpacity" config option.
10192     * Usage:
10193 <pre><code>
10194 // default: fade in from opacity 0 to 100%
10195 el.fadeIn();
10196
10197 // custom: fade in from opacity 0 to 75% over 2 seconds
10198 el.fadeIn({ endOpacity: .75, duration: 2});
10199
10200 // common config options shown with default values
10201 el.fadeIn({
10202     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10203     easing: 'easeOut',
10204     duration: .5
10205 });
10206 </code></pre>
10207     * @param {Object} options (optional) Object literal with any of the Fx config options
10208     * @return {Roo.Element} The Element
10209     */
10210     fadeIn : function(o){
10211         var el = this.getFxEl();
10212         o = o || {};
10213         el.queueFx(o, function(){
10214             this.setOpacity(0);
10215             this.fixDisplay();
10216             this.dom.style.visibility = 'visible';
10217             var to = o.endOpacity || 1;
10218             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10219                 o, null, .5, "easeOut", function(){
10220                 if(to == 1){
10221                     this.clearOpacity();
10222                 }
10223                 el.afterFx(o);
10224             });
10225         });
10226         return this;
10227     },
10228
10229    /**
10230     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10231     * using the "endOpacity" config option.
10232     * Usage:
10233 <pre><code>
10234 // default: fade out from the element's current opacity to 0
10235 el.fadeOut();
10236
10237 // custom: fade out from the element's current opacity to 25% over 2 seconds
10238 el.fadeOut({ endOpacity: .25, duration: 2});
10239
10240 // common config options shown with default values
10241 el.fadeOut({
10242     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10243     easing: 'easeOut',
10244     duration: .5
10245     remove: false,
10246     useDisplay: false
10247 });
10248 </code></pre>
10249     * @param {Object} options (optional) Object literal with any of the Fx config options
10250     * @return {Roo.Element} The Element
10251     */
10252     fadeOut : function(o){
10253         var el = this.getFxEl();
10254         o = o || {};
10255         el.queueFx(o, function(){
10256             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10257                 o, null, .5, "easeOut", function(){
10258                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10259                      this.dom.style.display = "none";
10260                 }else{
10261                      this.dom.style.visibility = "hidden";
10262                 }
10263                 this.clearOpacity();
10264                 el.afterFx(o);
10265             });
10266         });
10267         return this;
10268     },
10269
10270    /**
10271     * Animates the transition of an element's dimensions from a starting height/width
10272     * to an ending height/width.
10273     * Usage:
10274 <pre><code>
10275 // change height and width to 100x100 pixels
10276 el.scale(100, 100);
10277
10278 // common config options shown with default values.  The height and width will default to
10279 // the element's existing values if passed as null.
10280 el.scale(
10281     [element's width],
10282     [element's height], {
10283     easing: 'easeOut',
10284     duration: .35
10285 });
10286 </code></pre>
10287     * @param {Number} width  The new width (pass undefined to keep the original width)
10288     * @param {Number} height  The new height (pass undefined to keep the original height)
10289     * @param {Object} options (optional) Object literal with any of the Fx config options
10290     * @return {Roo.Element} The Element
10291     */
10292     scale : function(w, h, o){
10293         this.shift(Roo.apply({}, o, {
10294             width: w,
10295             height: h
10296         }));
10297         return this;
10298     },
10299
10300    /**
10301     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10302     * Any of these properties not specified in the config object will not be changed.  This effect 
10303     * requires that at least one new dimension, position or opacity setting must be passed in on
10304     * the config object in order for the function to have any effect.
10305     * Usage:
10306 <pre><code>
10307 // slide the element horizontally to x position 200 while changing the height and opacity
10308 el.shift({ x: 200, height: 50, opacity: .8 });
10309
10310 // common config options shown with default values.
10311 el.shift({
10312     width: [element's width],
10313     height: [element's height],
10314     x: [element's x position],
10315     y: [element's y position],
10316     opacity: [element's opacity],
10317     easing: 'easeOut',
10318     duration: .35
10319 });
10320 </code></pre>
10321     * @param {Object} options  Object literal with any of the Fx config options
10322     * @return {Roo.Element} The Element
10323     */
10324     shift : function(o){
10325         var el = this.getFxEl();
10326         o = o || {};
10327         el.queueFx(o, function(){
10328             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10329             if(w !== undefined){
10330                 a.width = {to: this.adjustWidth(w)};
10331             }
10332             if(h !== undefined){
10333                 a.height = {to: this.adjustHeight(h)};
10334             }
10335             if(x !== undefined || y !== undefined){
10336                 a.points = {to: [
10337                     x !== undefined ? x : this.getX(),
10338                     y !== undefined ? y : this.getY()
10339                 ]};
10340             }
10341             if(op !== undefined){
10342                 a.opacity = {to: op};
10343             }
10344             if(o.xy !== undefined){
10345                 a.points = {to: o.xy};
10346             }
10347             arguments.callee.anim = this.fxanim(a,
10348                 o, 'motion', .35, "easeOut", function(){
10349                 el.afterFx(o);
10350             });
10351         });
10352         return this;
10353     },
10354
10355         /**
10356          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10357          * ending point of the effect.
10358          * Usage:
10359          *<pre><code>
10360 // default: slide the element downward while fading out
10361 el.ghost();
10362
10363 // custom: slide the element out to the right with a 2-second duration
10364 el.ghost('r', { duration: 2 });
10365
10366 // common config options shown with default values
10367 el.ghost('b', {
10368     easing: 'easeOut',
10369     duration: .5
10370     remove: false,
10371     useDisplay: false
10372 });
10373 </code></pre>
10374          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10375          * @param {Object} options (optional) Object literal with any of the Fx config options
10376          * @return {Roo.Element} The Element
10377          */
10378     ghost : function(anchor, o){
10379         var el = this.getFxEl();
10380         o = o || {};
10381
10382         el.queueFx(o, function(){
10383             anchor = anchor || "b";
10384
10385             // restore values after effect
10386             var r = this.getFxRestore();
10387             var w = this.getWidth(),
10388                 h = this.getHeight();
10389
10390             var st = this.dom.style;
10391
10392             var after = function(){
10393                 if(o.useDisplay){
10394                     el.setDisplayed(false);
10395                 }else{
10396                     el.hide();
10397                 }
10398
10399                 el.clearOpacity();
10400                 el.setPositioning(r.pos);
10401                 st.width = r.width;
10402                 st.height = r.height;
10403
10404                 el.afterFx(o);
10405             };
10406
10407             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10408             switch(anchor.toLowerCase()){
10409                 case "t":
10410                     pt.by = [0, -h];
10411                 break;
10412                 case "l":
10413                     pt.by = [-w, 0];
10414                 break;
10415                 case "r":
10416                     pt.by = [w, 0];
10417                 break;
10418                 case "b":
10419                     pt.by = [0, h];
10420                 break;
10421                 case "tl":
10422                     pt.by = [-w, -h];
10423                 break;
10424                 case "bl":
10425                     pt.by = [-w, h];
10426                 break;
10427                 case "br":
10428                     pt.by = [w, h];
10429                 break;
10430                 case "tr":
10431                     pt.by = [w, -h];
10432                 break;
10433             }
10434
10435             arguments.callee.anim = this.fxanim(a,
10436                 o,
10437                 'motion',
10438                 .5,
10439                 "easeOut", after);
10440         });
10441         return this;
10442     },
10443
10444         /**
10445          * Ensures that all effects queued after syncFx is called on the element are
10446          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10447          * @return {Roo.Element} The Element
10448          */
10449     syncFx : function(){
10450         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10451             block : false,
10452             concurrent : true,
10453             stopFx : false
10454         });
10455         return this;
10456     },
10457
10458         /**
10459          * Ensures that all effects queued after sequenceFx is called on the element are
10460          * run in sequence.  This is the opposite of {@link #syncFx}.
10461          * @return {Roo.Element} The Element
10462          */
10463     sequenceFx : function(){
10464         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10465             block : false,
10466             concurrent : false,
10467             stopFx : false
10468         });
10469         return this;
10470     },
10471
10472         /* @private */
10473     nextFx : function(){
10474         var ef = this.fxQueue[0];
10475         if(ef){
10476             ef.call(this);
10477         }
10478     },
10479
10480         /**
10481          * Returns true if the element has any effects actively running or queued, else returns false.
10482          * @return {Boolean} True if element has active effects, else false
10483          */
10484     hasActiveFx : function(){
10485         return this.fxQueue && this.fxQueue[0];
10486     },
10487
10488         /**
10489          * Stops any running effects and clears the element's internal effects queue if it contains
10490          * any additional effects that haven't started yet.
10491          * @return {Roo.Element} The Element
10492          */
10493     stopFx : function(){
10494         if(this.hasActiveFx()){
10495             var cur = this.fxQueue[0];
10496             if(cur && cur.anim && cur.anim.isAnimated()){
10497                 this.fxQueue = [cur]; // clear out others
10498                 cur.anim.stop(true);
10499             }
10500         }
10501         return this;
10502     },
10503
10504         /* @private */
10505     beforeFx : function(o){
10506         if(this.hasActiveFx() && !o.concurrent){
10507            if(o.stopFx){
10508                this.stopFx();
10509                return true;
10510            }
10511            return false;
10512         }
10513         return true;
10514     },
10515
10516         /**
10517          * Returns true if the element is currently blocking so that no other effect can be queued
10518          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10519          * used to ensure that an effect initiated by a user action runs to completion prior to the
10520          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10521          * @return {Boolean} True if blocking, else false
10522          */
10523     hasFxBlock : function(){
10524         var q = this.fxQueue;
10525         return q && q[0] && q[0].block;
10526     },
10527
10528         /* @private */
10529     queueFx : function(o, fn){
10530         if(!this.fxQueue){
10531             this.fxQueue = [];
10532         }
10533         if(!this.hasFxBlock()){
10534             Roo.applyIf(o, this.fxDefaults);
10535             if(!o.concurrent){
10536                 var run = this.beforeFx(o);
10537                 fn.block = o.block;
10538                 this.fxQueue.push(fn);
10539                 if(run){
10540                     this.nextFx();
10541                 }
10542             }else{
10543                 fn.call(this);
10544             }
10545         }
10546         return this;
10547     },
10548
10549         /* @private */
10550     fxWrap : function(pos, o, vis){
10551         var wrap;
10552         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10553             var wrapXY;
10554             if(o.fixPosition){
10555                 wrapXY = this.getXY();
10556             }
10557             var div = document.createElement("div");
10558             div.style.visibility = vis;
10559             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10560             wrap.setPositioning(pos);
10561             if(wrap.getStyle("position") == "static"){
10562                 wrap.position("relative");
10563             }
10564             this.clearPositioning('auto');
10565             wrap.clip();
10566             wrap.dom.appendChild(this.dom);
10567             if(wrapXY){
10568                 wrap.setXY(wrapXY);
10569             }
10570         }
10571         return wrap;
10572     },
10573
10574         /* @private */
10575     fxUnwrap : function(wrap, pos, o){
10576         this.clearPositioning();
10577         this.setPositioning(pos);
10578         if(!o.wrap){
10579             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10580             wrap.remove();
10581         }
10582     },
10583
10584         /* @private */
10585     getFxRestore : function(){
10586         var st = this.dom.style;
10587         return {pos: this.getPositioning(), width: st.width, height : st.height};
10588     },
10589
10590         /* @private */
10591     afterFx : function(o){
10592         if(o.afterStyle){
10593             this.applyStyles(o.afterStyle);
10594         }
10595         if(o.afterCls){
10596             this.addClass(o.afterCls);
10597         }
10598         if(o.remove === true){
10599             this.remove();
10600         }
10601         Roo.callback(o.callback, o.scope, [this]);
10602         if(!o.concurrent){
10603             this.fxQueue.shift();
10604             this.nextFx();
10605         }
10606     },
10607
10608         /* @private */
10609     getFxEl : function(){ // support for composite element fx
10610         return Roo.get(this.dom);
10611     },
10612
10613         /* @private */
10614     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10615         animType = animType || 'run';
10616         opt = opt || {};
10617         var anim = Roo.lib.Anim[animType](
10618             this.dom, args,
10619             (opt.duration || defaultDur) || .35,
10620             (opt.easing || defaultEase) || 'easeOut',
10621             function(){
10622                 Roo.callback(cb, this);
10623             },
10624             this
10625         );
10626         opt.anim = anim;
10627         return anim;
10628     }
10629 };
10630
10631 // backwords compat
10632 Roo.Fx.resize = Roo.Fx.scale;
10633
10634 //When included, Roo.Fx is automatically applied to Element so that all basic
10635 //effects are available directly via the Element API
10636 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10637  * Based on:
10638  * Ext JS Library 1.1.1
10639  * Copyright(c) 2006-2007, Ext JS, LLC.
10640  *
10641  * Originally Released Under LGPL - original licence link has changed is not relivant.
10642  *
10643  * Fork - LGPL
10644  * <script type="text/javascript">
10645  */
10646
10647
10648 /**
10649  * @class Roo.CompositeElement
10650  * Standard composite class. Creates a Roo.Element for every element in the collection.
10651  * <br><br>
10652  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10653  * actions will be performed on all the elements in this collection.</b>
10654  * <br><br>
10655  * All methods return <i>this</i> and can be chained.
10656  <pre><code>
10657  var els = Roo.select("#some-el div.some-class", true);
10658  // or select directly from an existing element
10659  var el = Roo.get('some-el');
10660  el.select('div.some-class', true);
10661
10662  els.setWidth(100); // all elements become 100 width
10663  els.hide(true); // all elements fade out and hide
10664  // or
10665  els.setWidth(100).hide(true);
10666  </code></pre>
10667  */
10668 Roo.CompositeElement = function(els){
10669     this.elements = [];
10670     this.addElements(els);
10671 };
10672 Roo.CompositeElement.prototype = {
10673     isComposite: true,
10674     addElements : function(els){
10675         if(!els) return this;
10676         if(typeof els == "string"){
10677             els = Roo.Element.selectorFunction(els);
10678         }
10679         var yels = this.elements;
10680         var index = yels.length-1;
10681         for(var i = 0, len = els.length; i < len; i++) {
10682                 yels[++index] = Roo.get(els[i]);
10683         }
10684         return this;
10685     },
10686
10687     /**
10688     * Clears this composite and adds the elements returned by the passed selector.
10689     * @param {String/Array} els A string CSS selector, an array of elements or an element
10690     * @return {CompositeElement} this
10691     */
10692     fill : function(els){
10693         this.elements = [];
10694         this.add(els);
10695         return this;
10696     },
10697
10698     /**
10699     * Filters this composite to only elements that match the passed selector.
10700     * @param {String} selector A string CSS selector
10701     * @return {CompositeElement} this
10702     */
10703     filter : function(selector){
10704         var els = [];
10705         this.each(function(el){
10706             if(el.is(selector)){
10707                 els[els.length] = el.dom;
10708             }
10709         });
10710         this.fill(els);
10711         return this;
10712     },
10713
10714     invoke : function(fn, args){
10715         var els = this.elements;
10716         for(var i = 0, len = els.length; i < len; i++) {
10717                 Roo.Element.prototype[fn].apply(els[i], args);
10718         }
10719         return this;
10720     },
10721     /**
10722     * Adds elements to this composite.
10723     * @param {String/Array} els A string CSS selector, an array of elements or an element
10724     * @return {CompositeElement} this
10725     */
10726     add : function(els){
10727         if(typeof els == "string"){
10728             this.addElements(Roo.Element.selectorFunction(els));
10729         }else if(els.length !== undefined){
10730             this.addElements(els);
10731         }else{
10732             this.addElements([els]);
10733         }
10734         return this;
10735     },
10736     /**
10737     * Calls the passed function passing (el, this, index) for each element in this composite.
10738     * @param {Function} fn The function to call
10739     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10740     * @return {CompositeElement} this
10741     */
10742     each : function(fn, scope){
10743         var els = this.elements;
10744         for(var i = 0, len = els.length; i < len; i++){
10745             if(fn.call(scope || els[i], els[i], this, i) === false) {
10746                 break;
10747             }
10748         }
10749         return this;
10750     },
10751
10752     /**
10753      * Returns the Element object at the specified index
10754      * @param {Number} index
10755      * @return {Roo.Element}
10756      */
10757     item : function(index){
10758         return this.elements[index] || null;
10759     },
10760
10761     /**
10762      * Returns the first Element
10763      * @return {Roo.Element}
10764      */
10765     first : function(){
10766         return this.item(0);
10767     },
10768
10769     /**
10770      * Returns the last Element
10771      * @return {Roo.Element}
10772      */
10773     last : function(){
10774         return this.item(this.elements.length-1);
10775     },
10776
10777     /**
10778      * Returns the number of elements in this composite
10779      * @return Number
10780      */
10781     getCount : function(){
10782         return this.elements.length;
10783     },
10784
10785     /**
10786      * Returns true if this composite contains the passed element
10787      * @return Boolean
10788      */
10789     contains : function(el){
10790         return this.indexOf(el) !== -1;
10791     },
10792
10793     /**
10794      * Returns true if this composite contains the passed element
10795      * @return Boolean
10796      */
10797     indexOf : function(el){
10798         return this.elements.indexOf(Roo.get(el));
10799     },
10800
10801
10802     /**
10803     * Removes the specified element(s).
10804     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10805     * or an array of any of those.
10806     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10807     * @return {CompositeElement} this
10808     */
10809     removeElement : function(el, removeDom){
10810         if(el instanceof Array){
10811             for(var i = 0, len = el.length; i < len; i++){
10812                 this.removeElement(el[i]);
10813             }
10814             return this;
10815         }
10816         var index = typeof el == 'number' ? el : this.indexOf(el);
10817         if(index !== -1){
10818             if(removeDom){
10819                 var d = this.elements[index];
10820                 if(d.dom){
10821                     d.remove();
10822                 }else{
10823                     d.parentNode.removeChild(d);
10824                 }
10825             }
10826             this.elements.splice(index, 1);
10827         }
10828         return this;
10829     },
10830
10831     /**
10832     * Replaces the specified element with the passed element.
10833     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10834     * to replace.
10835     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10836     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10837     * @return {CompositeElement} this
10838     */
10839     replaceElement : function(el, replacement, domReplace){
10840         var index = typeof el == 'number' ? el : this.indexOf(el);
10841         if(index !== -1){
10842             if(domReplace){
10843                 this.elements[index].replaceWith(replacement);
10844             }else{
10845                 this.elements.splice(index, 1, Roo.get(replacement))
10846             }
10847         }
10848         return this;
10849     },
10850
10851     /**
10852      * Removes all elements.
10853      */
10854     clear : function(){
10855         this.elements = [];
10856     }
10857 };
10858 (function(){
10859     Roo.CompositeElement.createCall = function(proto, fnName){
10860         if(!proto[fnName]){
10861             proto[fnName] = function(){
10862                 return this.invoke(fnName, arguments);
10863             };
10864         }
10865     };
10866     for(var fnName in Roo.Element.prototype){
10867         if(typeof Roo.Element.prototype[fnName] == "function"){
10868             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10869         }
10870     };
10871 })();
10872 /*
10873  * Based on:
10874  * Ext JS Library 1.1.1
10875  * Copyright(c) 2006-2007, Ext JS, LLC.
10876  *
10877  * Originally Released Under LGPL - original licence link has changed is not relivant.
10878  *
10879  * Fork - LGPL
10880  * <script type="text/javascript">
10881  */
10882
10883 /**
10884  * @class Roo.CompositeElementLite
10885  * @extends Roo.CompositeElement
10886  * Flyweight composite class. Reuses the same Roo.Element for element operations.
10887  <pre><code>
10888  var els = Roo.select("#some-el div.some-class");
10889  // or select directly from an existing element
10890  var el = Roo.get('some-el');
10891  el.select('div.some-class');
10892
10893  els.setWidth(100); // all elements become 100 width
10894  els.hide(true); // all elements fade out and hide
10895  // or
10896  els.setWidth(100).hide(true);
10897  </code></pre><br><br>
10898  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10899  * actions will be performed on all the elements in this collection.</b>
10900  */
10901 Roo.CompositeElementLite = function(els){
10902     Roo.CompositeElementLite.superclass.constructor.call(this, els);
10903     this.el = new Roo.Element.Flyweight();
10904 };
10905 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10906     addElements : function(els){
10907         if(els){
10908             if(els instanceof Array){
10909                 this.elements = this.elements.concat(els);
10910             }else{
10911                 var yels = this.elements;
10912                 var index = yels.length-1;
10913                 for(var i = 0, len = els.length; i < len; i++) {
10914                     yels[++index] = els[i];
10915                 }
10916             }
10917         }
10918         return this;
10919     },
10920     invoke : function(fn, args){
10921         var els = this.elements;
10922         var el = this.el;
10923         for(var i = 0, len = els.length; i < len; i++) {
10924             el.dom = els[i];
10925                 Roo.Element.prototype[fn].apply(el, args);
10926         }
10927         return this;
10928     },
10929     /**
10930      * Returns a flyweight Element of the dom element object at the specified index
10931      * @param {Number} index
10932      * @return {Roo.Element}
10933      */
10934     item : function(index){
10935         if(!this.elements[index]){
10936             return null;
10937         }
10938         this.el.dom = this.elements[index];
10939         return this.el;
10940     },
10941
10942     // fixes scope with flyweight
10943     addListener : function(eventName, handler, scope, opt){
10944         var els = this.elements;
10945         for(var i = 0, len = els.length; i < len; i++) {
10946             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10947         }
10948         return this;
10949     },
10950
10951     /**
10952     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10953     * passed is the flyweight (shared) Roo.Element instance, so if you require a
10954     * a reference to the dom node, use el.dom.</b>
10955     * @param {Function} fn The function to call
10956     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10957     * @return {CompositeElement} this
10958     */
10959     each : function(fn, scope){
10960         var els = this.elements;
10961         var el = this.el;
10962         for(var i = 0, len = els.length; i < len; i++){
10963             el.dom = els[i];
10964                 if(fn.call(scope || el, el, this, i) === false){
10965                 break;
10966             }
10967         }
10968         return this;
10969     },
10970
10971     indexOf : function(el){
10972         return this.elements.indexOf(Roo.getDom(el));
10973     },
10974
10975     replaceElement : function(el, replacement, domReplace){
10976         var index = typeof el == 'number' ? el : this.indexOf(el);
10977         if(index !== -1){
10978             replacement = Roo.getDom(replacement);
10979             if(domReplace){
10980                 var d = this.elements[index];
10981                 d.parentNode.insertBefore(replacement, d);
10982                 d.parentNode.removeChild(d);
10983             }
10984             this.elements.splice(index, 1, replacement);
10985         }
10986         return this;
10987     }
10988 });
10989 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10990
10991 /*
10992  * Based on:
10993  * Ext JS Library 1.1.1
10994  * Copyright(c) 2006-2007, Ext JS, LLC.
10995  *
10996  * Originally Released Under LGPL - original licence link has changed is not relivant.
10997  *
10998  * Fork - LGPL
10999  * <script type="text/javascript">
11000  */
11001
11002  
11003
11004 /**
11005  * @class Roo.data.Connection
11006  * @extends Roo.util.Observable
11007  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11008  * either to a configured URL, or to a URL specified at request time.<br><br>
11009  * <p>
11010  * Requests made by this class are asynchronous, and will return immediately. No data from
11011  * the server will be available to the statement immediately following the {@link #request} call.
11012  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11013  * <p>
11014  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11015  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11016  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11017  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11018  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11019  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11020  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11021  * standard DOM methods.
11022  * @constructor
11023  * @param {Object} config a configuration object.
11024  */
11025 Roo.data.Connection = function(config){
11026     Roo.apply(this, config);
11027     this.addEvents({
11028         /**
11029          * @event beforerequest
11030          * Fires before a network request is made to retrieve a data object.
11031          * @param {Connection} conn This Connection object.
11032          * @param {Object} options The options config object passed to the {@link #request} method.
11033          */
11034         "beforerequest" : true,
11035         /**
11036          * @event requestcomplete
11037          * Fires if the request was successfully completed.
11038          * @param {Connection} conn This Connection object.
11039          * @param {Object} response The XHR object containing the response data.
11040          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11041          * @param {Object} options The options config object passed to the {@link #request} method.
11042          */
11043         "requestcomplete" : true,
11044         /**
11045          * @event requestexception
11046          * Fires if an error HTTP status was returned from the server.
11047          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11048          * @param {Connection} conn This Connection object.
11049          * @param {Object} response The XHR object containing the response data.
11050          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11051          * @param {Object} options The options config object passed to the {@link #request} method.
11052          */
11053         "requestexception" : true
11054     });
11055     Roo.data.Connection.superclass.constructor.call(this);
11056 };
11057
11058 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11059     /**
11060      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11061      */
11062     /**
11063      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11064      * extra parameters to each request made by this object. (defaults to undefined)
11065      */
11066     /**
11067      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11068      *  to each request made by this object. (defaults to undefined)
11069      */
11070     /**
11071      * @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)
11072      */
11073     /**
11074      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11075      */
11076     timeout : 30000,
11077     /**
11078      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11079      * @type Boolean
11080      */
11081     autoAbort:false,
11082
11083     /**
11084      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11085      * @type Boolean
11086      */
11087     disableCaching: true,
11088
11089     /**
11090      * Sends an HTTP request to a remote server.
11091      * @param {Object} options An object which may contain the following properties:<ul>
11092      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11093      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11094      * request, a url encoded string or a function to call to get either.</li>
11095      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11096      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11097      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11098      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11099      * <li>options {Object} The parameter to the request call.</li>
11100      * <li>success {Boolean} True if the request succeeded.</li>
11101      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11102      * </ul></li>
11103      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11104      * The callback is passed the following parameters:<ul>
11105      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11106      * <li>options {Object} The parameter to the request call.</li>
11107      * </ul></li>
11108      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11109      * The callback is passed the following parameters:<ul>
11110      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11111      * <li>options {Object} The parameter to the request call.</li>
11112      * </ul></li>
11113      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11114      * for the callback function. Defaults to the browser window.</li>
11115      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11116      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11117      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11118      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11119      * params for the post data. Any params will be appended to the URL.</li>
11120      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11121      * </ul>
11122      * @return {Number} transactionId
11123      */
11124     request : function(o){
11125         if(this.fireEvent("beforerequest", this, o) !== false){
11126             var p = o.params;
11127
11128             if(typeof p == "function"){
11129                 p = p.call(o.scope||window, o);
11130             }
11131             if(typeof p == "object"){
11132                 p = Roo.urlEncode(o.params);
11133             }
11134             if(this.extraParams){
11135                 var extras = Roo.urlEncode(this.extraParams);
11136                 p = p ? (p + '&' + extras) : extras;
11137             }
11138
11139             var url = o.url || this.url;
11140             if(typeof url == 'function'){
11141                 url = url.call(o.scope||window, o);
11142             }
11143
11144             if(o.form){
11145                 var form = Roo.getDom(o.form);
11146                 url = url || form.action;
11147
11148                 var enctype = form.getAttribute("enctype");
11149                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11150                     return this.doFormUpload(o, p, url);
11151                 }
11152                 var f = Roo.lib.Ajax.serializeForm(form);
11153                 p = p ? (p + '&' + f) : f;
11154             }
11155
11156             var hs = o.headers;
11157             if(this.defaultHeaders){
11158                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11159                 if(!o.headers){
11160                     o.headers = hs;
11161                 }
11162             }
11163
11164             var cb = {
11165                 success: this.handleResponse,
11166                 failure: this.handleFailure,
11167                 scope: this,
11168                 argument: {options: o},
11169                 timeout : this.timeout
11170             };
11171
11172             var method = o.method||this.method||(p ? "POST" : "GET");
11173
11174             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11175                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11176             }
11177
11178             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11179                 if(o.autoAbort){
11180                     this.abort();
11181                 }
11182             }else if(this.autoAbort !== false){
11183                 this.abort();
11184             }
11185
11186             if((method == 'GET' && p) || o.xmlData){
11187                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11188                 p = '';
11189             }
11190             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11191             return this.transId;
11192         }else{
11193             Roo.callback(o.callback, o.scope, [o, null, null]);
11194             return null;
11195         }
11196     },
11197
11198     /**
11199      * Determine whether this object has a request outstanding.
11200      * @param {Number} transactionId (Optional) defaults to the last transaction
11201      * @return {Boolean} True if there is an outstanding request.
11202      */
11203     isLoading : function(transId){
11204         if(transId){
11205             return Roo.lib.Ajax.isCallInProgress(transId);
11206         }else{
11207             return this.transId ? true : false;
11208         }
11209     },
11210
11211     /**
11212      * Aborts any outstanding request.
11213      * @param {Number} transactionId (Optional) defaults to the last transaction
11214      */
11215     abort : function(transId){
11216         if(transId || this.isLoading()){
11217             Roo.lib.Ajax.abort(transId || this.transId);
11218         }
11219     },
11220
11221     // private
11222     handleResponse : function(response){
11223         this.transId = false;
11224         var options = response.argument.options;
11225         response.argument = options ? options.argument : null;
11226         this.fireEvent("requestcomplete", this, response, options);
11227         Roo.callback(options.success, options.scope, [response, options]);
11228         Roo.callback(options.callback, options.scope, [options, true, response]);
11229     },
11230
11231     // private
11232     handleFailure : function(response, e){
11233         this.transId = false;
11234         var options = response.argument.options;
11235         response.argument = options ? options.argument : null;
11236         this.fireEvent("requestexception", this, response, options, e);
11237         Roo.callback(options.failure, options.scope, [response, options]);
11238         Roo.callback(options.callback, options.scope, [options, false, response]);
11239     },
11240
11241     // private
11242     doFormUpload : function(o, ps, url){
11243         var id = Roo.id();
11244         var frame = document.createElement('iframe');
11245         frame.id = id;
11246         frame.name = id;
11247         frame.className = 'x-hidden';
11248         if(Roo.isIE){
11249             frame.src = Roo.SSL_SECURE_URL;
11250         }
11251         document.body.appendChild(frame);
11252
11253         if(Roo.isIE){
11254            document.frames[id].name = id;
11255         }
11256
11257         var form = Roo.getDom(o.form);
11258         form.target = id;
11259         form.method = 'POST';
11260         form.enctype = form.encoding = 'multipart/form-data';
11261         if(url){
11262             form.action = url;
11263         }
11264
11265         var hiddens, hd;
11266         if(ps){ // add dynamic params
11267             hiddens = [];
11268             ps = Roo.urlDecode(ps, false);
11269             for(var k in ps){
11270                 if(ps.hasOwnProperty(k)){
11271                     hd = document.createElement('input');
11272                     hd.type = 'hidden';
11273                     hd.name = k;
11274                     hd.value = ps[k];
11275                     form.appendChild(hd);
11276                     hiddens.push(hd);
11277                 }
11278             }
11279         }
11280
11281         function cb(){
11282             var r = {  // bogus response object
11283                 responseText : '',
11284                 responseXML : null
11285             };
11286
11287             r.argument = o ? o.argument : null;
11288
11289             try { //
11290                 var doc;
11291                 if(Roo.isIE){
11292                     doc = frame.contentWindow.document;
11293                 }else {
11294                     doc = (frame.contentDocument || window.frames[id].document);
11295                 }
11296                 if(doc && doc.body){
11297                     r.responseText = doc.body.innerHTML;
11298                 }
11299                 if(doc && doc.XMLDocument){
11300                     r.responseXML = doc.XMLDocument;
11301                 }else {
11302                     r.responseXML = doc;
11303                 }
11304             }
11305             catch(e) {
11306                 // ignore
11307             }
11308
11309             Roo.EventManager.removeListener(frame, 'load', cb, this);
11310
11311             this.fireEvent("requestcomplete", this, r, o);
11312             Roo.callback(o.success, o.scope, [r, o]);
11313             Roo.callback(o.callback, o.scope, [o, true, r]);
11314
11315             setTimeout(function(){document.body.removeChild(frame);}, 100);
11316         }
11317
11318         Roo.EventManager.on(frame, 'load', cb, this);
11319         form.submit();
11320
11321         if(hiddens){ // remove dynamic params
11322             for(var i = 0, len = hiddens.length; i < len; i++){
11323                 form.removeChild(hiddens[i]);
11324             }
11325         }
11326     }
11327 });
11328
11329 /**
11330  * @class Roo.Ajax
11331  * @extends Roo.data.Connection
11332  * Global Ajax request class.
11333  *
11334  * @singleton
11335  */
11336 Roo.Ajax = new Roo.data.Connection({
11337     // fix up the docs
11338    /**
11339      * @cfg {String} url @hide
11340      */
11341     /**
11342      * @cfg {Object} extraParams @hide
11343      */
11344     /**
11345      * @cfg {Object} defaultHeaders @hide
11346      */
11347     /**
11348      * @cfg {String} method (Optional) @hide
11349      */
11350     /**
11351      * @cfg {Number} timeout (Optional) @hide
11352      */
11353     /**
11354      * @cfg {Boolean} autoAbort (Optional) @hide
11355      */
11356
11357     /**
11358      * @cfg {Boolean} disableCaching (Optional) @hide
11359      */
11360
11361     /**
11362      * @property  disableCaching
11363      * True to add a unique cache-buster param to GET requests. (defaults to true)
11364      * @type Boolean
11365      */
11366     /**
11367      * @property  url
11368      * The default URL to be used for requests to the server. (defaults to undefined)
11369      * @type String
11370      */
11371     /**
11372      * @property  extraParams
11373      * An object containing properties which are used as
11374      * extra parameters to each request made by this object. (defaults to undefined)
11375      * @type Object
11376      */
11377     /**
11378      * @property  defaultHeaders
11379      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11380      * @type Object
11381      */
11382     /**
11383      * @property  method
11384      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11385      * @type String
11386      */
11387     /**
11388      * @property  timeout
11389      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11390      * @type Number
11391      */
11392
11393     /**
11394      * @property  autoAbort
11395      * Whether a new request should abort any pending requests. (defaults to false)
11396      * @type Boolean
11397      */
11398     autoAbort : false,
11399
11400     /**
11401      * Serialize the passed form into a url encoded string
11402      * @param {String/HTMLElement} form
11403      * @return {String}
11404      */
11405     serializeForm : function(form){
11406         return Roo.lib.Ajax.serializeForm(form);
11407     }
11408 });/*
11409  * Based on:
11410  * Ext JS Library 1.1.1
11411  * Copyright(c) 2006-2007, Ext JS, LLC.
11412  *
11413  * Originally Released Under LGPL - original licence link has changed is not relivant.
11414  *
11415  * Fork - LGPL
11416  * <script type="text/javascript">
11417  */
11418  
11419 /**
11420  * @class Roo.Ajax
11421  * @extends Roo.data.Connection
11422  * Global Ajax request class.
11423  *
11424  * @instanceOf  Roo.data.Connection
11425  */
11426 Roo.Ajax = new Roo.data.Connection({
11427     // fix up the docs
11428     
11429     /**
11430      * fix up scoping
11431      * @scope Roo.Ajax
11432      */
11433     
11434    /**
11435      * @cfg {String} url @hide
11436      */
11437     /**
11438      * @cfg {Object} extraParams @hide
11439      */
11440     /**
11441      * @cfg {Object} defaultHeaders @hide
11442      */
11443     /**
11444      * @cfg {String} method (Optional) @hide
11445      */
11446     /**
11447      * @cfg {Number} timeout (Optional) @hide
11448      */
11449     /**
11450      * @cfg {Boolean} autoAbort (Optional) @hide
11451      */
11452
11453     /**
11454      * @cfg {Boolean} disableCaching (Optional) @hide
11455      */
11456
11457     /**
11458      * @property  disableCaching
11459      * True to add a unique cache-buster param to GET requests. (defaults to true)
11460      * @type Boolean
11461      */
11462     /**
11463      * @property  url
11464      * The default URL to be used for requests to the server. (defaults to undefined)
11465      * @type String
11466      */
11467     /**
11468      * @property  extraParams
11469      * An object containing properties which are used as
11470      * extra parameters to each request made by this object. (defaults to undefined)
11471      * @type Object
11472      */
11473     /**
11474      * @property  defaultHeaders
11475      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11476      * @type Object
11477      */
11478     /**
11479      * @property  method
11480      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11481      * @type String
11482      */
11483     /**
11484      * @property  timeout
11485      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11486      * @type Number
11487      */
11488
11489     /**
11490      * @property  autoAbort
11491      * Whether a new request should abort any pending requests. (defaults to false)
11492      * @type Boolean
11493      */
11494     autoAbort : false,
11495
11496     /**
11497      * Serialize the passed form into a url encoded string
11498      * @param {String/HTMLElement} form
11499      * @return {String}
11500      */
11501     serializeForm : function(form){
11502         return Roo.lib.Ajax.serializeForm(form);
11503     }
11504 });/*
11505  * Based on:
11506  * Ext JS Library 1.1.1
11507  * Copyright(c) 2006-2007, Ext JS, LLC.
11508  *
11509  * Originally Released Under LGPL - original licence link has changed is not relivant.
11510  *
11511  * Fork - LGPL
11512  * <script type="text/javascript">
11513  */
11514
11515  
11516 /**
11517  * @class Roo.UpdateManager
11518  * @extends Roo.util.Observable
11519  * Provides AJAX-style update for Element object.<br><br>
11520  * Usage:<br>
11521  * <pre><code>
11522  * // Get it from a Roo.Element object
11523  * var el = Roo.get("foo");
11524  * var mgr = el.getUpdateManager();
11525  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11526  * ...
11527  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11528  * <br>
11529  * // or directly (returns the same UpdateManager instance)
11530  * var mgr = new Roo.UpdateManager("myElementId");
11531  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11532  * mgr.on("update", myFcnNeedsToKnow);
11533  * <br>
11534    // short handed call directly from the element object
11535    Roo.get("foo").load({
11536         url: "bar.php",
11537         scripts:true,
11538         params: "for=bar",
11539         text: "Loading Foo..."
11540    });
11541  * </code></pre>
11542  * @constructor
11543  * Create new UpdateManager directly.
11544  * @param {String/HTMLElement/Roo.Element} el The element to update
11545  * @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).
11546  */
11547 Roo.UpdateManager = function(el, forceNew){
11548     el = Roo.get(el);
11549     if(!forceNew && el.updateManager){
11550         return el.updateManager;
11551     }
11552     /**
11553      * The Element object
11554      * @type Roo.Element
11555      */
11556     this.el = el;
11557     /**
11558      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11559      * @type String
11560      */
11561     this.defaultUrl = null;
11562
11563     this.addEvents({
11564         /**
11565          * @event beforeupdate
11566          * Fired before an update is made, return false from your handler and the update is cancelled.
11567          * @param {Roo.Element} el
11568          * @param {String/Object/Function} url
11569          * @param {String/Object} params
11570          */
11571         "beforeupdate": true,
11572         /**
11573          * @event update
11574          * Fired after successful update is made.
11575          * @param {Roo.Element} el
11576          * @param {Object} oResponseObject The response Object
11577          */
11578         "update": true,
11579         /**
11580          * @event failure
11581          * Fired on update failure.
11582          * @param {Roo.Element} el
11583          * @param {Object} oResponseObject The response Object
11584          */
11585         "failure": true
11586     });
11587     var d = Roo.UpdateManager.defaults;
11588     /**
11589      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11590      * @type String
11591      */
11592     this.sslBlankUrl = d.sslBlankUrl;
11593     /**
11594      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11595      * @type Boolean
11596      */
11597     this.disableCaching = d.disableCaching;
11598     /**
11599      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11600      * @type String
11601      */
11602     this.indicatorText = d.indicatorText;
11603     /**
11604      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11605      * @type String
11606      */
11607     this.showLoadIndicator = d.showLoadIndicator;
11608     /**
11609      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11610      * @type Number
11611      */
11612     this.timeout = d.timeout;
11613
11614     /**
11615      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11616      * @type Boolean
11617      */
11618     this.loadScripts = d.loadScripts;
11619
11620     /**
11621      * Transaction object of current executing transaction
11622      */
11623     this.transaction = null;
11624
11625     /**
11626      * @private
11627      */
11628     this.autoRefreshProcId = null;
11629     /**
11630      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11631      * @type Function
11632      */
11633     this.refreshDelegate = this.refresh.createDelegate(this);
11634     /**
11635      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11636      * @type Function
11637      */
11638     this.updateDelegate = this.update.createDelegate(this);
11639     /**
11640      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11641      * @type Function
11642      */
11643     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11644     /**
11645      * @private
11646      */
11647     this.successDelegate = this.processSuccess.createDelegate(this);
11648     /**
11649      * @private
11650      */
11651     this.failureDelegate = this.processFailure.createDelegate(this);
11652
11653     if(!this.renderer){
11654      /**
11655       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11656       */
11657     this.renderer = new Roo.UpdateManager.BasicRenderer();
11658     }
11659     
11660     Roo.UpdateManager.superclass.constructor.call(this);
11661 };
11662
11663 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11664     /**
11665      * Get the Element this UpdateManager is bound to
11666      * @return {Roo.Element} The element
11667      */
11668     getEl : function(){
11669         return this.el;
11670     },
11671     /**
11672      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11673      * @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:
11674 <pre><code>
11675 um.update({<br/>
11676     url: "your-url.php",<br/>
11677     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11678     callback: yourFunction,<br/>
11679     scope: yourObject, //(optional scope)  <br/>
11680     discardUrl: false, <br/>
11681     nocache: false,<br/>
11682     text: "Loading...",<br/>
11683     timeout: 30,<br/>
11684     scripts: false<br/>
11685 });
11686 </code></pre>
11687      * The only required property is url. The optional properties nocache, text and scripts
11688      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11689      * @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}
11690      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11691      * @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.
11692      */
11693     update : function(url, params, callback, discardUrl){
11694         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11695             var method = this.method, cfg;
11696             if(typeof url == "object"){ // must be config object
11697                 cfg = url;
11698                 url = cfg.url;
11699                 params = params || cfg.params;
11700                 callback = callback || cfg.callback;
11701                 discardUrl = discardUrl || cfg.discardUrl;
11702                 if(callback && cfg.scope){
11703                     callback = callback.createDelegate(cfg.scope);
11704                 }
11705                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11706                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11707                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11708                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11709                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11710             }
11711             this.showLoading();
11712             if(!discardUrl){
11713                 this.defaultUrl = url;
11714             }
11715             if(typeof url == "function"){
11716                 url = url.call(this);
11717             }
11718
11719             method = method || (params ? "POST" : "GET");
11720             if(method == "GET"){
11721                 url = this.prepareUrl(url);
11722             }
11723
11724             var o = Roo.apply(cfg ||{}, {
11725                 url : url,
11726                 params: params,
11727                 success: this.successDelegate,
11728                 failure: this.failureDelegate,
11729                 callback: undefined,
11730                 timeout: (this.timeout*1000),
11731                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11732             });
11733
11734             this.transaction = Roo.Ajax.request(o);
11735         }
11736     },
11737
11738     /**
11739      * 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.
11740      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11741      * @param {String/HTMLElement} form The form Id or form element
11742      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11743      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11744      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11745      */
11746     formUpdate : function(form, url, reset, callback){
11747         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11748             if(typeof url == "function"){
11749                 url = url.call(this);
11750             }
11751             form = Roo.getDom(form);
11752             this.transaction = Roo.Ajax.request({
11753                 form: form,
11754                 url:url,
11755                 success: this.successDelegate,
11756                 failure: this.failureDelegate,
11757                 timeout: (this.timeout*1000),
11758                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11759             });
11760             this.showLoading.defer(1, this);
11761         }
11762     },
11763
11764     /**
11765      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11766      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11767      */
11768     refresh : function(callback){
11769         if(this.defaultUrl == null){
11770             return;
11771         }
11772         this.update(this.defaultUrl, null, callback, true);
11773     },
11774
11775     /**
11776      * Set this element to auto refresh.
11777      * @param {Number} interval How often to update (in seconds).
11778      * @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)
11779      * @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}
11780      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11781      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11782      */
11783     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11784         if(refreshNow){
11785             this.update(url || this.defaultUrl, params, callback, true);
11786         }
11787         if(this.autoRefreshProcId){
11788             clearInterval(this.autoRefreshProcId);
11789         }
11790         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11791     },
11792
11793     /**
11794      * Stop auto refresh on this element.
11795      */
11796      stopAutoRefresh : function(){
11797         if(this.autoRefreshProcId){
11798             clearInterval(this.autoRefreshProcId);
11799             delete this.autoRefreshProcId;
11800         }
11801     },
11802
11803     isAutoRefreshing : function(){
11804        return this.autoRefreshProcId ? true : false;
11805     },
11806     /**
11807      * Called to update the element to "Loading" state. Override to perform custom action.
11808      */
11809     showLoading : function(){
11810         if(this.showLoadIndicator){
11811             this.el.update(this.indicatorText);
11812         }
11813     },
11814
11815     /**
11816      * Adds unique parameter to query string if disableCaching = true
11817      * @private
11818      */
11819     prepareUrl : function(url){
11820         if(this.disableCaching){
11821             var append = "_dc=" + (new Date().getTime());
11822             if(url.indexOf("?") !== -1){
11823                 url += "&" + append;
11824             }else{
11825                 url += "?" + append;
11826             }
11827         }
11828         return url;
11829     },
11830
11831     /**
11832      * @private
11833      */
11834     processSuccess : function(response){
11835         this.transaction = null;
11836         if(response.argument.form && response.argument.reset){
11837             try{ // put in try/catch since some older FF releases had problems with this
11838                 response.argument.form.reset();
11839             }catch(e){}
11840         }
11841         if(this.loadScripts){
11842             this.renderer.render(this.el, response, this,
11843                 this.updateComplete.createDelegate(this, [response]));
11844         }else{
11845             this.renderer.render(this.el, response, this);
11846             this.updateComplete(response);
11847         }
11848     },
11849
11850     updateComplete : function(response){
11851         this.fireEvent("update", this.el, response);
11852         if(typeof response.argument.callback == "function"){
11853             response.argument.callback(this.el, true, response);
11854         }
11855     },
11856
11857     /**
11858      * @private
11859      */
11860     processFailure : function(response){
11861         this.transaction = null;
11862         this.fireEvent("failure", this.el, response);
11863         if(typeof response.argument.callback == "function"){
11864             response.argument.callback(this.el, false, response);
11865         }
11866     },
11867
11868     /**
11869      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11870      * @param {Object} renderer The object implementing the render() method
11871      */
11872     setRenderer : function(renderer){
11873         this.renderer = renderer;
11874     },
11875
11876     getRenderer : function(){
11877        return this.renderer;
11878     },
11879
11880     /**
11881      * Set the defaultUrl used for updates
11882      * @param {String/Function} defaultUrl The url or a function to call to get the url
11883      */
11884     setDefaultUrl : function(defaultUrl){
11885         this.defaultUrl = defaultUrl;
11886     },
11887
11888     /**
11889      * Aborts the executing transaction
11890      */
11891     abort : function(){
11892         if(this.transaction){
11893             Roo.Ajax.abort(this.transaction);
11894         }
11895     },
11896
11897     /**
11898      * Returns true if an update is in progress
11899      * @return {Boolean}
11900      */
11901     isUpdating : function(){
11902         if(this.transaction){
11903             return Roo.Ajax.isLoading(this.transaction);
11904         }
11905         return false;
11906     }
11907 });
11908
11909 /**
11910  * @class Roo.UpdateManager.defaults
11911  * @static (not really - but it helps the doc tool)
11912  * The defaults collection enables customizing the default properties of UpdateManager
11913  */
11914    Roo.UpdateManager.defaults = {
11915        /**
11916          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11917          * @type Number
11918          */
11919          timeout : 30,
11920
11921          /**
11922          * True to process scripts by default (Defaults to false).
11923          * @type Boolean
11924          */
11925         loadScripts : false,
11926
11927         /**
11928         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11929         * @type String
11930         */
11931         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11932         /**
11933          * Whether to append unique parameter on get request to disable caching (Defaults to false).
11934          * @type Boolean
11935          */
11936         disableCaching : false,
11937         /**
11938          * Whether to show indicatorText when loading (Defaults to true).
11939          * @type Boolean
11940          */
11941         showLoadIndicator : true,
11942         /**
11943          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11944          * @type String
11945          */
11946         indicatorText : '<div class="loading-indicator">Loading...</div>'
11947    };
11948
11949 /**
11950  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11951  *Usage:
11952  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11953  * @param {String/HTMLElement/Roo.Element} el The element to update
11954  * @param {String} url The url
11955  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11956  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11957  * @static
11958  * @deprecated
11959  * @member Roo.UpdateManager
11960  */
11961 Roo.UpdateManager.updateElement = function(el, url, params, options){
11962     var um = Roo.get(el, true).getUpdateManager();
11963     Roo.apply(um, options);
11964     um.update(url, params, options ? options.callback : null);
11965 };
11966 // alias for backwards compat
11967 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11968 /**
11969  * @class Roo.UpdateManager.BasicRenderer
11970  * Default Content renderer. Updates the elements innerHTML with the responseText.
11971  */
11972 Roo.UpdateManager.BasicRenderer = function(){};
11973
11974 Roo.UpdateManager.BasicRenderer.prototype = {
11975     /**
11976      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11977      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11978      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11979      * @param {Roo.Element} el The element being rendered
11980      * @param {Object} response The YUI Connect response object
11981      * @param {UpdateManager} updateManager The calling update manager
11982      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11983      */
11984      render : function(el, response, updateManager, callback){
11985         el.update(response.responseText, updateManager.loadScripts, callback);
11986     }
11987 };
11988 /*
11989  * Based on:
11990  * Ext JS Library 1.1.1
11991  * Copyright(c) 2006-2007, Ext JS, LLC.
11992  *
11993  * Originally Released Under LGPL - original licence link has changed is not relivant.
11994  *
11995  * Fork - LGPL
11996  * <script type="text/javascript">
11997  */
11998
11999 /**
12000  * @class Roo.util.DelayedTask
12001  * Provides a convenient method of performing setTimeout where a new
12002  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12003  * You can use this class to buffer
12004  * the keypress events for a certain number of milliseconds, and perform only if they stop
12005  * for that amount of time.
12006  * @constructor The parameters to this constructor serve as defaults and are not required.
12007  * @param {Function} fn (optional) The default function to timeout
12008  * @param {Object} scope (optional) The default scope of that timeout
12009  * @param {Array} args (optional) The default Array of arguments
12010  */
12011 Roo.util.DelayedTask = function(fn, scope, args){
12012     var id = null, d, t;
12013
12014     var call = function(){
12015         var now = new Date().getTime();
12016         if(now - t >= d){
12017             clearInterval(id);
12018             id = null;
12019             fn.apply(scope, args || []);
12020         }
12021     };
12022     /**
12023      * Cancels any pending timeout and queues a new one
12024      * @param {Number} delay The milliseconds to delay
12025      * @param {Function} newFn (optional) Overrides function passed to constructor
12026      * @param {Object} newScope (optional) Overrides scope passed to constructor
12027      * @param {Array} newArgs (optional) Overrides args passed to constructor
12028      */
12029     this.delay = function(delay, newFn, newScope, newArgs){
12030         if(id && delay != d){
12031             this.cancel();
12032         }
12033         d = delay;
12034         t = new Date().getTime();
12035         fn = newFn || fn;
12036         scope = newScope || scope;
12037         args = newArgs || args;
12038         if(!id){
12039             id = setInterval(call, d);
12040         }
12041     };
12042
12043     /**
12044      * Cancel the last queued timeout
12045      */
12046     this.cancel = function(){
12047         if(id){
12048             clearInterval(id);
12049             id = null;
12050         }
12051     };
12052 };/*
12053  * Based on:
12054  * Ext JS Library 1.1.1
12055  * Copyright(c) 2006-2007, Ext JS, LLC.
12056  *
12057  * Originally Released Under LGPL - original licence link has changed is not relivant.
12058  *
12059  * Fork - LGPL
12060  * <script type="text/javascript">
12061  */
12062  
12063  
12064 Roo.util.TaskRunner = function(interval){
12065     interval = interval || 10;
12066     var tasks = [], removeQueue = [];
12067     var id = 0;
12068     var running = false;
12069
12070     var stopThread = function(){
12071         running = false;
12072         clearInterval(id);
12073         id = 0;
12074     };
12075
12076     var startThread = function(){
12077         if(!running){
12078             running = true;
12079             id = setInterval(runTasks, interval);
12080         }
12081     };
12082
12083     var removeTask = function(task){
12084         removeQueue.push(task);
12085         if(task.onStop){
12086             task.onStop();
12087         }
12088     };
12089
12090     var runTasks = function(){
12091         if(removeQueue.length > 0){
12092             for(var i = 0, len = removeQueue.length; i < len; i++){
12093                 tasks.remove(removeQueue[i]);
12094             }
12095             removeQueue = [];
12096             if(tasks.length < 1){
12097                 stopThread();
12098                 return;
12099             }
12100         }
12101         var now = new Date().getTime();
12102         for(var i = 0, len = tasks.length; i < len; ++i){
12103             var t = tasks[i];
12104             var itime = now - t.taskRunTime;
12105             if(t.interval <= itime){
12106                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12107                 t.taskRunTime = now;
12108                 if(rt === false || t.taskRunCount === t.repeat){
12109                     removeTask(t);
12110                     return;
12111                 }
12112             }
12113             if(t.duration && t.duration <= (now - t.taskStartTime)){
12114                 removeTask(t);
12115             }
12116         }
12117     };
12118
12119     /**
12120      * Queues a new task.
12121      * @param {Object} task
12122      */
12123     this.start = function(task){
12124         tasks.push(task);
12125         task.taskStartTime = new Date().getTime();
12126         task.taskRunTime = 0;
12127         task.taskRunCount = 0;
12128         startThread();
12129         return task;
12130     };
12131
12132     this.stop = function(task){
12133         removeTask(task);
12134         return task;
12135     };
12136
12137     this.stopAll = function(){
12138         stopThread();
12139         for(var i = 0, len = tasks.length; i < len; i++){
12140             if(tasks[i].onStop){
12141                 tasks[i].onStop();
12142             }
12143         }
12144         tasks = [];
12145         removeQueue = [];
12146     };
12147 };
12148
12149 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12150  * Based on:
12151  * Ext JS Library 1.1.1
12152  * Copyright(c) 2006-2007, Ext JS, LLC.
12153  *
12154  * Originally Released Under LGPL - original licence link has changed is not relivant.
12155  *
12156  * Fork - LGPL
12157  * <script type="text/javascript">
12158  */
12159
12160  
12161 /**
12162  * @class Roo.util.MixedCollection
12163  * @extends Roo.util.Observable
12164  * A Collection class that maintains both numeric indexes and keys and exposes events.
12165  * @constructor
12166  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12167  * collection (defaults to false)
12168  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12169  * and return the key value for that item.  This is used when available to look up the key on items that
12170  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12171  * equivalent to providing an implementation for the {@link #getKey} method.
12172  */
12173 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12174     this.items = [];
12175     this.map = {};
12176     this.keys = [];
12177     this.length = 0;
12178     this.addEvents({
12179         /**
12180          * @event clear
12181          * Fires when the collection is cleared.
12182          */
12183         "clear" : true,
12184         /**
12185          * @event add
12186          * Fires when an item is added to the collection.
12187          * @param {Number} index The index at which the item was added.
12188          * @param {Object} o The item added.
12189          * @param {String} key The key associated with the added item.
12190          */
12191         "add" : true,
12192         /**
12193          * @event replace
12194          * Fires when an item is replaced in the collection.
12195          * @param {String} key he key associated with the new added.
12196          * @param {Object} old The item being replaced.
12197          * @param {Object} new The new item.
12198          */
12199         "replace" : true,
12200         /**
12201          * @event remove
12202          * Fires when an item is removed from the collection.
12203          * @param {Object} o The item being removed.
12204          * @param {String} key (optional) The key associated with the removed item.
12205          */
12206         "remove" : true,
12207         "sort" : true
12208     });
12209     this.allowFunctions = allowFunctions === true;
12210     if(keyFn){
12211         this.getKey = keyFn;
12212     }
12213     Roo.util.MixedCollection.superclass.constructor.call(this);
12214 };
12215
12216 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12217     allowFunctions : false,
12218     
12219 /**
12220  * Adds an item to the collection.
12221  * @param {String} key The key to associate with the item
12222  * @param {Object} o The item to add.
12223  * @return {Object} The item added.
12224  */
12225     add : function(key, o){
12226         if(arguments.length == 1){
12227             o = arguments[0];
12228             key = this.getKey(o);
12229         }
12230         if(typeof key == "undefined" || key === null){
12231             this.length++;
12232             this.items.push(o);
12233             this.keys.push(null);
12234         }else{
12235             var old = this.map[key];
12236             if(old){
12237                 return this.replace(key, o);
12238             }
12239             this.length++;
12240             this.items.push(o);
12241             this.map[key] = o;
12242             this.keys.push(key);
12243         }
12244         this.fireEvent("add", this.length-1, o, key);
12245         return o;
12246     },
12247    
12248 /**
12249   * MixedCollection has a generic way to fetch keys if you implement getKey.
12250 <pre><code>
12251 // normal way
12252 var mc = new Roo.util.MixedCollection();
12253 mc.add(someEl.dom.id, someEl);
12254 mc.add(otherEl.dom.id, otherEl);
12255 //and so on
12256
12257 // using getKey
12258 var mc = new Roo.util.MixedCollection();
12259 mc.getKey = function(el){
12260    return el.dom.id;
12261 };
12262 mc.add(someEl);
12263 mc.add(otherEl);
12264
12265 // or via the constructor
12266 var mc = new Roo.util.MixedCollection(false, function(el){
12267    return el.dom.id;
12268 });
12269 mc.add(someEl);
12270 mc.add(otherEl);
12271 </code></pre>
12272  * @param o {Object} The item for which to find the key.
12273  * @return {Object} The key for the passed item.
12274  */
12275     getKey : function(o){
12276          return o.id; 
12277     },
12278    
12279 /**
12280  * Replaces an item in the collection.
12281  * @param {String} key The key associated with the item to replace, or the item to replace.
12282  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12283  * @return {Object}  The new item.
12284  */
12285     replace : function(key, o){
12286         if(arguments.length == 1){
12287             o = arguments[0];
12288             key = this.getKey(o);
12289         }
12290         var old = this.item(key);
12291         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12292              return this.add(key, o);
12293         }
12294         var index = this.indexOfKey(key);
12295         this.items[index] = o;
12296         this.map[key] = o;
12297         this.fireEvent("replace", key, old, o);
12298         return o;
12299     },
12300    
12301 /**
12302  * Adds all elements of an Array or an Object to the collection.
12303  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12304  * an Array of values, each of which are added to the collection.
12305  */
12306     addAll : function(objs){
12307         if(arguments.length > 1 || objs instanceof Array){
12308             var args = arguments.length > 1 ? arguments : objs;
12309             for(var i = 0, len = args.length; i < len; i++){
12310                 this.add(args[i]);
12311             }
12312         }else{
12313             for(var key in objs){
12314                 if(this.allowFunctions || typeof objs[key] != "function"){
12315                     this.add(key, objs[key]);
12316                 }
12317             }
12318         }
12319     },
12320    
12321 /**
12322  * Executes the specified function once for every item in the collection, passing each
12323  * item as the first and only parameter. returning false from the function will stop the iteration.
12324  * @param {Function} fn The function to execute for each item.
12325  * @param {Object} scope (optional) The scope in which to execute the function.
12326  */
12327     each : function(fn, scope){
12328         var items = [].concat(this.items); // each safe for removal
12329         for(var i = 0, len = items.length; i < len; i++){
12330             if(fn.call(scope || items[i], items[i], i, len) === false){
12331                 break;
12332             }
12333         }
12334     },
12335    
12336 /**
12337  * Executes the specified function once for every key in the collection, passing each
12338  * key, and its associated item as the first two parameters.
12339  * @param {Function} fn The function to execute for each item.
12340  * @param {Object} scope (optional) The scope in which to execute the function.
12341  */
12342     eachKey : function(fn, scope){
12343         for(var i = 0, len = this.keys.length; i < len; i++){
12344             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12345         }
12346     },
12347    
12348 /**
12349  * Returns the first item in the collection which elicits a true return value from the
12350  * passed selection function.
12351  * @param {Function} fn The selection function to execute for each item.
12352  * @param {Object} scope (optional) The scope in which to execute the function.
12353  * @return {Object} The first item in the collection which returned true from the selection function.
12354  */
12355     find : function(fn, scope){
12356         for(var i = 0, len = this.items.length; i < len; i++){
12357             if(fn.call(scope || window, this.items[i], this.keys[i])){
12358                 return this.items[i];
12359             }
12360         }
12361         return null;
12362     },
12363    
12364 /**
12365  * Inserts an item at the specified index in the collection.
12366  * @param {Number} index The index to insert the item at.
12367  * @param {String} key The key to associate with the new item, or the item itself.
12368  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12369  * @return {Object} The item inserted.
12370  */
12371     insert : function(index, key, o){
12372         if(arguments.length == 2){
12373             o = arguments[1];
12374             key = this.getKey(o);
12375         }
12376         if(index >= this.length){
12377             return this.add(key, o);
12378         }
12379         this.length++;
12380         this.items.splice(index, 0, o);
12381         if(typeof key != "undefined" && key != null){
12382             this.map[key] = o;
12383         }
12384         this.keys.splice(index, 0, key);
12385         this.fireEvent("add", index, o, key);
12386         return o;
12387     },
12388    
12389 /**
12390  * Removed an item from the collection.
12391  * @param {Object} o The item to remove.
12392  * @return {Object} The item removed.
12393  */
12394     remove : function(o){
12395         return this.removeAt(this.indexOf(o));
12396     },
12397    
12398 /**
12399  * Remove an item from a specified index in the collection.
12400  * @param {Number} index The index within the collection of the item to remove.
12401  */
12402     removeAt : function(index){
12403         if(index < this.length && index >= 0){
12404             this.length--;
12405             var o = this.items[index];
12406             this.items.splice(index, 1);
12407             var key = this.keys[index];
12408             if(typeof key != "undefined"){
12409                 delete this.map[key];
12410             }
12411             this.keys.splice(index, 1);
12412             this.fireEvent("remove", o, key);
12413         }
12414     },
12415    
12416 /**
12417  * Removed an item associated with the passed key fom the collection.
12418  * @param {String} key The key of the item to remove.
12419  */
12420     removeKey : function(key){
12421         return this.removeAt(this.indexOfKey(key));
12422     },
12423    
12424 /**
12425  * Returns the number of items in the collection.
12426  * @return {Number} the number of items in the collection.
12427  */
12428     getCount : function(){
12429         return this.length; 
12430     },
12431    
12432 /**
12433  * Returns index within the collection of the passed Object.
12434  * @param {Object} o The item to find the index of.
12435  * @return {Number} index of the item.
12436  */
12437     indexOf : function(o){
12438         if(!this.items.indexOf){
12439             for(var i = 0, len = this.items.length; i < len; i++){
12440                 if(this.items[i] == o) return i;
12441             }
12442             return -1;
12443         }else{
12444             return this.items.indexOf(o);
12445         }
12446     },
12447    
12448 /**
12449  * Returns index within the collection of the passed key.
12450  * @param {String} key The key to find the index of.
12451  * @return {Number} index of the key.
12452  */
12453     indexOfKey : function(key){
12454         if(!this.keys.indexOf){
12455             for(var i = 0, len = this.keys.length; i < len; i++){
12456                 if(this.keys[i] == key) return i;
12457             }
12458             return -1;
12459         }else{
12460             return this.keys.indexOf(key);
12461         }
12462     },
12463    
12464 /**
12465  * Returns the item associated with the passed key OR index. Key has priority over index.
12466  * @param {String/Number} key The key or index of the item.
12467  * @return {Object} The item associated with the passed key.
12468  */
12469     item : function(key){
12470         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12471         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12472     },
12473     
12474 /**
12475  * Returns the item at the specified index.
12476  * @param {Number} index The index of the item.
12477  * @return {Object}
12478  */
12479     itemAt : function(index){
12480         return this.items[index];
12481     },
12482     
12483 /**
12484  * Returns the item associated with the passed key.
12485  * @param {String/Number} key The key of the item.
12486  * @return {Object} The item associated with the passed key.
12487  */
12488     key : function(key){
12489         return this.map[key];
12490     },
12491    
12492 /**
12493  * Returns true if the collection contains the passed Object as an item.
12494  * @param {Object} o  The Object to look for in the collection.
12495  * @return {Boolean} True if the collection contains the Object as an item.
12496  */
12497     contains : function(o){
12498         return this.indexOf(o) != -1;
12499     },
12500    
12501 /**
12502  * Returns true if the collection contains the passed Object as a key.
12503  * @param {String} key The key to look for in the collection.
12504  * @return {Boolean} True if the collection contains the Object as a key.
12505  */
12506     containsKey : function(key){
12507         return typeof this.map[key] != "undefined";
12508     },
12509    
12510 /**
12511  * Removes all items from the collection.
12512  */
12513     clear : function(){
12514         this.length = 0;
12515         this.items = [];
12516         this.keys = [];
12517         this.map = {};
12518         this.fireEvent("clear");
12519     },
12520    
12521 /**
12522  * Returns the first item in the collection.
12523  * @return {Object} the first item in the collection..
12524  */
12525     first : function(){
12526         return this.items[0]; 
12527     },
12528    
12529 /**
12530  * Returns the last item in the collection.
12531  * @return {Object} the last item in the collection..
12532  */
12533     last : function(){
12534         return this.items[this.length-1];   
12535     },
12536     
12537     _sort : function(property, dir, fn){
12538         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12539         fn = fn || function(a, b){
12540             return a-b;
12541         };
12542         var c = [], k = this.keys, items = this.items;
12543         for(var i = 0, len = items.length; i < len; i++){
12544             c[c.length] = {key: k[i], value: items[i], index: i};
12545         }
12546         c.sort(function(a, b){
12547             var v = fn(a[property], b[property]) * dsc;
12548             if(v == 0){
12549                 v = (a.index < b.index ? -1 : 1);
12550             }
12551             return v;
12552         });
12553         for(var i = 0, len = c.length; i < len; i++){
12554             items[i] = c[i].value;
12555             k[i] = c[i].key;
12556         }
12557         this.fireEvent("sort", this);
12558     },
12559     
12560     /**
12561      * Sorts this collection with the passed comparison function
12562      * @param {String} direction (optional) "ASC" or "DESC"
12563      * @param {Function} fn (optional) comparison function
12564      */
12565     sort : function(dir, fn){
12566         this._sort("value", dir, fn);
12567     },
12568     
12569     /**
12570      * Sorts this collection by keys
12571      * @param {String} direction (optional) "ASC" or "DESC"
12572      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12573      */
12574     keySort : function(dir, fn){
12575         this._sort("key", dir, fn || function(a, b){
12576             return String(a).toUpperCase()-String(b).toUpperCase();
12577         });
12578     },
12579     
12580     /**
12581      * Returns a range of items in this collection
12582      * @param {Number} startIndex (optional) defaults to 0
12583      * @param {Number} endIndex (optional) default to the last item
12584      * @return {Array} An array of items
12585      */
12586     getRange : function(start, end){
12587         var items = this.items;
12588         if(items.length < 1){
12589             return [];
12590         }
12591         start = start || 0;
12592         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12593         var r = [];
12594         if(start <= end){
12595             for(var i = start; i <= end; i++) {
12596                     r[r.length] = items[i];
12597             }
12598         }else{
12599             for(var i = start; i >= end; i--) {
12600                     r[r.length] = items[i];
12601             }
12602         }
12603         return r;
12604     },
12605         
12606     /**
12607      * Filter the <i>objects</i> in this collection by a specific property. 
12608      * Returns a new collection that has been filtered.
12609      * @param {String} property A property on your objects
12610      * @param {String/RegExp} value Either string that the property values 
12611      * should start with or a RegExp to test against the property
12612      * @return {MixedCollection} The new filtered collection
12613      */
12614     filter : function(property, value){
12615         if(!value.exec){ // not a regex
12616             value = String(value);
12617             if(value.length == 0){
12618                 return this.clone();
12619             }
12620             value = new RegExp("^" + Roo.escapeRe(value), "i");
12621         }
12622         return this.filterBy(function(o){
12623             return o && value.test(o[property]);
12624         });
12625         },
12626     
12627     /**
12628      * Filter by a function. * Returns a new collection that has been filtered.
12629      * The passed function will be called with each 
12630      * object in the collection. If the function returns true, the value is included 
12631      * otherwise it is filtered.
12632      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12633      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12634      * @return {MixedCollection} The new filtered collection
12635      */
12636     filterBy : function(fn, scope){
12637         var r = new Roo.util.MixedCollection();
12638         r.getKey = this.getKey;
12639         var k = this.keys, it = this.items;
12640         for(var i = 0, len = it.length; i < len; i++){
12641             if(fn.call(scope||this, it[i], k[i])){
12642                                 r.add(k[i], it[i]);
12643                         }
12644         }
12645         return r;
12646     },
12647     
12648     /**
12649      * Creates a duplicate of this collection
12650      * @return {MixedCollection}
12651      */
12652     clone : function(){
12653         var r = new Roo.util.MixedCollection();
12654         var k = this.keys, it = this.items;
12655         for(var i = 0, len = it.length; i < len; i++){
12656             r.add(k[i], it[i]);
12657         }
12658         r.getKey = this.getKey;
12659         return r;
12660     }
12661 });
12662 /**
12663  * Returns the item associated with the passed key or index.
12664  * @method
12665  * @param {String/Number} key The key or index of the item.
12666  * @return {Object} The item associated with the passed key.
12667  */
12668 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12669  * Based on:
12670  * Ext JS Library 1.1.1
12671  * Copyright(c) 2006-2007, Ext JS, LLC.
12672  *
12673  * Originally Released Under LGPL - original licence link has changed is not relivant.
12674  *
12675  * Fork - LGPL
12676  * <script type="text/javascript">
12677  */
12678 /**
12679  * @class Roo.util.JSON
12680  * Modified version of Douglas Crockford"s json.js that doesn"t
12681  * mess with the Object prototype 
12682  * http://www.json.org/js.html
12683  * @singleton
12684  */
12685 Roo.util.JSON = new (function(){
12686     var useHasOwn = {}.hasOwnProperty ? true : false;
12687     
12688     // crashes Safari in some instances
12689     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12690     
12691     var pad = function(n) {
12692         return n < 10 ? "0" + n : n;
12693     };
12694     
12695     var m = {
12696         "\b": '\\b',
12697         "\t": '\\t',
12698         "\n": '\\n',
12699         "\f": '\\f',
12700         "\r": '\\r',
12701         '"' : '\\"',
12702         "\\": '\\\\'
12703     };
12704
12705     var encodeString = function(s){
12706         if (/["\\\x00-\x1f]/.test(s)) {
12707             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12708                 var c = m[b];
12709                 if(c){
12710                     return c;
12711                 }
12712                 c = b.charCodeAt();
12713                 return "\\u00" +
12714                     Math.floor(c / 16).toString(16) +
12715                     (c % 16).toString(16);
12716             }) + '"';
12717         }
12718         return '"' + s + '"';
12719     };
12720     
12721     var encodeArray = function(o){
12722         var a = ["["], b, i, l = o.length, v;
12723             for (i = 0; i < l; i += 1) {
12724                 v = o[i];
12725                 switch (typeof v) {
12726                     case "undefined":
12727                     case "function":
12728                     case "unknown":
12729                         break;
12730                     default:
12731                         if (b) {
12732                             a.push(',');
12733                         }
12734                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12735                         b = true;
12736                 }
12737             }
12738             a.push("]");
12739             return a.join("");
12740     };
12741     
12742     var encodeDate = function(o){
12743         return '"' + o.getFullYear() + "-" +
12744                 pad(o.getMonth() + 1) + "-" +
12745                 pad(o.getDate()) + "T" +
12746                 pad(o.getHours()) + ":" +
12747                 pad(o.getMinutes()) + ":" +
12748                 pad(o.getSeconds()) + '"';
12749     };
12750     
12751     /**
12752      * Encodes an Object, Array or other value
12753      * @param {Mixed} o The variable to encode
12754      * @return {String} The JSON string
12755      */
12756     this.encode = function(o){
12757         if(typeof o == "undefined" || o === null){
12758             return "null";
12759         }else if(o instanceof Array){
12760             return encodeArray(o);
12761         }else if(o instanceof Date){
12762             return encodeDate(o);
12763         }else if(typeof o == "string"){
12764             return encodeString(o);
12765         }else if(typeof o == "number"){
12766             return isFinite(o) ? String(o) : "null";
12767         }else if(typeof o == "boolean"){
12768             return String(o);
12769         }else {
12770             var a = ["{"], b, i, v;
12771             for (i in o) {
12772                 if(!useHasOwn || o.hasOwnProperty(i)) {
12773                     v = o[i];
12774                     switch (typeof v) {
12775                     case "undefined":
12776                     case "function":
12777                     case "unknown":
12778                         break;
12779                     default:
12780                         if(b){
12781                             a.push(',');
12782                         }
12783                         a.push(this.encode(i), ":",
12784                                 v === null ? "null" : this.encode(v));
12785                         b = true;
12786                     }
12787                 }
12788             }
12789             a.push("}");
12790             return a.join("");
12791         }
12792     };
12793     
12794     /**
12795      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12796      * @param {String} json The JSON string
12797      * @return {Object} The resulting object
12798      */
12799     this.decode = function(json){
12800         /**
12801          * eval:var:json
12802          */
12803         return eval("(" + json + ')');
12804     };
12805 })();
12806 /** 
12807  * Shorthand for {@link Roo.util.JSON#encode}
12808  * @member Roo encode 
12809  * @method */
12810 Roo.encode = Roo.util.JSON.encode;
12811 /** 
12812  * Shorthand for {@link Roo.util.JSON#decode}
12813  * @member Roo decode 
12814  * @method */
12815 Roo.decode = Roo.util.JSON.decode;
12816 /*
12817  * Based on:
12818  * Ext JS Library 1.1.1
12819  * Copyright(c) 2006-2007, Ext JS, LLC.
12820  *
12821  * Originally Released Under LGPL - original licence link has changed is not relivant.
12822  *
12823  * Fork - LGPL
12824  * <script type="text/javascript">
12825  */
12826  
12827 /**
12828  * @class Roo.util.Format
12829  * Reusable data formatting functions
12830  * @singleton
12831  */
12832 Roo.util.Format = function(){
12833     var trimRe = /^\s+|\s+$/g;
12834     return {
12835         /**
12836          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12837          * @param {String} value The string to truncate
12838          * @param {Number} length The maximum length to allow before truncating
12839          * @return {String} The converted text
12840          */
12841         ellipsis : function(value, len){
12842             if(value && value.length > len){
12843                 return value.substr(0, len-3)+"...";
12844             }
12845             return value;
12846         },
12847
12848         /**
12849          * Checks a reference and converts it to empty string if it is undefined
12850          * @param {Mixed} value Reference to check
12851          * @return {Mixed} Empty string if converted, otherwise the original value
12852          */
12853         undef : function(value){
12854             return typeof value != "undefined" ? value : "";
12855         },
12856
12857         /**
12858          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12859          * @param {String} value The string to encode
12860          * @return {String} The encoded text
12861          */
12862         htmlEncode : function(value){
12863             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12864         },
12865
12866         /**
12867          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12868          * @param {String} value The string to decode
12869          * @return {String} The decoded text
12870          */
12871         htmlDecode : function(value){
12872             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12873         },
12874
12875         /**
12876          * Trims any whitespace from either side of a string
12877          * @param {String} value The text to trim
12878          * @return {String} The trimmed text
12879          */
12880         trim : function(value){
12881             return String(value).replace(trimRe, "");
12882         },
12883
12884         /**
12885          * Returns a substring from within an original string
12886          * @param {String} value The original text
12887          * @param {Number} start The start index of the substring
12888          * @param {Number} length The length of the substring
12889          * @return {String} The substring
12890          */
12891         substr : function(value, start, length){
12892             return String(value).substr(start, length);
12893         },
12894
12895         /**
12896          * Converts a string to all lower case letters
12897          * @param {String} value The text to convert
12898          * @return {String} The converted text
12899          */
12900         lowercase : function(value){
12901             return String(value).toLowerCase();
12902         },
12903
12904         /**
12905          * Converts a string to all upper case letters
12906          * @param {String} value The text to convert
12907          * @return {String} The converted text
12908          */
12909         uppercase : function(value){
12910             return String(value).toUpperCase();
12911         },
12912
12913         /**
12914          * Converts the first character only of a string to upper case
12915          * @param {String} value The text to convert
12916          * @return {String} The converted text
12917          */
12918         capitalize : function(value){
12919             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12920         },
12921
12922         // private
12923         call : function(value, fn){
12924             if(arguments.length > 2){
12925                 var args = Array.prototype.slice.call(arguments, 2);
12926                 args.unshift(value);
12927                  
12928                 return /** eval:var:value */  eval(fn).apply(window, args);
12929             }else{
12930                 /** eval:var:value */
12931                 return /** eval:var:value */ eval(fn).call(window, value);
12932             }
12933         },
12934
12935         /**
12936          * Format a number as US currency
12937          * @param {Number/String} value The numeric value to format
12938          * @return {String} The formatted currency string
12939          */
12940         usMoney : function(v){
12941             v = (Math.round((v-0)*100))/100;
12942             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12943             v = String(v);
12944             var ps = v.split('.');
12945             var whole = ps[0];
12946             var sub = ps[1] ? '.'+ ps[1] : '.00';
12947             var r = /(\d+)(\d{3})/;
12948             while (r.test(whole)) {
12949                 whole = whole.replace(r, '$1' + ',' + '$2');
12950             }
12951             return "$" + whole + sub ;
12952         },
12953
12954         /**
12955          * Parse a value into a formatted date using the specified format pattern.
12956          * @param {Mixed} value The value to format
12957          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12958          * @return {String} The formatted date string
12959          */
12960         date : function(v, format){
12961             if(!v){
12962                 return "";
12963             }
12964             if(!(v instanceof Date)){
12965                 v = new Date(Date.parse(v));
12966             }
12967             return v.dateFormat(format || "m/d/Y");
12968         },
12969
12970         /**
12971          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12972          * @param {String} format Any valid date format string
12973          * @return {Function} The date formatting function
12974          */
12975         dateRenderer : function(format){
12976             return function(v){
12977                 return Roo.util.Format.date(v, format);  
12978             };
12979         },
12980
12981         // private
12982         stripTagsRE : /<\/?[^>]+>/gi,
12983         
12984         /**
12985          * Strips all HTML tags
12986          * @param {Mixed} value The text from which to strip tags
12987          * @return {String} The stripped text
12988          */
12989         stripTags : function(v){
12990             return !v ? v : String(v).replace(this.stripTagsRE, "");
12991         }
12992     };
12993 }();/*
12994  * Based on:
12995  * Ext JS Library 1.1.1
12996  * Copyright(c) 2006-2007, Ext JS, LLC.
12997  *
12998  * Originally Released Under LGPL - original licence link has changed is not relivant.
12999  *
13000  * Fork - LGPL
13001  * <script type="text/javascript">
13002  */
13003
13004
13005  
13006
13007 /**
13008  * @class Roo.MasterTemplate
13009  * @extends Roo.Template
13010  * Provides a template that can have child templates. The syntax is:
13011 <pre><code>
13012 var t = new Roo.MasterTemplate(
13013         '&lt;select name="{name}"&gt;',
13014                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13015         '&lt;/select&gt;'
13016 );
13017 t.add('options', {value: 'foo', text: 'bar'});
13018 // or you can add multiple child elements in one shot
13019 t.addAll('options', [
13020     {value: 'foo', text: 'bar'},
13021     {value: 'foo2', text: 'bar2'},
13022     {value: 'foo3', text: 'bar3'}
13023 ]);
13024 // then append, applying the master template values
13025 t.append('my-form', {name: 'my-select'});
13026 </code></pre>
13027 * A name attribute for the child template is not required if you have only one child
13028 * template or you want to refer to them by index.
13029  */
13030 Roo.MasterTemplate = function(){
13031     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13032     this.originalHtml = this.html;
13033     var st = {};
13034     var m, re = this.subTemplateRe;
13035     re.lastIndex = 0;
13036     var subIndex = 0;
13037     while(m = re.exec(this.html)){
13038         var name = m[1], content = m[2];
13039         st[subIndex] = {
13040             name: name,
13041             index: subIndex,
13042             buffer: [],
13043             tpl : new Roo.Template(content)
13044         };
13045         if(name){
13046             st[name] = st[subIndex];
13047         }
13048         st[subIndex].tpl.compile();
13049         st[subIndex].tpl.call = this.call.createDelegate(this);
13050         subIndex++;
13051     }
13052     this.subCount = subIndex;
13053     this.subs = st;
13054 };
13055 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13056     /**
13057     * The regular expression used to match sub templates
13058     * @type RegExp
13059     * @property
13060     */
13061     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13062
13063     /**
13064      * Applies the passed values to a child template.
13065      * @param {String/Number} name (optional) The name or index of the child template
13066      * @param {Array/Object} values The values to be applied to the template
13067      * @return {MasterTemplate} this
13068      */
13069      add : function(name, values){
13070         if(arguments.length == 1){
13071             values = arguments[0];
13072             name = 0;
13073         }
13074         var s = this.subs[name];
13075         s.buffer[s.buffer.length] = s.tpl.apply(values);
13076         return this;
13077     },
13078
13079     /**
13080      * Applies all the passed values to a child template.
13081      * @param {String/Number} name (optional) The name or index of the child template
13082      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13083      * @param {Boolean} reset (optional) True to reset the template first
13084      * @return {MasterTemplate} this
13085      */
13086     fill : function(name, values, reset){
13087         var a = arguments;
13088         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13089             values = a[0];
13090             name = 0;
13091             reset = a[1];
13092         }
13093         if(reset){
13094             this.reset();
13095         }
13096         for(var i = 0, len = values.length; i < len; i++){
13097             this.add(name, values[i]);
13098         }
13099         return this;
13100     },
13101
13102     /**
13103      * Resets the template for reuse
13104      * @return {MasterTemplate} this
13105      */
13106      reset : function(){
13107         var s = this.subs;
13108         for(var i = 0; i < this.subCount; i++){
13109             s[i].buffer = [];
13110         }
13111         return this;
13112     },
13113
13114     applyTemplate : function(values){
13115         var s = this.subs;
13116         var replaceIndex = -1;
13117         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13118             return s[++replaceIndex].buffer.join("");
13119         });
13120         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13121     },
13122
13123     apply : function(){
13124         return this.applyTemplate.apply(this, arguments);
13125     },
13126
13127     compile : function(){return this;}
13128 });
13129
13130 /**
13131  * Alias for fill().
13132  * @method
13133  */
13134 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13135  /**
13136  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13137  * var tpl = Roo.MasterTemplate.from('element-id');
13138  * @param {String/HTMLElement} el
13139  * @param {Object} config
13140  * @static
13141  */
13142 Roo.MasterTemplate.from = function(el, config){
13143     el = Roo.getDom(el);
13144     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13145 };/*
13146  * Based on:
13147  * Ext JS Library 1.1.1
13148  * Copyright(c) 2006-2007, Ext JS, LLC.
13149  *
13150  * Originally Released Under LGPL - original licence link has changed is not relivant.
13151  *
13152  * Fork - LGPL
13153  * <script type="text/javascript">
13154  */
13155
13156  
13157 /**
13158  * @class Roo.util.CSS
13159  * Utility class for manipulating CSS rules
13160  * @singleton
13161  */
13162 Roo.util.CSS = function(){
13163         var rules = null;
13164         var doc = document;
13165
13166     var camelRe = /(-[a-z])/gi;
13167     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13168
13169    return {
13170    /**
13171     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13172     * tag and appended to the HEAD of the document.
13173     * @param {String} cssText The text containing the css rules
13174     * @param {String} id An id to add to the stylesheet for later removal
13175     * @return {StyleSheet}
13176     */
13177    createStyleSheet : function(cssText, id){
13178        var ss;
13179        var head = doc.getElementsByTagName("head")[0];
13180        var rules = doc.createElement("style");
13181        rules.setAttribute("type", "text/css");
13182        if(id){
13183            rules.setAttribute("id", id);
13184        }
13185        if(Roo.isIE){
13186            head.appendChild(rules);
13187            ss = rules.styleSheet;
13188            ss.cssText = cssText;
13189        }else{
13190            try{
13191                 rules.appendChild(doc.createTextNode(cssText));
13192            }catch(e){
13193                rules.cssText = cssText; 
13194            }
13195            head.appendChild(rules);
13196            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13197        }
13198        this.cacheStyleSheet(ss);
13199        return ss;
13200    },
13201
13202    /**
13203     * Removes a style or link tag by id
13204     * @param {String} id The id of the tag
13205     */
13206    removeStyleSheet : function(id){
13207        var existing = doc.getElementById(id);
13208        if(existing){
13209            existing.parentNode.removeChild(existing);
13210        }
13211    },
13212
13213    /**
13214     * Dynamically swaps an existing stylesheet reference for a new one
13215     * @param {String} id The id of an existing link tag to remove
13216     * @param {String} url The href of the new stylesheet to include
13217     */
13218    swapStyleSheet : function(id, url){
13219        this.removeStyleSheet(id);
13220        var ss = doc.createElement("link");
13221        ss.setAttribute("rel", "stylesheet");
13222        ss.setAttribute("type", "text/css");
13223        ss.setAttribute("id", id);
13224        ss.setAttribute("href", url);
13225        doc.getElementsByTagName("head")[0].appendChild(ss);
13226    },
13227    
13228    /**
13229     * Refresh the rule cache if you have dynamically added stylesheets
13230     * @return {Object} An object (hash) of rules indexed by selector
13231     */
13232    refreshCache : function(){
13233        return this.getRules(true);
13234    },
13235
13236    // private
13237    cacheStyleSheet : function(ss){
13238        if(!rules){
13239            rules = {};
13240        }
13241        try{// try catch for cross domain access issue
13242            var ssRules = ss.cssRules || ss.rules;
13243            for(var j = ssRules.length-1; j >= 0; --j){
13244                rules[ssRules[j].selectorText] = ssRules[j];
13245            }
13246        }catch(e){}
13247    },
13248    
13249    /**
13250     * Gets all css rules for the document
13251     * @param {Boolean} refreshCache true to refresh the internal cache
13252     * @return {Object} An object (hash) of rules indexed by selector
13253     */
13254    getRules : function(refreshCache){
13255                 if(rules == null || refreshCache){
13256                         rules = {};
13257                         var ds = doc.styleSheets;
13258                         for(var i =0, len = ds.length; i < len; i++){
13259                             try{
13260                         this.cacheStyleSheet(ds[i]);
13261                     }catch(e){} 
13262                 }
13263                 }
13264                 return rules;
13265         },
13266         
13267         /**
13268     * Gets an an individual CSS rule by selector(s)
13269     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13270     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13271     * @return {CSSRule} The CSS rule or null if one is not found
13272     */
13273    getRule : function(selector, refreshCache){
13274                 var rs = this.getRules(refreshCache);
13275                 if(!(selector instanceof Array)){
13276                     return rs[selector];
13277                 }
13278                 for(var i = 0; i < selector.length; i++){
13279                         if(rs[selector[i]]){
13280                                 return rs[selector[i]];
13281                         }
13282                 }
13283                 return null;
13284         },
13285         
13286         
13287         /**
13288     * Updates a rule property
13289     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13290     * @param {String} property The css property
13291     * @param {String} value The new value for the property
13292     * @return {Boolean} true If a rule was found and updated
13293     */
13294    updateRule : function(selector, property, value){
13295                 if(!(selector instanceof Array)){
13296                         var rule = this.getRule(selector);
13297                         if(rule){
13298                                 rule.style[property.replace(camelRe, camelFn)] = value;
13299                                 return true;
13300                         }
13301                 }else{
13302                         for(var i = 0; i < selector.length; i++){
13303                                 if(this.updateRule(selector[i], property, value)){
13304                                         return true;
13305                                 }
13306                         }
13307                 }
13308                 return false;
13309         }
13310    };   
13311 }();/*
13312  * Based on:
13313  * Ext JS Library 1.1.1
13314  * Copyright(c) 2006-2007, Ext JS, LLC.
13315  *
13316  * Originally Released Under LGPL - original licence link has changed is not relivant.
13317  *
13318  * Fork - LGPL
13319  * <script type="text/javascript">
13320  */
13321
13322  
13323
13324 /**
13325  * @class Roo.util.ClickRepeater
13326  * @extends Roo.util.Observable
13327  * 
13328  * A wrapper class which can be applied to any element. Fires a "click" event while the
13329  * mouse is pressed. The interval between firings may be specified in the config but
13330  * defaults to 10 milliseconds.
13331  * 
13332  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13333  * 
13334  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13335  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13336  * Similar to an autorepeat key delay.
13337  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13338  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13339  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13340  *           "interval" and "delay" are ignored. "immediate" is honored.
13341  * @cfg {Boolean} preventDefault True to prevent the default click event
13342  * @cfg {Boolean} stopDefault True to stop the default click event
13343  * 
13344  * @history
13345  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13346  *     2007-02-02 jvs Renamed to ClickRepeater
13347  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13348  *
13349  *  @constructor
13350  * @param {String/HTMLElement/Element} el The element to listen on
13351  * @param {Object} config
13352  **/
13353 Roo.util.ClickRepeater = function(el, config)
13354 {
13355     this.el = Roo.get(el);
13356     this.el.unselectable();
13357
13358     Roo.apply(this, config);
13359
13360     this.addEvents({
13361     /**
13362      * @event mousedown
13363      * Fires when the mouse button is depressed.
13364      * @param {Roo.util.ClickRepeater} this
13365      */
13366         "mousedown" : true,
13367     /**
13368      * @event click
13369      * Fires on a specified interval during the time the element is pressed.
13370      * @param {Roo.util.ClickRepeater} this
13371      */
13372         "click" : true,
13373     /**
13374      * @event mouseup
13375      * Fires when the mouse key is released.
13376      * @param {Roo.util.ClickRepeater} this
13377      */
13378         "mouseup" : true
13379     });
13380
13381     this.el.on("mousedown", this.handleMouseDown, this);
13382     if(this.preventDefault || this.stopDefault){
13383         this.el.on("click", function(e){
13384             if(this.preventDefault){
13385                 e.preventDefault();
13386             }
13387             if(this.stopDefault){
13388                 e.stopEvent();
13389             }
13390         }, this);
13391     }
13392
13393     // allow inline handler
13394     if(this.handler){
13395         this.on("click", this.handler,  this.scope || this);
13396     }
13397
13398     Roo.util.ClickRepeater.superclass.constructor.call(this);
13399 };
13400
13401 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13402     interval : 20,
13403     delay: 250,
13404     preventDefault : true,
13405     stopDefault : false,
13406     timer : 0,
13407
13408     // private
13409     handleMouseDown : function(){
13410         clearTimeout(this.timer);
13411         this.el.blur();
13412         if(this.pressClass){
13413             this.el.addClass(this.pressClass);
13414         }
13415         this.mousedownTime = new Date();
13416
13417         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13418         this.el.on("mouseout", this.handleMouseOut, this);
13419
13420         this.fireEvent("mousedown", this);
13421         this.fireEvent("click", this);
13422         
13423         this.timer = this.click.defer(this.delay || this.interval, this);
13424     },
13425
13426     // private
13427     click : function(){
13428         this.fireEvent("click", this);
13429         this.timer = this.click.defer(this.getInterval(), this);
13430     },
13431
13432     // private
13433     getInterval: function(){
13434         if(!this.accelerate){
13435             return this.interval;
13436         }
13437         var pressTime = this.mousedownTime.getElapsed();
13438         if(pressTime < 500){
13439             return 400;
13440         }else if(pressTime < 1700){
13441             return 320;
13442         }else if(pressTime < 2600){
13443             return 250;
13444         }else if(pressTime < 3500){
13445             return 180;
13446         }else if(pressTime < 4400){
13447             return 140;
13448         }else if(pressTime < 5300){
13449             return 80;
13450         }else if(pressTime < 6200){
13451             return 50;
13452         }else{
13453             return 10;
13454         }
13455     },
13456
13457     // private
13458     handleMouseOut : function(){
13459         clearTimeout(this.timer);
13460         if(this.pressClass){
13461             this.el.removeClass(this.pressClass);
13462         }
13463         this.el.on("mouseover", this.handleMouseReturn, this);
13464     },
13465
13466     // private
13467     handleMouseReturn : function(){
13468         this.el.un("mouseover", this.handleMouseReturn);
13469         if(this.pressClass){
13470             this.el.addClass(this.pressClass);
13471         }
13472         this.click();
13473     },
13474
13475     // private
13476     handleMouseUp : function(){
13477         clearTimeout(this.timer);
13478         this.el.un("mouseover", this.handleMouseReturn);
13479         this.el.un("mouseout", this.handleMouseOut);
13480         Roo.get(document).un("mouseup", this.handleMouseUp);
13481         this.el.removeClass(this.pressClass);
13482         this.fireEvent("mouseup", this);
13483     }
13484 });/*
13485  * Based on:
13486  * Ext JS Library 1.1.1
13487  * Copyright(c) 2006-2007, Ext JS, LLC.
13488  *
13489  * Originally Released Under LGPL - original licence link has changed is not relivant.
13490  *
13491  * Fork - LGPL
13492  * <script type="text/javascript">
13493  */
13494
13495  
13496 /**
13497  * @class Roo.KeyNav
13498  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13499  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13500  * way to implement custom navigation schemes for any UI component.</p>
13501  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13502  * pageUp, pageDown, del, home, end.  Usage:</p>
13503  <pre><code>
13504 var nav = new Roo.KeyNav("my-element", {
13505     "left" : function(e){
13506         this.moveLeft(e.ctrlKey);
13507     },
13508     "right" : function(e){
13509         this.moveRight(e.ctrlKey);
13510     },
13511     "enter" : function(e){
13512         this.save();
13513     },
13514     scope : this
13515 });
13516 </code></pre>
13517  * @constructor
13518  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13519  * @param {Object} config The config
13520  */
13521 Roo.KeyNav = function(el, config){
13522     this.el = Roo.get(el);
13523     Roo.apply(this, config);
13524     if(!this.disabled){
13525         this.disabled = true;
13526         this.enable();
13527     }
13528 };
13529
13530 Roo.KeyNav.prototype = {
13531     /**
13532      * @cfg {Boolean} disabled
13533      * True to disable this KeyNav instance (defaults to false)
13534      */
13535     disabled : false,
13536     /**
13537      * @cfg {String} defaultEventAction
13538      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13539      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13540      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13541      */
13542     defaultEventAction: "stopEvent",
13543     /**
13544      * @cfg {Boolean} forceKeyDown
13545      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13546      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13547      * handle keydown instead of keypress.
13548      */
13549     forceKeyDown : false,
13550
13551     // private
13552     prepareEvent : function(e){
13553         var k = e.getKey();
13554         var h = this.keyToHandler[k];
13555         //if(h && this[h]){
13556         //    e.stopPropagation();
13557         //}
13558         if(Roo.isSafari && h && k >= 37 && k <= 40){
13559             e.stopEvent();
13560         }
13561     },
13562
13563     // private
13564     relay : function(e){
13565         var k = e.getKey();
13566         var h = this.keyToHandler[k];
13567         if(h && this[h]){
13568             if(this.doRelay(e, this[h], h) !== true){
13569                 e[this.defaultEventAction]();
13570             }
13571         }
13572     },
13573
13574     // private
13575     doRelay : function(e, h, hname){
13576         return h.call(this.scope || this, e);
13577     },
13578
13579     // possible handlers
13580     enter : false,
13581     left : false,
13582     right : false,
13583     up : false,
13584     down : false,
13585     tab : false,
13586     esc : false,
13587     pageUp : false,
13588     pageDown : false,
13589     del : false,
13590     home : false,
13591     end : false,
13592
13593     // quick lookup hash
13594     keyToHandler : {
13595         37 : "left",
13596         39 : "right",
13597         38 : "up",
13598         40 : "down",
13599         33 : "pageUp",
13600         34 : "pageDown",
13601         46 : "del",
13602         36 : "home",
13603         35 : "end",
13604         13 : "enter",
13605         27 : "esc",
13606         9  : "tab"
13607     },
13608
13609         /**
13610          * Enable this KeyNav
13611          */
13612         enable: function(){
13613                 if(this.disabled){
13614             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13615             // the EventObject will normalize Safari automatically
13616             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13617                 this.el.on("keydown", this.relay,  this);
13618             }else{
13619                 this.el.on("keydown", this.prepareEvent,  this);
13620                 this.el.on("keypress", this.relay,  this);
13621             }
13622                     this.disabled = false;
13623                 }
13624         },
13625
13626         /**
13627          * Disable this KeyNav
13628          */
13629         disable: function(){
13630                 if(!this.disabled){
13631                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13632                 this.el.un("keydown", this.relay);
13633             }else{
13634                 this.el.un("keydown", this.prepareEvent);
13635                 this.el.un("keypress", this.relay);
13636             }
13637                     this.disabled = true;
13638                 }
13639         }
13640 };/*
13641  * Based on:
13642  * Ext JS Library 1.1.1
13643  * Copyright(c) 2006-2007, Ext JS, LLC.
13644  *
13645  * Originally Released Under LGPL - original licence link has changed is not relivant.
13646  *
13647  * Fork - LGPL
13648  * <script type="text/javascript">
13649  */
13650
13651  
13652 /**
13653  * @class Roo.KeyMap
13654  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13655  * The constructor accepts the same config object as defined by {@link #addBinding}.
13656  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13657  * combination it will call the function with this signature (if the match is a multi-key
13658  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13659  * A KeyMap can also handle a string representation of keys.<br />
13660  * Usage:
13661  <pre><code>
13662 // map one key by key code
13663 var map = new Roo.KeyMap("my-element", {
13664     key: 13, // or Roo.EventObject.ENTER
13665     fn: myHandler,
13666     scope: myObject
13667 });
13668
13669 // map multiple keys to one action by string
13670 var map = new Roo.KeyMap("my-element", {
13671     key: "a\r\n\t",
13672     fn: myHandler,
13673     scope: myObject
13674 });
13675
13676 // map multiple keys to multiple actions by strings and array of codes
13677 var map = new Roo.KeyMap("my-element", [
13678     {
13679         key: [10,13],
13680         fn: function(){ alert("Return was pressed"); }
13681     }, {
13682         key: "abc",
13683         fn: function(){ alert('a, b or c was pressed'); }
13684     }, {
13685         key: "\t",
13686         ctrl:true,
13687         shift:true,
13688         fn: function(){ alert('Control + shift + tab was pressed.'); }
13689     }
13690 ]);
13691 </code></pre>
13692  * <b>Note: A KeyMap starts enabled</b>
13693  * @constructor
13694  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13695  * @param {Object} config The config (see {@link #addBinding})
13696  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13697  */
13698 Roo.KeyMap = function(el, config, eventName){
13699     this.el  = Roo.get(el);
13700     this.eventName = eventName || "keydown";
13701     this.bindings = [];
13702     if(config){
13703         this.addBinding(config);
13704     }
13705     this.enable();
13706 };
13707
13708 Roo.KeyMap.prototype = {
13709     /**
13710      * True to stop the event from bubbling and prevent the default browser action if the
13711      * key was handled by the KeyMap (defaults to false)
13712      * @type Boolean
13713      */
13714     stopEvent : false,
13715
13716     /**
13717      * Add a new binding to this KeyMap. The following config object properties are supported:
13718      * <pre>
13719 Property    Type             Description
13720 ----------  ---------------  ----------------------------------------------------------------------
13721 key         String/Array     A single keycode or an array of keycodes to handle
13722 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13723 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13724 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13725 fn          Function         The function to call when KeyMap finds the expected key combination
13726 scope       Object           The scope of the callback function
13727 </pre>
13728      *
13729      * Usage:
13730      * <pre><code>
13731 // Create a KeyMap
13732 var map = new Roo.KeyMap(document, {
13733     key: Roo.EventObject.ENTER,
13734     fn: handleKey,
13735     scope: this
13736 });
13737
13738 //Add a new binding to the existing KeyMap later
13739 map.addBinding({
13740     key: 'abc',
13741     shift: true,
13742     fn: handleKey,
13743     scope: this
13744 });
13745 </code></pre>
13746      * @param {Object/Array} config A single KeyMap config or an array of configs
13747      */
13748         addBinding : function(config){
13749         if(config instanceof Array){
13750             for(var i = 0, len = config.length; i < len; i++){
13751                 this.addBinding(config[i]);
13752             }
13753             return;
13754         }
13755         var keyCode = config.key,
13756             shift = config.shift, 
13757             ctrl = config.ctrl, 
13758             alt = config.alt,
13759             fn = config.fn,
13760             scope = config.scope;
13761         if(typeof keyCode == "string"){
13762             var ks = [];
13763             var keyString = keyCode.toUpperCase();
13764             for(var j = 0, len = keyString.length; j < len; j++){
13765                 ks.push(keyString.charCodeAt(j));
13766             }
13767             keyCode = ks;
13768         }
13769         var keyArray = keyCode instanceof Array;
13770         var handler = function(e){
13771             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13772                 var k = e.getKey();
13773                 if(keyArray){
13774                     for(var i = 0, len = keyCode.length; i < len; i++){
13775                         if(keyCode[i] == k){
13776                           if(this.stopEvent){
13777                               e.stopEvent();
13778                           }
13779                           fn.call(scope || window, k, e);
13780                           return;
13781                         }
13782                     }
13783                 }else{
13784                     if(k == keyCode){
13785                         if(this.stopEvent){
13786                            e.stopEvent();
13787                         }
13788                         fn.call(scope || window, k, e);
13789                     }
13790                 }
13791             }
13792         };
13793         this.bindings.push(handler);  
13794         },
13795
13796     /**
13797      * Shorthand for adding a single key listener
13798      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13799      * following options:
13800      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13801      * @param {Function} fn The function to call
13802      * @param {Object} scope (optional) The scope of the function
13803      */
13804     on : function(key, fn, scope){
13805         var keyCode, shift, ctrl, alt;
13806         if(typeof key == "object" && !(key instanceof Array)){
13807             keyCode = key.key;
13808             shift = key.shift;
13809             ctrl = key.ctrl;
13810             alt = key.alt;
13811         }else{
13812             keyCode = key;
13813         }
13814         this.addBinding({
13815             key: keyCode,
13816             shift: shift,
13817             ctrl: ctrl,
13818             alt: alt,
13819             fn: fn,
13820             scope: scope
13821         })
13822     },
13823
13824     // private
13825     handleKeyDown : function(e){
13826             if(this.enabled){ //just in case
13827             var b = this.bindings;
13828             for(var i = 0, len = b.length; i < len; i++){
13829                 b[i].call(this, e);
13830             }
13831             }
13832         },
13833         
13834         /**
13835          * Returns true if this KeyMap is enabled
13836          * @return {Boolean} 
13837          */
13838         isEnabled : function(){
13839             return this.enabled;  
13840         },
13841         
13842         /**
13843          * Enables this KeyMap
13844          */
13845         enable: function(){
13846                 if(!this.enabled){
13847                     this.el.on(this.eventName, this.handleKeyDown, this);
13848                     this.enabled = true;
13849                 }
13850         },
13851
13852         /**
13853          * Disable this KeyMap
13854          */
13855         disable: function(){
13856                 if(this.enabled){
13857                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
13858                     this.enabled = false;
13859                 }
13860         }
13861 };/*
13862  * Based on:
13863  * Ext JS Library 1.1.1
13864  * Copyright(c) 2006-2007, Ext JS, LLC.
13865  *
13866  * Originally Released Under LGPL - original licence link has changed is not relivant.
13867  *
13868  * Fork - LGPL
13869  * <script type="text/javascript">
13870  */
13871
13872  
13873 /**
13874  * @class Roo.util.TextMetrics
13875  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13876  * wide, in pixels, a given block of text will be.
13877  * @singleton
13878  */
13879 Roo.util.TextMetrics = function(){
13880     var shared;
13881     return {
13882         /**
13883          * Measures the size of the specified text
13884          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13885          * that can affect the size of the rendered text
13886          * @param {String} text The text to measure
13887          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13888          * in order to accurately measure the text height
13889          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13890          */
13891         measure : function(el, text, fixedWidth){
13892             if(!shared){
13893                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13894             }
13895             shared.bind(el);
13896             shared.setFixedWidth(fixedWidth || 'auto');
13897             return shared.getSize(text);
13898         },
13899
13900         /**
13901          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
13902          * the overhead of multiple calls to initialize the style properties on each measurement.
13903          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13904          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13905          * in order to accurately measure the text height
13906          * @return {Roo.util.TextMetrics.Instance} instance The new instance
13907          */
13908         createInstance : function(el, fixedWidth){
13909             return Roo.util.TextMetrics.Instance(el, fixedWidth);
13910         }
13911     };
13912 }();
13913
13914  
13915
13916 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13917     var ml = new Roo.Element(document.createElement('div'));
13918     document.body.appendChild(ml.dom);
13919     ml.position('absolute');
13920     ml.setLeftTop(-1000, -1000);
13921     ml.hide();
13922
13923     if(fixedWidth){
13924         ml.setWidth(fixedWidth);
13925     }
13926      
13927     var instance = {
13928         /**
13929          * Returns the size of the specified text based on the internal element's style and width properties
13930          * @memberOf Roo.util.TextMetrics.Instance#
13931          * @param {String} text The text to measure
13932          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13933          */
13934         getSize : function(text){
13935             ml.update(text);
13936             var s = ml.getSize();
13937             ml.update('');
13938             return s;
13939         },
13940
13941         /**
13942          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13943          * that can affect the size of the rendered text
13944          * @memberOf Roo.util.TextMetrics.Instance#
13945          * @param {String/HTMLElement} el The element, dom node or id
13946          */
13947         bind : function(el){
13948             ml.setStyle(
13949                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13950             );
13951         },
13952
13953         /**
13954          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
13955          * to set a fixed width in order to accurately measure the text height.
13956          * @memberOf Roo.util.TextMetrics.Instance#
13957          * @param {Number} width The width to set on the element
13958          */
13959         setFixedWidth : function(width){
13960             ml.setWidth(width);
13961         },
13962
13963         /**
13964          * Returns the measured width of the specified text
13965          * @memberOf Roo.util.TextMetrics.Instance#
13966          * @param {String} text The text to measure
13967          * @return {Number} width The width in pixels
13968          */
13969         getWidth : function(text){
13970             ml.dom.style.width = 'auto';
13971             return this.getSize(text).width;
13972         },
13973
13974         /**
13975          * Returns the measured height of the specified text.  For multiline text, be sure to call
13976          * {@link #setFixedWidth} if necessary.
13977          * @memberOf Roo.util.TextMetrics.Instance#
13978          * @param {String} text The text to measure
13979          * @return {Number} height The height in pixels
13980          */
13981         getHeight : function(text){
13982             return this.getSize(text).height;
13983         }
13984     };
13985
13986     instance.bind(bindTo);
13987
13988     return instance;
13989 };
13990
13991 // backwards compat
13992 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13993  * Based on:
13994  * Ext JS Library 1.1.1
13995  * Copyright(c) 2006-2007, Ext JS, LLC.
13996  *
13997  * Originally Released Under LGPL - original licence link has changed is not relivant.
13998  *
13999  * Fork - LGPL
14000  * <script type="text/javascript">
14001  */
14002
14003 /**
14004  * @class Roo.state.Provider
14005  * Abstract base class for state provider implementations. This class provides methods
14006  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14007  * Provider interface.
14008  */
14009 Roo.state.Provider = function(){
14010     /**
14011      * @event statechange
14012      * Fires when a state change occurs.
14013      * @param {Provider} this This state provider
14014      * @param {String} key The state key which was changed
14015      * @param {String} value The encoded value for the state
14016      */
14017     this.addEvents({
14018         "statechange": true
14019     });
14020     this.state = {};
14021     Roo.state.Provider.superclass.constructor.call(this);
14022 };
14023 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14024     /**
14025      * Returns the current value for a key
14026      * @param {String} name The key name
14027      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14028      * @return {Mixed} The state data
14029      */
14030     get : function(name, defaultValue){
14031         return typeof this.state[name] == "undefined" ?
14032             defaultValue : this.state[name];
14033     },
14034     
14035     /**
14036      * Clears a value from the state
14037      * @param {String} name The key name
14038      */
14039     clear : function(name){
14040         delete this.state[name];
14041         this.fireEvent("statechange", this, name, null);
14042     },
14043     
14044     /**
14045      * Sets the value for a key
14046      * @param {String} name The key name
14047      * @param {Mixed} value The value to set
14048      */
14049     set : function(name, value){
14050         this.state[name] = value;
14051         this.fireEvent("statechange", this, name, value);
14052     },
14053     
14054     /**
14055      * Decodes a string previously encoded with {@link #encodeValue}.
14056      * @param {String} value The value to decode
14057      * @return {Mixed} The decoded value
14058      */
14059     decodeValue : function(cookie){
14060         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14061         var matches = re.exec(unescape(cookie));
14062         if(!matches || !matches[1]) return; // non state cookie
14063         var type = matches[1];
14064         var v = matches[2];
14065         switch(type){
14066             case "n":
14067                 return parseFloat(v);
14068             case "d":
14069                 return new Date(Date.parse(v));
14070             case "b":
14071                 return (v == "1");
14072             case "a":
14073                 var all = [];
14074                 var values = v.split("^");
14075                 for(var i = 0, len = values.length; i < len; i++){
14076                     all.push(this.decodeValue(values[i]));
14077                 }
14078                 return all;
14079            case "o":
14080                 var all = {};
14081                 var values = v.split("^");
14082                 for(var i = 0, len = values.length; i < len; i++){
14083                     var kv = values[i].split("=");
14084                     all[kv[0]] = this.decodeValue(kv[1]);
14085                 }
14086                 return all;
14087            default:
14088                 return v;
14089         }
14090     },
14091     
14092     /**
14093      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14094      * @param {Mixed} value The value to encode
14095      * @return {String} The encoded value
14096      */
14097     encodeValue : function(v){
14098         var enc;
14099         if(typeof v == "number"){
14100             enc = "n:" + v;
14101         }else if(typeof v == "boolean"){
14102             enc = "b:" + (v ? "1" : "0");
14103         }else if(v instanceof Date){
14104             enc = "d:" + v.toGMTString();
14105         }else if(v instanceof Array){
14106             var flat = "";
14107             for(var i = 0, len = v.length; i < len; i++){
14108                 flat += this.encodeValue(v[i]);
14109                 if(i != len-1) flat += "^";
14110             }
14111             enc = "a:" + flat;
14112         }else if(typeof v == "object"){
14113             var flat = "";
14114             for(var key in v){
14115                 if(typeof v[key] != "function"){
14116                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14117                 }
14118             }
14119             enc = "o:" + flat.substring(0, flat.length-1);
14120         }else{
14121             enc = "s:" + v;
14122         }
14123         return escape(enc);        
14124     }
14125 });
14126
14127 /*
14128  * Based on:
14129  * Ext JS Library 1.1.1
14130  * Copyright(c) 2006-2007, Ext JS, LLC.
14131  *
14132  * Originally Released Under LGPL - original licence link has changed is not relivant.
14133  *
14134  * Fork - LGPL
14135  * <script type="text/javascript">
14136  */
14137 /**
14138  * @class Roo.state.Manager
14139  * This is the global state manager. By default all components that are "state aware" check this class
14140  * for state information if you don't pass them a custom state provider. In order for this class
14141  * to be useful, it must be initialized with a provider when your application initializes.
14142  <pre><code>
14143 // in your initialization function
14144 init : function(){
14145    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14146    ...
14147    // supposed you have a {@link Roo.BorderLayout}
14148    var layout = new Roo.BorderLayout(...);
14149    layout.restoreState();
14150    // or a {Roo.BasicDialog}
14151    var dialog = new Roo.BasicDialog(...);
14152    dialog.restoreState();
14153  </code></pre>
14154  * @singleton
14155  */
14156 Roo.state.Manager = function(){
14157     var provider = new Roo.state.Provider();
14158     
14159     return {
14160         /**
14161          * Configures the default state provider for your application
14162          * @param {Provider} stateProvider The state provider to set
14163          */
14164         setProvider : function(stateProvider){
14165             provider = stateProvider;
14166         },
14167         
14168         /**
14169          * Returns the current value for a key
14170          * @param {String} name The key name
14171          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14172          * @return {Mixed} The state data
14173          */
14174         get : function(key, defaultValue){
14175             return provider.get(key, defaultValue);
14176         },
14177         
14178         /**
14179          * Sets the value for a key
14180          * @param {String} name The key name
14181          * @param {Mixed} value The state data
14182          */
14183          set : function(key, value){
14184             provider.set(key, value);
14185         },
14186         
14187         /**
14188          * Clears a value from the state
14189          * @param {String} name The key name
14190          */
14191         clear : function(key){
14192             provider.clear(key);
14193         },
14194         
14195         /**
14196          * Gets the currently configured state provider
14197          * @return {Provider} The state provider
14198          */
14199         getProvider : function(){
14200             return provider;
14201         }
14202     };
14203 }();
14204 /*
14205  * Based on:
14206  * Ext JS Library 1.1.1
14207  * Copyright(c) 2006-2007, Ext JS, LLC.
14208  *
14209  * Originally Released Under LGPL - original licence link has changed is not relivant.
14210  *
14211  * Fork - LGPL
14212  * <script type="text/javascript">
14213  */
14214 /**
14215  * @class Roo.state.CookieProvider
14216  * @extends Roo.state.Provider
14217  * The default Provider implementation which saves state via cookies.
14218  * <br />Usage:
14219  <pre><code>
14220    var cp = new Roo.state.CookieProvider({
14221        path: "/cgi-bin/",
14222        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14223        domain: "roojs.com"
14224    })
14225    Roo.state.Manager.setProvider(cp);
14226  </code></pre>
14227  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14228  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14229  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14230  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14231  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14232  * domain the page is running on including the 'www' like 'www.roojs.com')
14233  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14234  * @constructor
14235  * Create a new CookieProvider
14236  * @param {Object} config The configuration object
14237  */
14238 Roo.state.CookieProvider = function(config){
14239     Roo.state.CookieProvider.superclass.constructor.call(this);
14240     this.path = "/";
14241     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14242     this.domain = null;
14243     this.secure = false;
14244     Roo.apply(this, config);
14245     this.state = this.readCookies();
14246 };
14247
14248 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14249     // private
14250     set : function(name, value){
14251         if(typeof value == "undefined" || value === null){
14252             this.clear(name);
14253             return;
14254         }
14255         this.setCookie(name, value);
14256         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14257     },
14258
14259     // private
14260     clear : function(name){
14261         this.clearCookie(name);
14262         Roo.state.CookieProvider.superclass.clear.call(this, name);
14263     },
14264
14265     // private
14266     readCookies : function(){
14267         var cookies = {};
14268         var c = document.cookie + ";";
14269         var re = /\s?(.*?)=(.*?);/g;
14270         var matches;
14271         while((matches = re.exec(c)) != null){
14272             var name = matches[1];
14273             var value = matches[2];
14274             if(name && name.substring(0,3) == "ys-"){
14275                 cookies[name.substr(3)] = this.decodeValue(value);
14276             }
14277         }
14278         return cookies;
14279     },
14280
14281     // private
14282     setCookie : function(name, value){
14283         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14284            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14285            ((this.path == null) ? "" : ("; path=" + this.path)) +
14286            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14287            ((this.secure == true) ? "; secure" : "");
14288     },
14289
14290     // private
14291     clearCookie : function(name){
14292         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14293            ((this.path == null) ? "" : ("; path=" + this.path)) +
14294            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14295            ((this.secure == true) ? "; secure" : "");
14296     }
14297 });