roojs-core-debug.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88
89         /**
90          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
91          * @type Boolean
92          */
93         enableGarbageCollector : true,
94
95         /**
96          * True to automatically purge event listeners after uncaching an element (defaults to false).
97          * Note: this only happens if enableGarbageCollector is true.
98          * @type Boolean
99          */
100         enableListenerCollection:false,
101
102         /**
103          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104          * the IE insecure content warning (defaults to javascript:false).
105          * @type String
106          */
107         SSL_SECURE_URL : "javascript:false",
108
109         /**
110          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
112          * @type String
113          */
114         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
115
116         emptyFn : function(){},
117
118         /**
119          * Copies all the properties of config to obj if they don't already exist.
120          * @param {Object} obj The receiver of the properties
121          * @param {Object} config The source of the properties
122          * @return {Object} returns obj
123          */
124         applyIf : function(o, c){
125             if(o && c){
126                 for(var p in c){
127                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
128                 }
129             }
130             return o;
131         },
132
133         /**
134          * Applies event listeners to elements by selectors when the document is ready.
135          * The event name is specified with an @ suffix.
136 <pre><code>
137 Roo.addBehaviors({
138    // add a listener for click on all anchors in element with id foo
139    '#foo a@click' : function(e, t){
140        // do something
141    },
142
143    // add the same listener to multiple selectors (separated by comma BEFORE the @)
144    '#foo a, #bar span.some-class@mouseover' : function(){
145        // do something
146    }
147 });
148 </code></pre>
149          * @param {Object} obj The list of behaviors to apply
150          */
151         addBehaviors : function(o){
152             if(!Roo.isReady){
153                 Roo.onReady(function(){
154                     Roo.addBehaviors(o);
155                 });
156                 return;
157             }
158             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
159             for(var b in o){
160                 var parts = b.split('@');
161                 if(parts[1]){ // for Object prototype breakers
162                     var s = parts[0];
163                     if(!cache[s]){
164                         cache[s] = Roo.select(s);
165                     }
166                     cache[s].on(parts[1], o[b]);
167                 }
168             }
169             cache = null;
170         },
171
172         /**
173          * Generates unique ids. If the element already has an id, it is unchanged
174          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176          * @return {String} The generated Id.
177          */
178         id : function(el, prefix){
179             prefix = prefix || "roo-gen";
180             el = Roo.getDom(el);
181             var id = prefix + (++idSeed);
182             return el ? (el.id ? el.id : (el.id = id)) : id;
183         },
184          
185        
186         /**
187          * Extends one class with another class and optionally overrides members with the passed literal. This class
188          * also adds the function "override()" to the class that can be used to override
189          * members on an instance.
190          * @param {Object} subclass The class inheriting the functionality
191          * @param {Object} superclass The class being extended
192          * @param {Object} overrides (optional) A literal with members
193          * @method extend
194          */
195         extend : function(){
196             // inline overrides
197             var io = function(o){
198                 for(var m in o){
199                     this[m] = o[m];
200                 }
201             };
202             return function(sb, sp, overrides){
203                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
204                     overrides = sp;
205                     sp = sb;
206                     sb = function(){sp.apply(this, arguments);};
207                 }
208                 var F = function(){}, sbp, spp = sp.prototype;
209                 F.prototype = spp;
210                 sbp = sb.prototype = new F();
211                 sbp.constructor=sb;
212                 sb.superclass=spp;
213                 
214                 if(spp.constructor == Object.prototype.constructor){
215                     spp.constructor=sp;
216                    
217                 }
218                 
219                 sb.override = function(o){
220                     Roo.override(sb, o);
221                 };
222                 sbp.override = io;
223                 Roo.override(sb, overrides);
224                 return sb;
225             };
226         }(),
227
228         /**
229          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
230          * Usage:<pre><code>
231 Roo.override(MyClass, {
232     newMethod1: function(){
233         // etc.
234     },
235     newMethod2: function(foo){
236         // etc.
237     }
238 });
239  </code></pre>
240          * @param {Object} origclass The class to override
241          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
242          * containing one or more methods.
243          * @method override
244          */
245         override : function(origclass, overrides){
246             if(overrides){
247                 var p = origclass.prototype;
248                 for(var method in overrides){
249                     p[method] = overrides[method];
250                 }
251             }
252         },
253         /**
254          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
255          * <pre><code>
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
259 </code></pre>
260          * @param {String} namespace1
261          * @param {String} namespace2
262          * @param {String} etc
263          * @method namespace
264          */
265         namespace : function(){
266             var a=arguments, o=null, i, j, d, rt;
267             for (i=0; i<a.length; ++i) {
268                 d=a[i].split(".");
269                 rt = d[0];
270                 /** eval:var:o */
271                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272                 for (j=1; j<d.length; ++j) {
273                     o[d[j]]=o[d[j]] || {};
274                     o=o[d[j]];
275                 }
276             }
277         },
278         /**
279          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
280          * <pre><code>
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
283 </code></pre>
284          * @param {String} classname
285          * @param {String} namespace (optional)
286          * @method factory
287          */
288          
289         factory : function(c, ns)
290         {
291             // no xtype, no ns or c.xns - or forced off by c.xns
292             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
293                 return c;
294             }
295             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296             if (c.constructor == ns[c.xtype]) {// already created...
297                 return c;
298             }
299             if (ns[c.xtype]) {
300                 if (Roo.debug) console.log("Roo.Factory(" + c.xtype + ")");
301                 var ret = new ns[c.xtype](c);
302                 ret.xns = false;
303                 return ret;
304             }
305             c.xns = false; // prevent recursion..
306             return c;
307         },
308          
309         /**
310          * 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.
311          * @param {Object} o
312          * @return {String}
313          */
314         urlEncode : function(o){
315             if(!o){
316                 return "";
317             }
318             var buf = [];
319             for(var key in o){
320                 var ov = o[key], k = encodeURIComponent(key);
321                 var type = typeof ov;
322                 if(type == 'undefined'){
323                     buf.push(k, "=&");
324                 }else if(type != "function" && type != "object"){
325                     buf.push(k, "=", encodeURIComponent(ov), "&");
326                 }else if(ov instanceof Array){
327                     if (ov.length) {
328                             for(var i = 0, len = ov.length; i < len; i++) {
329                                 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
330                             }
331                         } else {
332                             buf.push(k, "=&");
333                         }
334                 }
335             }
336             buf.pop();
337             return buf.join("");
338         },
339
340         /**
341          * 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]}.
342          * @param {String} string
343          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344          * @return {Object} A literal with members
345          */
346         urlDecode : function(string, overwrite){
347             if(!string || !string.length){
348                 return {};
349             }
350             var obj = {};
351             var pairs = string.split('&');
352             var pair, name, value;
353             for(var i = 0, len = pairs.length; i < len; i++){
354                 pair = pairs[i].split('=');
355                 name = decodeURIComponent(pair[0]);
356                 value = decodeURIComponent(pair[1]);
357                 if(overwrite !== true){
358                     if(typeof obj[name] == "undefined"){
359                         obj[name] = value;
360                     }else if(typeof obj[name] == "string"){
361                         obj[name] = [obj[name]];
362                         obj[name].push(value);
363                     }else{
364                         obj[name].push(value);
365                     }
366                 }else{
367                     obj[name] = value;
368                 }
369             }
370             return obj;
371         },
372
373         /**
374          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375          * passed array is not really an array, your function is called once with it.
376          * The supplied function is called with (Object item, Number index, Array allItems).
377          * @param {Array/NodeList/Mixed} array
378          * @param {Function} fn
379          * @param {Object} scope
380          */
381         each : function(array, fn, scope){
382             if(typeof array.length == "undefined" || typeof array == "string"){
383                 array = [array];
384             }
385             for(var i = 0, len = array.length; i < len; i++){
386                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
387             }
388         },
389
390         // deprecated
391         combine : function(){
392             var as = arguments, l = as.length, r = [];
393             for(var i = 0; i < l; i++){
394                 var a = as[i];
395                 if(a instanceof Array){
396                     r = r.concat(a);
397                 }else if(a.length !== undefined && !a.substr){
398                     r = r.concat(Array.prototype.slice.call(a, 0));
399                 }else{
400                     r.push(a);
401                 }
402             }
403             return r;
404         },
405
406         /**
407          * Escapes the passed string for use in a regular expression
408          * @param {String} str
409          * @return {String}
410          */
411         escapeRe : function(s) {
412             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
413         },
414
415         // internal
416         callback : function(cb, scope, args, delay){
417             if(typeof cb == "function"){
418                 if(delay){
419                     cb.defer(delay, scope, args || []);
420                 }else{
421                     cb.apply(scope, args || []);
422                 }
423             }
424         },
425
426         /**
427          * Return the dom node for the passed string (id), dom node, or Roo.Element
428          * @param {String/HTMLElement/Roo.Element} el
429          * @return HTMLElement
430          */
431         getDom : function(el){
432             if(!el){
433                 return null;
434             }
435             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
436         },
437
438         /**
439         * Shorthand for {@link Roo.ComponentMgr#get}
440         * @param {String} id
441         * @return Roo.Component
442         */
443         getCmp : function(id){
444             return Roo.ComponentMgr.get(id);
445         },
446          
447         num : function(v, defaultValue){
448             if(typeof v != 'number'){
449                 return defaultValue;
450             }
451             return v;
452         },
453
454         destroy : function(){
455             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
456                 var as = a[i];
457                 if(as){
458                     if(as.dom){
459                         as.removeAllListeners();
460                         as.remove();
461                         continue;
462                     }
463                     if(typeof as.purgeListeners == 'function'){
464                         as.purgeListeners();
465                     }
466                     if(typeof as.destroy == 'function'){
467                         as.destroy();
468                     }
469                 }
470             }
471         },
472
473         // inpired by a similar function in mootools library
474         /**
475          * Returns the type of object that is passed in. If the object passed in is null or undefined it
476          * return false otherwise it returns one of the following values:<ul>
477          * <li><b>string</b>: If the object passed is a string</li>
478          * <li><b>number</b>: If the object passed is a number</li>
479          * <li><b>boolean</b>: If the object passed is a boolean value</li>
480          * <li><b>function</b>: If the object passed is a function reference</li>
481          * <li><b>object</b>: If the object passed is an object</li>
482          * <li><b>array</b>: If the object passed is an array</li>
483          * <li><b>regexp</b>: If the object passed is a regular expression</li>
484          * <li><b>element</b>: If the object passed is a DOM Element</li>
485          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488          * @param {Mixed} object
489          * @return {String}
490          */
491         type : function(o){
492             if(o === undefined || o === null){
493                 return false;
494             }
495             if(o.htmlElement){
496                 return 'element';
497             }
498             var t = typeof o;
499             if(t == 'object' && o.nodeName) {
500                 switch(o.nodeType) {
501                     case 1: return 'element';
502                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
503                 }
504             }
505             if(t == 'object' || t == 'function') {
506                 switch(o.constructor) {
507                     case Array: return 'array';
508                     case RegExp: return 'regexp';
509                 }
510                 if(typeof o.length == 'number' && typeof o.item == 'function') {
511                     return 'nodelist';
512                 }
513             }
514             return t;
515         },
516
517         /**
518          * Returns true if the passed value is null, undefined or an empty string (optional).
519          * @param {Mixed} value The value to test
520          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
521          * @return {Boolean}
522          */
523         isEmpty : function(v, allowBlank){
524             return v === null || v === undefined || (!allowBlank ? v === '' : false);
525         },
526         
527         /** @type Boolean */
528         isOpera : isOpera,
529         /** @type Boolean */
530         isSafari : isSafari,
531         /** @type Boolean */
532         isIE : isIE,
533         /** @type Boolean */
534         isIE7 : isIE7,
535         /** @type Boolean */
536         isGecko : isGecko,
537         /** @type Boolean */
538         isBorderBox : isBorderBox,
539         /** @type Boolean */
540         isWindows : isWindows,
541         /** @type Boolean */
542         isLinux : isLinux,
543         /** @type Boolean */
544         isMac : isMac,
545
546         /**
547          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548          * you may want to set this to true.
549          * @type Boolean
550          */
551         useShims : ((isIE && !isIE7) || (isGecko && isMac))
552     });
553
554
555 })();
556
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
559 /*
560  * Based on:
561  * Ext JS Library 1.1.1
562  * Copyright(c) 2006-2007, Ext JS, LLC.
563  *
564  * Originally Released Under LGPL - original licence link has changed is not relivant.
565  *
566  * Fork - LGPL
567  * <script type="text/javascript">
568  */
569
570 (function() {    
571     // wrappedn so fnCleanup is not in global scope...
572     if(Roo.isIE) {
573         function fnCleanUp() {
574             var p = Function.prototype;
575             delete p.createSequence;
576             delete p.defer;
577             delete p.createDelegate;
578             delete p.createCallback;
579             delete p.createInterceptor;
580
581             window.detachEvent("onunload", fnCleanUp);
582         }
583         window.attachEvent("onunload", fnCleanUp);
584     }
585 })();
586
587
588 /**
589  * @class Function
590  * These functions are available on every Function object (any JavaScript function).
591  */
592 Roo.apply(Function.prototype, {
593      /**
594      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596      * Will create a function that is bound to those 2 args.
597      * @return {Function} The new function
598     */
599     createCallback : function(/*args...*/){
600         // make args available, in function below
601         var args = arguments;
602         var method = this;
603         return function() {
604             return method.apply(window, args);
605         };
606     },
607
608     /**
609      * Creates a delegate (callback) that sets the scope to obj.
610      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611      * Will create a function that is automatically scoped to this.
612      * @param {Object} obj (optional) The object for which the scope is set
613      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615      *                                             if a number the args are inserted at the specified position
616      * @return {Function} The new function
617      */
618     createDelegate : function(obj, args, appendArgs){
619         var method = this;
620         return function() {
621             var callArgs = args || arguments;
622             if(appendArgs === true){
623                 callArgs = Array.prototype.slice.call(arguments, 0);
624                 callArgs = callArgs.concat(args);
625             }else if(typeof appendArgs == "number"){
626                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
629             }
630             return method.apply(obj || window, callArgs);
631         };
632     },
633
634     /**
635      * Calls this function after the number of millseconds specified.
636      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637      * @param {Object} obj (optional) The object for which the scope is set
638      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640      *                                             if a number the args are inserted at the specified position
641      * @return {Number} The timeout id that can be used with clearTimeout
642      */
643     defer : function(millis, obj, args, appendArgs){
644         var fn = this.createDelegate(obj, args, appendArgs);
645         if(millis){
646             return setTimeout(fn, millis);
647         }
648         fn();
649         return 0;
650     },
651     /**
652      * Create a combined function call sequence of the original function + the passed function.
653      * The resulting function returns the results of the original function.
654      * The passed fcn is called with the parameters of the original function
655      * @param {Function} fcn The function to sequence
656      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657      * @return {Function} The new function
658      */
659     createSequence : function(fcn, scope){
660         if(typeof fcn != "function"){
661             return this;
662         }
663         var method = this;
664         return function() {
665             var retval = method.apply(this || window, arguments);
666             fcn.apply(scope || this || window, arguments);
667             return retval;
668         };
669     },
670
671     /**
672      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673      * The resulting function returns the results of the original function.
674      * The passed fcn is called with the parameters of the original function.
675      * @addon
676      * @param {Function} fcn The function to call before the original
677      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678      * @return {Function} The new function
679      */
680     createInterceptor : function(fcn, scope){
681         if(typeof fcn != "function"){
682             return this;
683         }
684         var method = this;
685         return function() {
686             fcn.target = this;
687             fcn.method = method;
688             if(fcn.apply(scope || this || window, arguments) === false){
689                 return;
690             }
691             return method.apply(this || window, arguments);
692         };
693     }
694 });
695 /*
696  * Based on:
697  * Ext JS Library 1.1.1
698  * Copyright(c) 2006-2007, Ext JS, LLC.
699  *
700  * Originally Released Under LGPL - original licence link has changed is not relivant.
701  *
702  * Fork - LGPL
703  * <script type="text/javascript">
704  */
705
706 Roo.applyIf(String, {
707     
708     /** @scope String */
709     
710     /**
711      * Escapes the passed string for ' and \
712      * @param {String} string The string to escape
713      * @return {String} The escaped string
714      * @static
715      */
716     escape : function(string) {
717         return string.replace(/('|\\)/g, "\\$1");
718     },
719
720     /**
721      * Pads the left side of a string with a specified character.  This is especially useful
722      * for normalizing number and date strings.  Example usage:
723      * <pre><code>
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
726 </code></pre>
727      * @param {String} string The original string
728      * @param {Number} size The total length of the output string
729      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730      * @return {String} The padded string
731      * @static
732      */
733     leftPad : function (val, size, ch) {
734         var result = new String(val);
735         if(ch === null || ch === undefined || ch === '') {
736             ch = " ";
737         }
738         while (result.length < size) {
739             result = ch + result;
740         }
741         return result;
742     },
743
744     /**
745      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
746      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
747      * <pre><code>
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
751 </code></pre>
752      * @param {String} string The tokenized string to be formatted
753      * @param {String} value1 The value to replace token {0}
754      * @param {String} value2 Etc...
755      * @return {String} The formatted string
756      * @static
757      */
758     format : function(format){
759         var args = Array.prototype.slice.call(arguments, 1);
760         return format.replace(/\{(\d+)\}/g, function(m, i){
761             return Roo.util.Format.htmlEncode(args[i]);
762         });
763     }
764 });
765
766 /**
767  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
768  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
769  * they are already different, the first value passed in is returned.  Note that this method returns the new value
770  * but does not change the current string.
771  * <pre><code>
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
774
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
777 </code></pre>
778  * @param {String} value The value to compare to the current string
779  * @param {String} other The new value to use if the string already equals the first value passed in
780  * @return {String} The new value
781  */
782  
783 String.prototype.toggle = function(value, other){
784     return this == value ? other : value;
785 };/*
786  * Based on:
787  * Ext JS Library 1.1.1
788  * Copyright(c) 2006-2007, Ext JS, LLC.
789  *
790  * Originally Released Under LGPL - original licence link has changed is not relivant.
791  *
792  * Fork - LGPL
793  * <script type="text/javascript">
794  */
795
796  /**
797  * @class Number
798  */
799 Roo.applyIf(Number.prototype, {
800     /**
801      * Checks whether or not the current number is within a desired range.  If the number is already within the
802      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803      * exceeded.  Note that this method returns the constrained value but does not change the current number.
804      * @param {Number} min The minimum number in the range
805      * @param {Number} max The maximum number in the range
806      * @return {Number} The constrained value if outside the range, otherwise the current value
807      */
808     constrain : function(min, max){
809         return Math.min(Math.max(this, min), max);
810     }
811 });/*
812  * Based on:
813  * Ext JS Library 1.1.1
814  * Copyright(c) 2006-2007, Ext JS, LLC.
815  *
816  * Originally Released Under LGPL - original licence link has changed is not relivant.
817  *
818  * Fork - LGPL
819  * <script type="text/javascript">
820  */
821  /**
822  * @class Array
823  */
824 Roo.applyIf(Array.prototype, {
825     /**
826      * Checks whether or not the specified object exists in the array.
827      * @param {Object} o The object to check for
828      * @return {Number} The index of o in the array (or -1 if it is not found)
829      */
830     indexOf : function(o){
831        for (var i = 0, len = this.length; i < len; i++){
832               if(this[i] == o) return i;
833        }
834            return -1;
835     },
836
837     /**
838      * Removes the specified object from the array.  If the object is not found nothing happens.
839      * @param {Object} o The object to remove
840      */
841     remove : function(o){
842        var index = this.indexOf(o);
843        if(index != -1){
844            this.splice(index, 1);
845        }
846     },
847     /**
848      * Map (JS 1.6 compatibility)
849      * @param {Function} function  to call
850      */
851     map : function(fun /*, thisp*/)
852     {
853         var len = this.length >>> 0;
854         if (typeof fun != "function")
855             throw new TypeError();
856
857         var res = new Array(len);
858         var thisp = arguments[1];
859         for (var i = 0; i < len; i++)
860         {
861             if (i in this)
862                 res[i] = fun.call(thisp, this[i], i, this);
863         }
864
865         return res;
866     }
867     
868 });
869
870
871
872 if (!Array.prototype.map)
873 {
874   Array.prototype.
875 }/*
876  * Based on:
877  * Ext JS Library 1.1.1
878  * Copyright(c) 2006-2007, Ext JS, LLC.
879  *
880  * Originally Released Under LGPL - original licence link has changed is not relivant.
881  *
882  * Fork - LGPL
883  * <script type="text/javascript">
884  */
885
886 /**
887  * @class Date
888  *
889  * The date parsing and format syntax is a subset of
890  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
891  * supported will provide results equivalent to their PHP versions.
892  *
893  * Following is the list of all currently supported formats:
894  *<pre>
895 Sample date:
896 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
897
898 Format  Output      Description
899 ------  ----------  --------------------------------------------------------------
900   d      10         Day of the month, 2 digits with leading zeros
901   D      Wed        A textual representation of a day, three letters
902   j      10         Day of the month without leading zeros
903   l      Wednesday  A full textual representation of the day of the week
904   S      th         English ordinal day of month suffix, 2 chars (use with j)
905   w      3          Numeric representation of the day of the week
906   z      9          The julian date, or day of the year (0-365)
907   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
908   F      January    A full textual representation of the month
909   m      01         Numeric representation of a month, with leading zeros
910   M      Jan        Month name abbreviation, three letters
911   n      1          Numeric representation of a month, without leading zeros
912   t      31         Number of days in the given month
913   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
914   Y      2007       A full numeric representation of a year, 4 digits
915   y      07         A two digit representation of a year
916   a      pm         Lowercase Ante meridiem and Post meridiem
917   A      PM         Uppercase Ante meridiem and Post meridiem
918   g      3          12-hour format of an hour without leading zeros
919   G      15         24-hour format of an hour without leading zeros
920   h      03         12-hour format of an hour with leading zeros
921   H      15         24-hour format of an hour with leading zeros
922   i      05         Minutes with leading zeros
923   s      01         Seconds, with leading zeros
924   O      -0600      Difference to Greenwich time (GMT) in hours
925   T      CST        Timezone setting of the machine running the code
926   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
927 </pre>
928  *
929  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
930  * <pre><code>
931 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
932 document.write(dt.format('Y-m-d'));                         //2007-01-10
933 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
934 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
935  </code></pre>
936  *
937  * Here are some standard date/time patterns that you might find helpful.  They
938  * are not part of the source of Date.js, but to use them you can simply copy this
939  * block of code into any script that is included after Date.js and they will also become
940  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
941  * <pre><code>
942 Date.patterns = {
943     ISO8601Long:"Y-m-d H:i:s",
944     ISO8601Short:"Y-m-d",
945     ShortDate: "n/j/Y",
946     LongDate: "l, F d, Y",
947     FullDateTime: "l, F d, Y g:i:s A",
948     MonthDay: "F d",
949     ShortTime: "g:i A",
950     LongTime: "g:i:s A",
951     SortableDateTime: "Y-m-d\\TH:i:s",
952     UniversalSortableDateTime: "Y-m-d H:i:sO",
953     YearMonth: "F, Y"
954 };
955 </code></pre>
956  *
957  * Example usage:
958  * <pre><code>
959 var dt = new Date();
960 document.write(dt.format(Date.patterns.ShortDate));
961  </code></pre>
962  */
963
964 /*
965  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
966  * They generate precompiled functions from date formats instead of parsing and
967  * processing the pattern every time you format a date.  These functions are available
968  * on every Date object (any javascript function).
969  *
970  * The original article and download are here:
971  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
972  *
973  */
974  
975  
976  // was in core
977 /**
978  Returns the number of milliseconds between this date and date
979  @param {Date} date (optional) Defaults to now
980  @return {Number} The diff in milliseconds
981  @member Date getElapsed
982  */
983 Date.prototype.getElapsed = function(date) {
984         return Math.abs((date || new Date()).getTime()-this.getTime());
985 };
986 // was in date file..
987
988
989 // private
990 Date.parseFunctions = {count:0};
991 // private
992 Date.parseRegexes = [];
993 // private
994 Date.formatFunctions = {count:0};
995
996 // private
997 Date.prototype.dateFormat = function(format) {
998     if (Date.formatFunctions[format] == null) {
999         Date.createNewFormat(format);
1000     }
1001     var func = Date.formatFunctions[format];
1002     return this[func]();
1003 };
1004
1005
1006 /**
1007  * Formats a date given the supplied format string
1008  * @param {String} format The format string
1009  * @return {String} The formatted date
1010  * @method
1011  */
1012 Date.prototype.format = Date.prototype.dateFormat;
1013
1014 // private
1015 Date.createNewFormat = function(format) {
1016     var funcName = "format" + Date.formatFunctions.count++;
1017     Date.formatFunctions[format] = funcName;
1018     var code = "Date.prototype." + funcName + " = function(){return ";
1019     var special = false;
1020     var ch = '';
1021     for (var i = 0; i < format.length; ++i) {
1022         ch = format.charAt(i);
1023         if (!special && ch == "\\") {
1024             special = true;
1025         }
1026         else if (special) {
1027             special = false;
1028             code += "'" + String.escape(ch) + "' + ";
1029         }
1030         else {
1031             code += Date.getFormatCode(ch);
1032         }
1033     }
1034     /** eval:var:zzzzzzzzzzzzz */
1035     eval(code.substring(0, code.length - 3) + ";}");
1036 };
1037
1038 // private
1039 Date.getFormatCode = function(character) {
1040     switch (character) {
1041     case "d":
1042         return "String.leftPad(this.getDate(), 2, '0') + ";
1043     case "D":
1044         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1045     case "j":
1046         return "this.getDate() + ";
1047     case "l":
1048         return "Date.dayNames[this.getDay()] + ";
1049     case "S":
1050         return "this.getSuffix() + ";
1051     case "w":
1052         return "this.getDay() + ";
1053     case "z":
1054         return "this.getDayOfYear() + ";
1055     case "W":
1056         return "this.getWeekOfYear() + ";
1057     case "F":
1058         return "Date.monthNames[this.getMonth()] + ";
1059     case "m":
1060         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1061     case "M":
1062         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1063     case "n":
1064         return "(this.getMonth() + 1) + ";
1065     case "t":
1066         return "this.getDaysInMonth() + ";
1067     case "L":
1068         return "(this.isLeapYear() ? 1 : 0) + ";
1069     case "Y":
1070         return "this.getFullYear() + ";
1071     case "y":
1072         return "('' + this.getFullYear()).substring(2, 4) + ";
1073     case "a":
1074         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1075     case "A":
1076         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1077     case "g":
1078         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1079     case "G":
1080         return "this.getHours() + ";
1081     case "h":
1082         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1083     case "H":
1084         return "String.leftPad(this.getHours(), 2, '0') + ";
1085     case "i":
1086         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1087     case "s":
1088         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1089     case "O":
1090         return "this.getGMTOffset() + ";
1091     case "T":
1092         return "this.getTimezone() + ";
1093     case "Z":
1094         return "(this.getTimezoneOffset() * -60) + ";
1095     default:
1096         return "'" + String.escape(character) + "' + ";
1097     }
1098 };
1099
1100 /**
1101  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1102  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1103  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1104  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1105  * string or the parse operation will fail.
1106  * Example Usage:
1107 <pre><code>
1108 //dt = Fri May 25 2007 (current date)
1109 var dt = new Date();
1110
1111 //dt = Thu May 25 2006 (today's month/day in 2006)
1112 dt = Date.parseDate("2006", "Y");
1113
1114 //dt = Sun Jan 15 2006 (all date parts specified)
1115 dt = Date.parseDate("2006-1-15", "Y-m-d");
1116
1117 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1118 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1119 </code></pre>
1120  * @param {String} input The unparsed date as a string
1121  * @param {String} format The format the date is in
1122  * @return {Date} The parsed date
1123  * @static
1124  */
1125 Date.parseDate = function(input, format) {
1126     if (Date.parseFunctions[format] == null) {
1127         Date.createParser(format);
1128     }
1129     var func = Date.parseFunctions[format];
1130     return Date[func](input);
1131 };
1132 /**
1133  * @private
1134  */
1135 Date.createParser = function(format) {
1136     var funcName = "parse" + Date.parseFunctions.count++;
1137     var regexNum = Date.parseRegexes.length;
1138     var currentGroup = 1;
1139     Date.parseFunctions[format] = funcName;
1140
1141     var code = "Date." + funcName + " = function(input){\n"
1142         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1143         + "var d = new Date();\n"
1144         + "y = d.getFullYear();\n"
1145         + "m = d.getMonth();\n"
1146         + "d = d.getDate();\n"
1147         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1148         + "if (results && results.length > 0) {";
1149     var regex = "";
1150
1151     var special = false;
1152     var ch = '';
1153     for (var i = 0; i < format.length; ++i) {
1154         ch = format.charAt(i);
1155         if (!special && ch == "\\") {
1156             special = true;
1157         }
1158         else if (special) {
1159             special = false;
1160             regex += String.escape(ch);
1161         }
1162         else {
1163             var obj = Date.formatCodeToRegex(ch, currentGroup);
1164             currentGroup += obj.g;
1165             regex += obj.s;
1166             if (obj.g && obj.c) {
1167                 code += obj.c;
1168             }
1169         }
1170     }
1171
1172     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1173         + "{v = new Date(y, m, d, h, i, s);}\n"
1174         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1175         + "{v = new Date(y, m, d, h, i);}\n"
1176         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1177         + "{v = new Date(y, m, d, h);}\n"
1178         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1179         + "{v = new Date(y, m, d);}\n"
1180         + "else if (y >= 0 && m >= 0)\n"
1181         + "{v = new Date(y, m);}\n"
1182         + "else if (y >= 0)\n"
1183         + "{v = new Date(y);}\n"
1184         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1185         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1186         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1187         + ";}";
1188
1189     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1190     /** eval:var:zzzzzzzzzzzzz */
1191     eval(code);
1192 };
1193
1194 // private
1195 Date.formatCodeToRegex = function(character, currentGroup) {
1196     switch (character) {
1197     case "D":
1198         return {g:0,
1199         c:null,
1200         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1201     case "j":
1202         return {g:1,
1203             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1204             s:"(\\d{1,2})"}; // day of month without leading zeroes
1205     case "d":
1206         return {g:1,
1207             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1208             s:"(\\d{2})"}; // day of month with leading zeroes
1209     case "l":
1210         return {g:0,
1211             c:null,
1212             s:"(?:" + Date.dayNames.join("|") + ")"};
1213     case "S":
1214         return {g:0,
1215             c:null,
1216             s:"(?:st|nd|rd|th)"};
1217     case "w":
1218         return {g:0,
1219             c:null,
1220             s:"\\d"};
1221     case "z":
1222         return {g:0,
1223             c:null,
1224             s:"(?:\\d{1,3})"};
1225     case "W":
1226         return {g:0,
1227             c:null,
1228             s:"(?:\\d{2})"};
1229     case "F":
1230         return {g:1,
1231             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1232             s:"(" + Date.monthNames.join("|") + ")"};
1233     case "M":
1234         return {g:1,
1235             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1236             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1237     case "n":
1238         return {g:1,
1239             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1240             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1241     case "m":
1242         return {g:1,
1243             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1244             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1245     case "t":
1246         return {g:0,
1247             c:null,
1248             s:"\\d{1,2}"};
1249     case "L":
1250         return {g:0,
1251             c:null,
1252             s:"(?:1|0)"};
1253     case "Y":
1254         return {g:1,
1255             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1256             s:"(\\d{4})"};
1257     case "y":
1258         return {g:1,
1259             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1260                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1261             s:"(\\d{1,2})"};
1262     case "a":
1263         return {g:1,
1264             c:"if (results[" + currentGroup + "] == 'am') {\n"
1265                 + "if (h == 12) { h = 0; }\n"
1266                 + "} else { if (h < 12) { h += 12; }}",
1267             s:"(am|pm)"};
1268     case "A":
1269         return {g:1,
1270             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1271                 + "if (h == 12) { h = 0; }\n"
1272                 + "} else { if (h < 12) { h += 12; }}",
1273             s:"(AM|PM)"};
1274     case "g":
1275     case "G":
1276         return {g:1,
1277             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1278             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1279     case "h":
1280     case "H":
1281         return {g:1,
1282             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1283             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1284     case "i":
1285         return {g:1,
1286             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1287             s:"(\\d{2})"};
1288     case "s":
1289         return {g:1,
1290             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1291             s:"(\\d{2})"};
1292     case "O":
1293         return {g:1,
1294             c:[
1295                 "o = results[", currentGroup, "];\n",
1296                 "var sn = o.substring(0,1);\n", // get + / - sign
1297                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1298                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1299                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1300                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1301             ].join(""),
1302             s:"([+\-]\\d{4})"};
1303     case "T":
1304         return {g:0,
1305             c:null,
1306             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1307     case "Z":
1308         return {g:1,
1309             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1310                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1311             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1312     default:
1313         return {g:0,
1314             c:null,
1315             s:String.escape(character)};
1316     }
1317 };
1318
1319 /**
1320  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1321  * @return {String} The abbreviated timezone name (e.g. 'CST')
1322  */
1323 Date.prototype.getTimezone = function() {
1324     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1325 };
1326
1327 /**
1328  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1329  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1330  */
1331 Date.prototype.getGMTOffset = function() {
1332     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1333         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1334         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1335 };
1336
1337 /**
1338  * Get the numeric day number of the year, adjusted for leap year.
1339  * @return {Number} 0 through 364 (365 in leap years)
1340  */
1341 Date.prototype.getDayOfYear = function() {
1342     var num = 0;
1343     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1344     for (var i = 0; i < this.getMonth(); ++i) {
1345         num += Date.daysInMonth[i];
1346     }
1347     return num + this.getDate() - 1;
1348 };
1349
1350 /**
1351  * Get the string representation of the numeric week number of the year
1352  * (equivalent to the format specifier 'W').
1353  * @return {String} '00' through '52'
1354  */
1355 Date.prototype.getWeekOfYear = function() {
1356     // Skip to Thursday of this week
1357     var now = this.getDayOfYear() + (4 - this.getDay());
1358     // Find the first Thursday of the year
1359     var jan1 = new Date(this.getFullYear(), 0, 1);
1360     var then = (7 - jan1.getDay() + 4);
1361     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1362 };
1363
1364 /**
1365  * Whether or not the current date is in a leap year.
1366  * @return {Boolean} True if the current date is in a leap year, else false
1367  */
1368 Date.prototype.isLeapYear = function() {
1369     var year = this.getFullYear();
1370     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1371 };
1372
1373 /**
1374  * Get the first day of the current month, adjusted for leap year.  The returned value
1375  * is the numeric day index within the week (0-6) which can be used in conjunction with
1376  * the {@link #monthNames} array to retrieve the textual day name.
1377  * Example:
1378  *<pre><code>
1379 var dt = new Date('1/10/2007');
1380 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1381 </code></pre>
1382  * @return {Number} The day number (0-6)
1383  */
1384 Date.prototype.getFirstDayOfMonth = function() {
1385     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1386     return (day < 0) ? (day + 7) : day;
1387 };
1388
1389 /**
1390  * Get the last day of the current month, adjusted for leap year.  The returned value
1391  * is the numeric day index within the week (0-6) which can be used in conjunction with
1392  * the {@link #monthNames} array to retrieve the textual day name.
1393  * Example:
1394  *<pre><code>
1395 var dt = new Date('1/10/2007');
1396 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1397 </code></pre>
1398  * @return {Number} The day number (0-6)
1399  */
1400 Date.prototype.getLastDayOfMonth = function() {
1401     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1402     return (day < 0) ? (day + 7) : day;
1403 };
1404
1405
1406 /**
1407  * Get the first date of this date's month
1408  * @return {Date}
1409  */
1410 Date.prototype.getFirstDateOfMonth = function() {
1411     return new Date(this.getFullYear(), this.getMonth(), 1);
1412 };
1413
1414 /**
1415  * Get the last date of this date's month
1416  * @return {Date}
1417  */
1418 Date.prototype.getLastDateOfMonth = function() {
1419     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1420 };
1421 /**
1422  * Get the number of days in the current month, adjusted for leap year.
1423  * @return {Number} The number of days in the month
1424  */
1425 Date.prototype.getDaysInMonth = function() {
1426     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1427     return Date.daysInMonth[this.getMonth()];
1428 };
1429
1430 /**
1431  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1432  * @return {String} 'st, 'nd', 'rd' or 'th'
1433  */
1434 Date.prototype.getSuffix = function() {
1435     switch (this.getDate()) {
1436         case 1:
1437         case 21:
1438         case 31:
1439             return "st";
1440         case 2:
1441         case 22:
1442             return "nd";
1443         case 3:
1444         case 23:
1445             return "rd";
1446         default:
1447             return "th";
1448     }
1449 };
1450
1451 // private
1452 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1453
1454 /**
1455  * An array of textual month names.
1456  * Override these values for international dates, for example...
1457  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1458  * @type Array
1459  * @static
1460  */
1461 Date.monthNames =
1462    ["January",
1463     "February",
1464     "March",
1465     "April",
1466     "May",
1467     "June",
1468     "July",
1469     "August",
1470     "September",
1471     "October",
1472     "November",
1473     "December"];
1474
1475 /**
1476  * An array of textual day names.
1477  * Override these values for international dates, for example...
1478  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1479  * @type Array
1480  * @static
1481  */
1482 Date.dayNames =
1483    ["Sunday",
1484     "Monday",
1485     "Tuesday",
1486     "Wednesday",
1487     "Thursday",
1488     "Friday",
1489     "Saturday"];
1490
1491 // private
1492 Date.y2kYear = 50;
1493 // private
1494 Date.monthNumbers = {
1495     Jan:0,
1496     Feb:1,
1497     Mar:2,
1498     Apr:3,
1499     May:4,
1500     Jun:5,
1501     Jul:6,
1502     Aug:7,
1503     Sep:8,
1504     Oct:9,
1505     Nov:10,
1506     Dec:11};
1507
1508 /**
1509  * Creates and returns a new Date instance with the exact same date value as the called instance.
1510  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1511  * variable will also be changed.  When the intention is to create a new variable that will not
1512  * modify the original instance, you should create a clone.
1513  *
1514  * Example of correctly cloning a date:
1515  * <pre><code>
1516 //wrong way:
1517 var orig = new Date('10/1/2006');
1518 var copy = orig;
1519 copy.setDate(5);
1520 document.write(orig);  //returns 'Thu Oct 05 2006'!
1521
1522 //correct way:
1523 var orig = new Date('10/1/2006');
1524 var copy = orig.clone();
1525 copy.setDate(5);
1526 document.write(orig);  //returns 'Thu Oct 01 2006'
1527 </code></pre>
1528  * @return {Date} The new Date instance
1529  */
1530 Date.prototype.clone = function() {
1531         return new Date(this.getTime());
1532 };
1533
1534 /**
1535  * Clears any time information from this date
1536  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1537  @return {Date} this or the clone
1538  */
1539 Date.prototype.clearTime = function(clone){
1540     if(clone){
1541         return this.clone().clearTime();
1542     }
1543     this.setHours(0);
1544     this.setMinutes(0);
1545     this.setSeconds(0);
1546     this.setMilliseconds(0);
1547     return this;
1548 };
1549
1550 // private
1551 // safari setMonth is broken
1552 if(Roo.isSafari){
1553     Date.brokenSetMonth = Date.prototype.setMonth;
1554         Date.prototype.setMonth = function(num){
1555                 if(num <= -1){
1556                         var n = Math.ceil(-num);
1557                         var back_year = Math.ceil(n/12);
1558                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1559                         this.setFullYear(this.getFullYear() - back_year);
1560                         return Date.brokenSetMonth.call(this, month);
1561                 } else {
1562                         return Date.brokenSetMonth.apply(this, arguments);
1563                 }
1564         };
1565 }
1566
1567 /** Date interval constant 
1568 * @static 
1569 * @type String */
1570 Date.MILLI = "ms";
1571 /** Date interval constant 
1572 * @static 
1573 * @type String */
1574 Date.SECOND = "s";
1575 /** Date interval constant 
1576 * @static 
1577 * @type String */
1578 Date.MINUTE = "mi";
1579 /** Date interval constant 
1580 * @static 
1581 * @type String */
1582 Date.HOUR = "h";
1583 /** Date interval constant 
1584 * @static 
1585 * @type String */
1586 Date.DAY = "d";
1587 /** Date interval constant 
1588 * @static 
1589 * @type String */
1590 Date.MONTH = "mo";
1591 /** Date interval constant 
1592 * @static 
1593 * @type String */
1594 Date.YEAR = "y";
1595
1596 /**
1597  * Provides a convenient method of performing basic date arithmetic.  This method
1598  * does not modify the Date instance being called - it creates and returns
1599  * a new Date instance containing the resulting date value.
1600  *
1601  * Examples:
1602  * <pre><code>
1603 //Basic usage:
1604 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1605 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1606
1607 //Negative values will subtract correctly:
1608 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1609 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1610
1611 //You can even chain several calls together in one line!
1612 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1613 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1614  </code></pre>
1615  *
1616  * @param {String} interval   A valid date interval enum value
1617  * @param {Number} value      The amount to add to the current date
1618  * @return {Date} The new Date instance
1619  */
1620 Date.prototype.add = function(interval, value){
1621   var d = this.clone();
1622   if (!interval || value === 0) return d;
1623   switch(interval.toLowerCase()){
1624     case Date.MILLI:
1625       d.setMilliseconds(this.getMilliseconds() + value);
1626       break;
1627     case Date.SECOND:
1628       d.setSeconds(this.getSeconds() + value);
1629       break;
1630     case Date.MINUTE:
1631       d.setMinutes(this.getMinutes() + value);
1632       break;
1633     case Date.HOUR:
1634       d.setHours(this.getHours() + value);
1635       break;
1636     case Date.DAY:
1637       d.setDate(this.getDate() + value);
1638       break;
1639     case Date.MONTH:
1640       var day = this.getDate();
1641       if(day > 28){
1642           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1643       }
1644       d.setDate(day);
1645       d.setMonth(this.getMonth() + value);
1646       break;
1647     case Date.YEAR:
1648       d.setFullYear(this.getFullYear() + value);
1649       break;
1650   }
1651   return d;
1652 };/*
1653  * Based on:
1654  * Ext JS Library 1.1.1
1655  * Copyright(c) 2006-2007, Ext JS, LLC.
1656  *
1657  * Originally Released Under LGPL - original licence link has changed is not relivant.
1658  *
1659  * Fork - LGPL
1660  * <script type="text/javascript">
1661  */
1662
1663 Roo.lib.Dom = {
1664     getViewWidth : function(full) {
1665         return full ? this.getDocumentWidth() : this.getViewportWidth();
1666     },
1667
1668     getViewHeight : function(full) {
1669         return full ? this.getDocumentHeight() : this.getViewportHeight();
1670     },
1671
1672     getDocumentHeight: function() {
1673         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1674         return Math.max(scrollHeight, this.getViewportHeight());
1675     },
1676
1677     getDocumentWidth: function() {
1678         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1679         return Math.max(scrollWidth, this.getViewportWidth());
1680     },
1681
1682     getViewportHeight: function() {
1683         var height = self.innerHeight;
1684         var mode = document.compatMode;
1685
1686         if ((mode || Roo.isIE) && !Roo.isOpera) {
1687             height = (mode == "CSS1Compat") ?
1688                      document.documentElement.clientHeight :
1689                      document.body.clientHeight;
1690         }
1691
1692         return height;
1693     },
1694
1695     getViewportWidth: function() {
1696         var width = self.innerWidth;
1697         var mode = document.compatMode;
1698
1699         if (mode || Roo.isIE) {
1700             width = (mode == "CSS1Compat") ?
1701                     document.documentElement.clientWidth :
1702                     document.body.clientWidth;
1703         }
1704         return width;
1705     },
1706
1707     isAncestor : function(p, c) {
1708         p = Roo.getDom(p);
1709         c = Roo.getDom(c);
1710         if (!p || !c) {
1711             return false;
1712         }
1713
1714         if (p.contains && !Roo.isSafari) {
1715             return p.contains(c);
1716         } else if (p.compareDocumentPosition) {
1717             return !!(p.compareDocumentPosition(c) & 16);
1718         } else {
1719             var parent = c.parentNode;
1720             while (parent) {
1721                 if (parent == p) {
1722                     return true;
1723                 }
1724                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1725                     return false;
1726                 }
1727                 parent = parent.parentNode;
1728             }
1729             return false;
1730         }
1731     },
1732
1733     getRegion : function(el) {
1734         return Roo.lib.Region.getRegion(el);
1735     },
1736
1737     getY : function(el) {
1738         return this.getXY(el)[1];
1739     },
1740
1741     getX : function(el) {
1742         return this.getXY(el)[0];
1743     },
1744
1745     getXY : function(el) {
1746         var p, pe, b, scroll, bd = document.body;
1747         el = Roo.getDom(el);
1748         var fly = Roo.lib.AnimBase.fly;
1749         if (el.getBoundingClientRect) {
1750             b = el.getBoundingClientRect();
1751             scroll = fly(document).getScroll();
1752             return [b.left + scroll.left, b.top + scroll.top];
1753         }
1754         var x = 0, y = 0;
1755
1756         p = el;
1757
1758         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1759
1760         while (p) {
1761
1762             x += p.offsetLeft;
1763             y += p.offsetTop;
1764
1765             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1766                 hasAbsolute = true;
1767             }
1768
1769             if (Roo.isGecko) {
1770                 pe = fly(p);
1771
1772                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1773                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1774
1775
1776                 x += bl;
1777                 y += bt;
1778
1779
1780                 if (p != el && pe.getStyle('overflow') != 'visible') {
1781                     x += bl;
1782                     y += bt;
1783                 }
1784             }
1785             p = p.offsetParent;
1786         }
1787
1788         if (Roo.isSafari && hasAbsolute) {
1789             x -= bd.offsetLeft;
1790             y -= bd.offsetTop;
1791         }
1792
1793         if (Roo.isGecko && !hasAbsolute) {
1794             var dbd = fly(bd);
1795             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1796             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1797         }
1798
1799         p = el.parentNode;
1800         while (p && p != bd) {
1801             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1802                 x -= p.scrollLeft;
1803                 y -= p.scrollTop;
1804             }
1805             p = p.parentNode;
1806         }
1807         return [x, y];
1808     },
1809  
1810   
1811
1812
1813     setXY : function(el, xy) {
1814         el = Roo.fly(el, '_setXY');
1815         el.position();
1816         var pts = el.translatePoints(xy);
1817         if (xy[0] !== false) {
1818             el.dom.style.left = pts.left + "px";
1819         }
1820         if (xy[1] !== false) {
1821             el.dom.style.top = pts.top + "px";
1822         }
1823     },
1824
1825     setX : function(el, x) {
1826         this.setXY(el, [x, false]);
1827     },
1828
1829     setY : function(el, y) {
1830         this.setXY(el, [false, y]);
1831     }
1832 };
1833 /*
1834  * Portions of this file are based on pieces of Yahoo User Interface Library
1835  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1836  * YUI licensed under the BSD License:
1837  * http://developer.yahoo.net/yui/license.txt
1838  * <script type="text/javascript">
1839  *
1840  */
1841
1842 Roo.lib.Event = function() {
1843     var loadComplete = false;
1844     var listeners = [];
1845     var unloadListeners = [];
1846     var retryCount = 0;
1847     var onAvailStack = [];
1848     var counter = 0;
1849     var lastError = null;
1850
1851     return {
1852         POLL_RETRYS: 200,
1853         POLL_INTERVAL: 20,
1854         EL: 0,
1855         TYPE: 1,
1856         FN: 2,
1857         WFN: 3,
1858         OBJ: 3,
1859         ADJ_SCOPE: 4,
1860         _interval: null,
1861
1862         startInterval: function() {
1863             if (!this._interval) {
1864                 var self = this;
1865                 var callback = function() {
1866                     self._tryPreloadAttach();
1867                 };
1868                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1869
1870             }
1871         },
1872
1873         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1874             onAvailStack.push({ id:         p_id,
1875                 fn:         p_fn,
1876                 obj:        p_obj,
1877                 override:   p_override,
1878                 checkReady: false    });
1879
1880             retryCount = this.POLL_RETRYS;
1881             this.startInterval();
1882         },
1883
1884
1885         addListener: function(el, eventName, fn) {
1886             el = Roo.getDom(el);
1887             if (!el || !fn) {
1888                 return false;
1889             }
1890
1891             if ("unload" == eventName) {
1892                 unloadListeners[unloadListeners.length] =
1893                 [el, eventName, fn];
1894                 return true;
1895             }
1896
1897             var wrappedFn = function(e) {
1898                 return fn(Roo.lib.Event.getEvent(e));
1899             };
1900
1901             var li = [el, eventName, fn, wrappedFn];
1902
1903             var index = listeners.length;
1904             listeners[index] = li;
1905
1906             this.doAdd(el, eventName, wrappedFn, false);
1907             return true;
1908
1909         },
1910
1911
1912         removeListener: function(el, eventName, fn) {
1913             var i, len;
1914
1915             el = Roo.getDom(el);
1916
1917             if(!fn) {
1918                 return this.purgeElement(el, false, eventName);
1919             }
1920
1921
1922             if ("unload" == eventName) {
1923
1924                 for (i = 0,len = unloadListeners.length; i < len; i++) {
1925                     var li = unloadListeners[i];
1926                     if (li &&
1927                         li[0] == el &&
1928                         li[1] == eventName &&
1929                         li[2] == fn) {
1930                         unloadListeners.splice(i, 1);
1931                         return true;
1932                     }
1933                 }
1934
1935                 return false;
1936             }
1937
1938             var cacheItem = null;
1939
1940
1941             var index = arguments[3];
1942
1943             if ("undefined" == typeof index) {
1944                 index = this._getCacheIndex(el, eventName, fn);
1945             }
1946
1947             if (index >= 0) {
1948                 cacheItem = listeners[index];
1949             }
1950
1951             if (!el || !cacheItem) {
1952                 return false;
1953             }
1954
1955             this.doRemove(el, eventName, cacheItem[this.WFN], false);
1956
1957             delete listeners[index][this.WFN];
1958             delete listeners[index][this.FN];
1959             listeners.splice(index, 1);
1960
1961             return true;
1962
1963         },
1964
1965
1966         getTarget: function(ev, resolveTextNode) {
1967             ev = ev.browserEvent || ev;
1968             var t = ev.target || ev.srcElement;
1969             return this.resolveTextNode(t);
1970         },
1971
1972
1973         resolveTextNode: function(node) {
1974             if (Roo.isSafari && node && 3 == node.nodeType) {
1975                 return node.parentNode;
1976             } else {
1977                 return node;
1978             }
1979         },
1980
1981
1982         getPageX: function(ev) {
1983             ev = ev.browserEvent || ev;
1984             var x = ev.pageX;
1985             if (!x && 0 !== x) {
1986                 x = ev.clientX || 0;
1987
1988                 if (Roo.isIE) {
1989                     x += this.getScroll()[1];
1990                 }
1991             }
1992
1993             return x;
1994         },
1995
1996
1997         getPageY: function(ev) {
1998             ev = ev.browserEvent || ev;
1999             var y = ev.pageY;
2000             if (!y && 0 !== y) {
2001                 y = ev.clientY || 0;
2002
2003                 if (Roo.isIE) {
2004                     y += this.getScroll()[0];
2005                 }
2006             }
2007
2008
2009             return y;
2010         },
2011
2012
2013         getXY: function(ev) {
2014             ev = ev.browserEvent || ev;
2015             return [this.getPageX(ev), this.getPageY(ev)];
2016         },
2017
2018
2019         getRelatedTarget: function(ev) {
2020             ev = ev.browserEvent || ev;
2021             var t = ev.relatedTarget;
2022             if (!t) {
2023                 if (ev.type == "mouseout") {
2024                     t = ev.toElement;
2025                 } else if (ev.type == "mouseover") {
2026                     t = ev.fromElement;
2027                 }
2028             }
2029
2030             return this.resolveTextNode(t);
2031         },
2032
2033
2034         getTime: function(ev) {
2035             ev = ev.browserEvent || ev;
2036             if (!ev.time) {
2037                 var t = new Date().getTime();
2038                 try {
2039                     ev.time = t;
2040                 } catch(ex) {
2041                     this.lastError = ex;
2042                     return t;
2043                 }
2044             }
2045
2046             return ev.time;
2047         },
2048
2049
2050         stopEvent: function(ev) {
2051             this.stopPropagation(ev);
2052             this.preventDefault(ev);
2053         },
2054
2055
2056         stopPropagation: function(ev) {
2057             ev = ev.browserEvent || ev;
2058             if (ev.stopPropagation) {
2059                 ev.stopPropagation();
2060             } else {
2061                 ev.cancelBubble = true;
2062             }
2063         },
2064
2065
2066         preventDefault: function(ev) {
2067             ev = ev.browserEvent || ev;
2068             if(ev.preventDefault) {
2069                 ev.preventDefault();
2070             } else {
2071                 ev.returnValue = false;
2072             }
2073         },
2074
2075
2076         getEvent: function(e) {
2077             var ev = e || window.event;
2078             if (!ev) {
2079                 var c = this.getEvent.caller;
2080                 while (c) {
2081                     ev = c.arguments[0];
2082                     if (ev && Event == ev.constructor) {
2083                         break;
2084                     }
2085                     c = c.caller;
2086                 }
2087             }
2088             return ev;
2089         },
2090
2091
2092         getCharCode: function(ev) {
2093             ev = ev.browserEvent || ev;
2094             return ev.charCode || ev.keyCode || 0;
2095         },
2096
2097
2098         _getCacheIndex: function(el, eventName, fn) {
2099             for (var i = 0,len = listeners.length; i < len; ++i) {
2100                 var li = listeners[i];
2101                 if (li &&
2102                     li[this.FN] == fn &&
2103                     li[this.EL] == el &&
2104                     li[this.TYPE] == eventName) {
2105                     return i;
2106                 }
2107             }
2108
2109             return -1;
2110         },
2111
2112
2113         elCache: {},
2114
2115
2116         getEl: function(id) {
2117             return document.getElementById(id);
2118         },
2119
2120
2121         clearCache: function() {
2122         },
2123
2124
2125         _load: function(e) {
2126             loadComplete = true;
2127             var EU = Roo.lib.Event;
2128
2129
2130             if (Roo.isIE) {
2131                 EU.doRemove(window, "load", EU._load);
2132             }
2133         },
2134
2135
2136         _tryPreloadAttach: function() {
2137
2138             if (this.locked) {
2139                 return false;
2140             }
2141
2142             this.locked = true;
2143
2144
2145             var tryAgain = !loadComplete;
2146             if (!tryAgain) {
2147                 tryAgain = (retryCount > 0);
2148             }
2149
2150
2151             var notAvail = [];
2152             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2153                 var item = onAvailStack[i];
2154                 if (item) {
2155                     var el = this.getEl(item.id);
2156
2157                     if (el) {
2158                         if (!item.checkReady ||
2159                             loadComplete ||
2160                             el.nextSibling ||
2161                             (document && document.body)) {
2162
2163                             var scope = el;
2164                             if (item.override) {
2165                                 if (item.override === true) {
2166                                     scope = item.obj;
2167                                 } else {
2168                                     scope = item.override;
2169                                 }
2170                             }
2171                             item.fn.call(scope, item.obj);
2172                             onAvailStack[i] = null;
2173                         }
2174                     } else {
2175                         notAvail.push(item);
2176                     }
2177                 }
2178             }
2179
2180             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2181
2182             if (tryAgain) {
2183
2184                 this.startInterval();
2185             } else {
2186                 clearInterval(this._interval);
2187                 this._interval = null;
2188             }
2189
2190             this.locked = false;
2191
2192             return true;
2193
2194         },
2195
2196
2197         purgeElement: function(el, recurse, eventName) {
2198             var elListeners = this.getListeners(el, eventName);
2199             if (elListeners) {
2200                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2201                     var l = elListeners[i];
2202                     this.removeListener(el, l.type, l.fn);
2203                 }
2204             }
2205
2206             if (recurse && el && el.childNodes) {
2207                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2208                     this.purgeElement(el.childNodes[i], recurse, eventName);
2209                 }
2210             }
2211         },
2212
2213
2214         getListeners: function(el, eventName) {
2215             var results = [], searchLists;
2216             if (!eventName) {
2217                 searchLists = [listeners, unloadListeners];
2218             } else if (eventName == "unload") {
2219                 searchLists = [unloadListeners];
2220             } else {
2221                 searchLists = [listeners];
2222             }
2223
2224             for (var j = 0; j < searchLists.length; ++j) {
2225                 var searchList = searchLists[j];
2226                 if (searchList && searchList.length > 0) {
2227                     for (var i = 0,len = searchList.length; i < len; ++i) {
2228                         var l = searchList[i];
2229                         if (l && l[this.EL] === el &&
2230                             (!eventName || eventName === l[this.TYPE])) {
2231                             results.push({
2232                                 type:   l[this.TYPE],
2233                                 fn:     l[this.FN],
2234                                 obj:    l[this.OBJ],
2235                                 adjust: l[this.ADJ_SCOPE],
2236                                 index:  i
2237                             });
2238                         }
2239                     }
2240                 }
2241             }
2242
2243             return (results.length) ? results : null;
2244         },
2245
2246
2247         _unload: function(e) {
2248
2249             var EU = Roo.lib.Event, i, j, l, len, index;
2250
2251             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2252                 l = unloadListeners[i];
2253                 if (l) {
2254                     var scope = window;
2255                     if (l[EU.ADJ_SCOPE]) {
2256                         if (l[EU.ADJ_SCOPE] === true) {
2257                             scope = l[EU.OBJ];
2258                         } else {
2259                             scope = l[EU.ADJ_SCOPE];
2260                         }
2261                     }
2262                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2263                     unloadListeners[i] = null;
2264                     l = null;
2265                     scope = null;
2266                 }
2267             }
2268
2269             unloadListeners = null;
2270
2271             if (listeners && listeners.length > 0) {
2272                 j = listeners.length;
2273                 while (j) {
2274                     index = j - 1;
2275                     l = listeners[index];
2276                     if (l) {
2277                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2278                                 l[EU.FN], index);
2279                     }
2280                     j = j - 1;
2281                 }
2282                 l = null;
2283
2284                 EU.clearCache();
2285             }
2286
2287             EU.doRemove(window, "unload", EU._unload);
2288
2289         },
2290
2291
2292         getScroll: function() {
2293             var dd = document.documentElement, db = document.body;
2294             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2295                 return [dd.scrollTop, dd.scrollLeft];
2296             } else if (db) {
2297                 return [db.scrollTop, db.scrollLeft];
2298             } else {
2299                 return [0, 0];
2300             }
2301         },
2302
2303
2304         doAdd: function () {
2305             if (window.addEventListener) {
2306                 return function(el, eventName, fn, capture) {
2307                     el.addEventListener(eventName, fn, (capture));
2308                 };
2309             } else if (window.attachEvent) {
2310                 return function(el, eventName, fn, capture) {
2311                     el.attachEvent("on" + eventName, fn);
2312                 };
2313             } else {
2314                 return function() {
2315                 };
2316             }
2317         }(),
2318
2319
2320         doRemove: function() {
2321             if (window.removeEventListener) {
2322                 return function (el, eventName, fn, capture) {
2323                     el.removeEventListener(eventName, fn, (capture));
2324                 };
2325             } else if (window.detachEvent) {
2326                 return function (el, eventName, fn) {
2327                     el.detachEvent("on" + eventName, fn);
2328                 };
2329             } else {
2330                 return function() {
2331                 };
2332             }
2333         }()
2334     };
2335     
2336 }();
2337 (function() {     
2338    
2339     var E = Roo.lib.Event;
2340     E.on = E.addListener;
2341     E.un = E.removeListener;
2342
2343     if (document && document.body) {
2344         E._load();
2345     } else {
2346         E.doAdd(window, "load", E._load);
2347     }
2348     E.doAdd(window, "unload", E._unload);
2349     E._tryPreloadAttach();
2350 })();
2351
2352 /*
2353  * Portions of this file are based on pieces of Yahoo User Interface Library
2354  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2355  * YUI licensed under the BSD License:
2356  * http://developer.yahoo.net/yui/license.txt
2357  * <script type="text/javascript">
2358  *
2359  */
2360
2361 (function() {
2362     
2363     Roo.lib.Ajax = {
2364         request : function(method, uri, cb, data, options) {
2365             if(options){
2366                 var hs = options.headers;
2367                 if(hs){
2368                     for(var h in hs){
2369                         if(hs.hasOwnProperty(h)){
2370                             this.initHeader(h, hs[h], false);
2371                         }
2372                     }
2373                 }
2374                 if(options.xmlData){
2375                     this.initHeader('Content-Type', 'text/xml', false);
2376                     method = 'POST';
2377                     data = options.xmlData;
2378                 }
2379             }
2380
2381             return this.asyncRequest(method, uri, cb, data);
2382         },
2383
2384         serializeForm : function(form) {
2385             if(typeof form == 'string') {
2386                 form = (document.getElementById(form) || document.forms[form]);
2387             }
2388
2389             var el, name, val, disabled, data = '', hasSubmit = false;
2390             for (var i = 0; i < form.elements.length; i++) {
2391                 el = form.elements[i];
2392                 disabled = form.elements[i].disabled;
2393                 name = form.elements[i].name;
2394                 val = form.elements[i].value;
2395
2396                 if (!disabled && name){
2397                     switch (el.type)
2398                             {
2399                         case 'select-one':
2400                         case 'select-multiple':
2401                             for (var j = 0; j < el.options.length; j++) {
2402                                 if (el.options[j].selected) {
2403                                     if (Roo.isIE) {
2404                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2405                                     }
2406                                     else {
2407                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2408                                     }
2409                                 }
2410                             }
2411                             break;
2412                         case 'radio':
2413                         case 'checkbox':
2414                             if (el.checked) {
2415                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2416                             }
2417                             break;
2418                         case 'file':
2419
2420                         case undefined:
2421
2422                         case 'reset':
2423
2424                         case 'button':
2425
2426                             break;
2427                         case 'submit':
2428                             if(hasSubmit == false) {
2429                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2430                                 hasSubmit = true;
2431                             }
2432                             break;
2433                         default:
2434                             data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2435                             break;
2436                     }
2437                 }
2438             }
2439             data = data.substr(0, data.length - 1);
2440             return data;
2441         },
2442
2443         headers:{},
2444
2445         hasHeaders:false,
2446
2447         useDefaultHeader:true,
2448
2449         defaultPostHeader:'application/x-www-form-urlencoded',
2450
2451         useDefaultXhrHeader:true,
2452
2453         defaultXhrHeader:'XMLHttpRequest',
2454
2455         hasDefaultHeaders:true,
2456
2457         defaultHeaders:{},
2458
2459         poll:{},
2460
2461         timeout:{},
2462
2463         pollInterval:50,
2464
2465         transactionId:0,
2466
2467         setProgId:function(id)
2468         {
2469             this.activeX.unshift(id);
2470         },
2471
2472         setDefaultPostHeader:function(b)
2473         {
2474             this.useDefaultHeader = b;
2475         },
2476
2477         setDefaultXhrHeader:function(b)
2478         {
2479             this.useDefaultXhrHeader = b;
2480         },
2481
2482         setPollingInterval:function(i)
2483         {
2484             if (typeof i == 'number' && isFinite(i)) {
2485                 this.pollInterval = i;
2486             }
2487         },
2488
2489         createXhrObject:function(transactionId)
2490         {
2491             var obj,http;
2492             try
2493             {
2494
2495                 http = new XMLHttpRequest();
2496
2497                 obj = { conn:http, tId:transactionId };
2498             }
2499             catch(e)
2500             {
2501                 for (var i = 0; i < this.activeX.length; ++i) {
2502                     try
2503                     {
2504
2505                         http = new ActiveXObject(this.activeX[i]);
2506
2507                         obj = { conn:http, tId:transactionId };
2508                         break;
2509                     }
2510                     catch(e) {
2511                     }
2512                 }
2513             }
2514             finally
2515             {
2516                 return obj;
2517             }
2518         },
2519
2520         getConnectionObject:function()
2521         {
2522             var o;
2523             var tId = this.transactionId;
2524
2525             try
2526             {
2527                 o = this.createXhrObject(tId);
2528                 if (o) {
2529                     this.transactionId++;
2530                 }
2531             }
2532             catch(e) {
2533             }
2534             finally
2535             {
2536                 return o;
2537             }
2538         },
2539
2540         asyncRequest:function(method, uri, callback, postData)
2541         {
2542             var o = this.getConnectionObject();
2543
2544             if (!o) {
2545                 return null;
2546             }
2547             else {
2548                 o.conn.open(method, uri, true);
2549
2550                 if (this.useDefaultXhrHeader) {
2551                     if (!this.defaultHeaders['X-Requested-With']) {
2552                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2553                     }
2554                 }
2555
2556                 if(postData && this.useDefaultHeader){
2557                     this.initHeader('Content-Type', this.defaultPostHeader);
2558                 }
2559
2560                  if (this.hasDefaultHeaders || this.hasHeaders) {
2561                     this.setHeader(o);
2562                 }
2563
2564                 this.handleReadyState(o, callback);
2565                 o.conn.send(postData || null);
2566
2567                 return o;
2568             }
2569         },
2570
2571         handleReadyState:function(o, callback)
2572         {
2573             var oConn = this;
2574
2575             if (callback && callback.timeout) {
2576                 this.timeout[o.tId] = window.setTimeout(function() {
2577                     oConn.abort(o, callback, true);
2578                 }, callback.timeout);
2579             }
2580
2581             this.poll[o.tId] = window.setInterval(
2582                     function() {
2583                         if (o.conn && o.conn.readyState == 4) {
2584                             window.clearInterval(oConn.poll[o.tId]);
2585                             delete oConn.poll[o.tId];
2586
2587                             if(callback && callback.timeout) {
2588                                 window.clearTimeout(oConn.timeout[o.tId]);
2589                                 delete oConn.timeout[o.tId];
2590                             }
2591
2592                             oConn.handleTransactionResponse(o, callback);
2593                         }
2594                     }
2595                     , this.pollInterval);
2596         },
2597
2598         handleTransactionResponse:function(o, callback, isAbort)
2599         {
2600
2601             if (!callback) {
2602                 this.releaseObject(o);
2603                 return;
2604             }
2605
2606             var httpStatus, responseObject;
2607
2608             try
2609             {
2610                 if (o.conn.status !== undefined && o.conn.status != 0) {
2611                     httpStatus = o.conn.status;
2612                 }
2613                 else {
2614                     httpStatus = 13030;
2615                 }
2616             }
2617             catch(e) {
2618
2619
2620                 httpStatus = 13030;
2621             }
2622
2623             if (httpStatus >= 200 && httpStatus < 300) {
2624                 responseObject = this.createResponseObject(o, callback.argument);
2625                 if (callback.success) {
2626                     if (!callback.scope) {
2627                         callback.success(responseObject);
2628                     }
2629                     else {
2630
2631
2632                         callback.success.apply(callback.scope, [responseObject]);
2633                     }
2634                 }
2635             }
2636             else {
2637                 switch (httpStatus) {
2638
2639                     case 12002:
2640                     case 12029:
2641                     case 12030:
2642                     case 12031:
2643                     case 12152:
2644                     case 13030:
2645                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2646                         if (callback.failure) {
2647                             if (!callback.scope) {
2648                                 callback.failure(responseObject);
2649                             }
2650                             else {
2651                                 callback.failure.apply(callback.scope, [responseObject]);
2652                             }
2653                         }
2654                         break;
2655                     default:
2656                         responseObject = this.createResponseObject(o, callback.argument);
2657                         if (callback.failure) {
2658                             if (!callback.scope) {
2659                                 callback.failure(responseObject);
2660                             }
2661                             else {
2662                                 callback.failure.apply(callback.scope, [responseObject]);
2663                             }
2664                         }
2665                 }
2666             }
2667
2668             this.releaseObject(o);
2669             responseObject = null;
2670         },
2671
2672         createResponseObject:function(o, callbackArg)
2673         {
2674             var obj = {};
2675             var headerObj = {};
2676
2677             try
2678             {
2679                 var headerStr = o.conn.getAllResponseHeaders();
2680                 var header = headerStr.split('\n');
2681                 for (var i = 0; i < header.length; i++) {
2682                     var delimitPos = header[i].indexOf(':');
2683                     if (delimitPos != -1) {
2684                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2685                     }
2686                 }
2687             }
2688             catch(e) {
2689             }
2690
2691             obj.tId = o.tId;
2692             obj.status = o.conn.status;
2693             obj.statusText = o.conn.statusText;
2694             obj.getResponseHeader = headerObj;
2695             obj.getAllResponseHeaders = headerStr;
2696             obj.responseText = o.conn.responseText;
2697             obj.responseXML = o.conn.responseXML;
2698
2699             if (typeof callbackArg !== undefined) {
2700                 obj.argument = callbackArg;
2701             }
2702
2703             return obj;
2704         },
2705
2706         createExceptionObject:function(tId, callbackArg, isAbort)
2707         {
2708             var COMM_CODE = 0;
2709             var COMM_ERROR = 'communication failure';
2710             var ABORT_CODE = -1;
2711             var ABORT_ERROR = 'transaction aborted';
2712
2713             var obj = {};
2714
2715             obj.tId = tId;
2716             if (isAbort) {
2717                 obj.status = ABORT_CODE;
2718                 obj.statusText = ABORT_ERROR;
2719             }
2720             else {
2721                 obj.status = COMM_CODE;
2722                 obj.statusText = COMM_ERROR;
2723             }
2724
2725             if (callbackArg) {
2726                 obj.argument = callbackArg;
2727             }
2728
2729             return obj;
2730         },
2731
2732         initHeader:function(label, value, isDefault)
2733         {
2734             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2735
2736             if (headerObj[label] === undefined) {
2737                 headerObj[label] = value;
2738             }
2739             else {
2740
2741
2742                 headerObj[label] = value + "," + headerObj[label];
2743             }
2744
2745             if (isDefault) {
2746                 this.hasDefaultHeaders = true;
2747             }
2748             else {
2749                 this.hasHeaders = true;
2750             }
2751         },
2752
2753
2754         setHeader:function(o)
2755         {
2756             if (this.hasDefaultHeaders) {
2757                 for (var prop in this.defaultHeaders) {
2758                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2759                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2760                     }
2761                 }
2762             }
2763
2764             if (this.hasHeaders) {
2765                 for (var prop in this.headers) {
2766                     if (this.headers.hasOwnProperty(prop)) {
2767                         o.conn.setRequestHeader(prop, this.headers[prop]);
2768                     }
2769                 }
2770                 this.headers = {};
2771                 this.hasHeaders = false;
2772             }
2773         },
2774
2775         resetDefaultHeaders:function() {
2776             delete this.defaultHeaders;
2777             this.defaultHeaders = {};
2778             this.hasDefaultHeaders = false;
2779         },
2780
2781         abort:function(o, callback, isTimeout)
2782         {
2783             if(this.isCallInProgress(o)) {
2784                 o.conn.abort();
2785                 window.clearInterval(this.poll[o.tId]);
2786                 delete this.poll[o.tId];
2787                 if (isTimeout) {
2788                     delete this.timeout[o.tId];
2789                 }
2790
2791                 this.handleTransactionResponse(o, callback, true);
2792
2793                 return true;
2794             }
2795             else {
2796                 return false;
2797             }
2798         },
2799
2800
2801         isCallInProgress:function(o)
2802         {
2803             if (o && o.conn) {
2804                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2805             }
2806             else {
2807
2808                 return false;
2809             }
2810         },
2811
2812
2813         releaseObject:function(o)
2814         {
2815
2816             o.conn = null;
2817
2818             o = null;
2819         },
2820
2821         activeX:[
2822         'MSXML2.XMLHTTP.3.0',
2823         'MSXML2.XMLHTTP',
2824         'Microsoft.XMLHTTP'
2825         ]
2826
2827
2828     };
2829 })();/*
2830  * Portions of this file are based on pieces of Yahoo User Interface Library
2831  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2832  * YUI licensed under the BSD License:
2833  * http://developer.yahoo.net/yui/license.txt
2834  * <script type="text/javascript">
2835  *
2836  */
2837
2838 Roo.lib.Region = function(t, r, b, l) {
2839     this.top = t;
2840     this[1] = t;
2841     this.right = r;
2842     this.bottom = b;
2843     this.left = l;
2844     this[0] = l;
2845 };
2846
2847
2848 Roo.lib.Region.prototype = {
2849     contains : function(region) {
2850         return ( region.left >= this.left &&
2851                  region.right <= this.right &&
2852                  region.top >= this.top &&
2853                  region.bottom <= this.bottom    );
2854
2855     },
2856
2857     getArea : function() {
2858         return ( (this.bottom - this.top) * (this.right - this.left) );
2859     },
2860
2861     intersect : function(region) {
2862         var t = Math.max(this.top, region.top);
2863         var r = Math.min(this.right, region.right);
2864         var b = Math.min(this.bottom, region.bottom);
2865         var l = Math.max(this.left, region.left);
2866
2867         if (b >= t && r >= l) {
2868             return new Roo.lib.Region(t, r, b, l);
2869         } else {
2870             return null;
2871         }
2872     },
2873     union : function(region) {
2874         var t = Math.min(this.top, region.top);
2875         var r = Math.max(this.right, region.right);
2876         var b = Math.max(this.bottom, region.bottom);
2877         var l = Math.min(this.left, region.left);
2878
2879         return new Roo.lib.Region(t, r, b, l);
2880     },
2881
2882     adjust : function(t, l, b, r) {
2883         this.top += t;
2884         this.left += l;
2885         this.right += r;
2886         this.bottom += b;
2887         return this;
2888     }
2889 };
2890
2891 Roo.lib.Region.getRegion = function(el) {
2892     var p = Roo.lib.Dom.getXY(el);
2893
2894     var t = p[1];
2895     var r = p[0] + el.offsetWidth;
2896     var b = p[1] + el.offsetHeight;
2897     var l = p[0];
2898
2899     return new Roo.lib.Region(t, r, b, l);
2900 };
2901 /*
2902  * Portions of this file are based on pieces of Yahoo User Interface Library
2903  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2904  * YUI licensed under the BSD License:
2905  * http://developer.yahoo.net/yui/license.txt
2906  * <script type="text/javascript">
2907  *
2908  */
2909 //@@dep Roo.lib.Region
2910
2911
2912 Roo.lib.Point = function(x, y) {
2913     if (x instanceof Array) {
2914         y = x[1];
2915         x = x[0];
2916     }
2917     this.x = this.right = this.left = this[0] = x;
2918     this.y = this.top = this.bottom = this[1] = y;
2919 };
2920
2921 Roo.lib.Point.prototype = new Roo.lib.Region();
2922 /*
2923  * Portions of this file are based on pieces of Yahoo User Interface Library
2924  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2925  * YUI licensed under the BSD License:
2926  * http://developer.yahoo.net/yui/license.txt
2927  * <script type="text/javascript">
2928  *
2929  */
2930  
2931 (function() {   
2932
2933     Roo.lib.Anim = {
2934         scroll : function(el, args, duration, easing, cb, scope) {
2935             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2936         },
2937
2938         motion : function(el, args, duration, easing, cb, scope) {
2939             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2940         },
2941
2942         color : function(el, args, duration, easing, cb, scope) {
2943             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2944         },
2945
2946         run : function(el, args, duration, easing, cb, scope, type) {
2947             type = type || Roo.lib.AnimBase;
2948             if (typeof easing == "string") {
2949                 easing = Roo.lib.Easing[easing];
2950             }
2951             var anim = new type(el, args, duration, easing);
2952             anim.animateX(function() {
2953                 Roo.callback(cb, scope);
2954             });
2955             return anim;
2956         }
2957     };
2958 })();/*
2959  * Portions of this file are based on pieces of Yahoo User Interface Library
2960  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2961  * YUI licensed under the BSD License:
2962  * http://developer.yahoo.net/yui/license.txt
2963  * <script type="text/javascript">
2964  *
2965  */
2966
2967 (function() {    
2968     var libFlyweight;
2969     
2970     function fly(el) {
2971         if (!libFlyweight) {
2972             libFlyweight = new Roo.Element.Flyweight();
2973         }
2974         libFlyweight.dom = el;
2975         return libFlyweight;
2976     }
2977
2978     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2979     
2980    
2981     
2982     Roo.lib.AnimBase = function(el, attributes, duration, method) {
2983         if (el) {
2984             this.init(el, attributes, duration, method);
2985         }
2986     };
2987
2988     Roo.lib.AnimBase.fly = fly;
2989     
2990     
2991     
2992     Roo.lib.AnimBase.prototype = {
2993
2994         toString: function() {
2995             var el = this.getEl();
2996             var id = el.id || el.tagName;
2997             return ("Anim " + id);
2998         },
2999
3000         patterns: {
3001             noNegatives:        /width|height|opacity|padding/i,
3002             offsetAttribute:  /^((width|height)|(top|left))$/,
3003             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3004             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3005         },
3006
3007
3008         doMethod: function(attr, start, end) {
3009             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3010         },
3011
3012
3013         setAttribute: function(attr, val, unit) {
3014             if (this.patterns.noNegatives.test(attr)) {
3015                 val = (val > 0) ? val : 0;
3016             }
3017
3018             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3019         },
3020
3021
3022         getAttribute: function(attr) {
3023             var el = this.getEl();
3024             var val = fly(el).getStyle(attr);
3025
3026             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3027                 return parseFloat(val);
3028             }
3029
3030             var a = this.patterns.offsetAttribute.exec(attr) || [];
3031             var pos = !!( a[3] );
3032             var box = !!( a[2] );
3033
3034
3035             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3036                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3037             } else {
3038                 val = 0;
3039             }
3040
3041             return val;
3042         },
3043
3044
3045         getDefaultUnit: function(attr) {
3046             if (this.patterns.defaultUnit.test(attr)) {
3047                 return 'px';
3048             }
3049
3050             return '';
3051         },
3052
3053         animateX : function(callback, scope) {
3054             var f = function() {
3055                 this.onComplete.removeListener(f);
3056                 if (typeof callback == "function") {
3057                     callback.call(scope || this, this);
3058                 }
3059             };
3060             this.onComplete.addListener(f, this);
3061             this.animate();
3062         },
3063
3064
3065         setRuntimeAttribute: function(attr) {
3066             var start;
3067             var end;
3068             var attributes = this.attributes;
3069
3070             this.runtimeAttributes[attr] = {};
3071
3072             var isset = function(prop) {
3073                 return (typeof prop !== 'undefined');
3074             };
3075
3076             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3077                 return false;
3078             }
3079
3080             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3081
3082
3083             if (isset(attributes[attr]['to'])) {
3084                 end = attributes[attr]['to'];
3085             } else if (isset(attributes[attr]['by'])) {
3086                 if (start.constructor == Array) {
3087                     end = [];
3088                     for (var i = 0, len = start.length; i < len; ++i) {
3089                         end[i] = start[i] + attributes[attr]['by'][i];
3090                     }
3091                 } else {
3092                     end = start + attributes[attr]['by'];
3093                 }
3094             }
3095
3096             this.runtimeAttributes[attr].start = start;
3097             this.runtimeAttributes[attr].end = end;
3098
3099
3100             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3101         },
3102
3103
3104         init: function(el, attributes, duration, method) {
3105
3106             var isAnimated = false;
3107
3108
3109             var startTime = null;
3110
3111
3112             var actualFrames = 0;
3113
3114
3115             el = Roo.getDom(el);
3116
3117
3118             this.attributes = attributes || {};
3119
3120
3121             this.duration = duration || 1;
3122
3123
3124             this.method = method || Roo.lib.Easing.easeNone;
3125
3126
3127             this.useSeconds = true;
3128
3129
3130             this.currentFrame = 0;
3131
3132
3133             this.totalFrames = Roo.lib.AnimMgr.fps;
3134
3135
3136             this.getEl = function() {
3137                 return el;
3138             };
3139
3140
3141             this.isAnimated = function() {
3142                 return isAnimated;
3143             };
3144
3145
3146             this.getStartTime = function() {
3147                 return startTime;
3148             };
3149
3150             this.runtimeAttributes = {};
3151
3152
3153             this.animate = function() {
3154                 if (this.isAnimated()) {
3155                     return false;
3156                 }
3157
3158                 this.currentFrame = 0;
3159
3160                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3161
3162                 Roo.lib.AnimMgr.registerElement(this);
3163             };
3164
3165
3166             this.stop = function(finish) {
3167                 if (finish) {
3168                     this.currentFrame = this.totalFrames;
3169                     this._onTween.fire();
3170                 }
3171                 Roo.lib.AnimMgr.stop(this);
3172             };
3173
3174             var onStart = function() {
3175                 this.onStart.fire();
3176
3177                 this.runtimeAttributes = {};
3178                 for (var attr in this.attributes) {
3179                     this.setRuntimeAttribute(attr);
3180                 }
3181
3182                 isAnimated = true;
3183                 actualFrames = 0;
3184                 startTime = new Date();
3185             };
3186
3187
3188             var onTween = function() {
3189                 var data = {
3190                     duration: new Date() - this.getStartTime(),
3191                     currentFrame: this.currentFrame
3192                 };
3193
3194                 data.toString = function() {
3195                     return (
3196                             'duration: ' + data.duration +
3197                             ', currentFrame: ' + data.currentFrame
3198                             );
3199                 };
3200
3201                 this.onTween.fire(data);
3202
3203                 var runtimeAttributes = this.runtimeAttributes;
3204
3205                 for (var attr in runtimeAttributes) {
3206                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3207                 }
3208
3209                 actualFrames += 1;
3210             };
3211
3212             var onComplete = function() {
3213                 var actual_duration = (new Date() - startTime) / 1000 ;
3214
3215                 var data = {
3216                     duration: actual_duration,
3217                     frames: actualFrames,
3218                     fps: actualFrames / actual_duration
3219                 };
3220
3221                 data.toString = function() {
3222                     return (
3223                             'duration: ' + data.duration +
3224                             ', frames: ' + data.frames +
3225                             ', fps: ' + data.fps
3226                             );
3227                 };
3228
3229                 isAnimated = false;
3230                 actualFrames = 0;
3231                 this.onComplete.fire(data);
3232             };
3233
3234
3235             this._onStart = new Roo.util.Event(this);
3236             this.onStart = new Roo.util.Event(this);
3237             this.onTween = new Roo.util.Event(this);
3238             this._onTween = new Roo.util.Event(this);
3239             this.onComplete = new Roo.util.Event(this);
3240             this._onComplete = new Roo.util.Event(this);
3241             this._onStart.addListener(onStart);
3242             this._onTween.addListener(onTween);
3243             this._onComplete.addListener(onComplete);
3244         }
3245     };
3246 })();
3247 /*
3248  * Portions of this file are based on pieces of Yahoo User Interface Library
3249  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3250  * YUI licensed under the BSD License:
3251  * http://developer.yahoo.net/yui/license.txt
3252  * <script type="text/javascript">
3253  *
3254  */
3255
3256 Roo.lib.AnimMgr = new function() {
3257
3258         var thread = null;
3259
3260
3261         var queue = [];
3262
3263
3264         var tweenCount = 0;
3265
3266
3267         this.fps = 1000;
3268
3269
3270         this.delay = 1;
3271
3272
3273         this.registerElement = function(tween) {
3274             queue[queue.length] = tween;
3275             tweenCount += 1;
3276             tween._onStart.fire();
3277             this.start();
3278         };
3279
3280
3281         this.unRegister = function(tween, index) {
3282             tween._onComplete.fire();
3283             index = index || getIndex(tween);
3284             if (index != -1) {
3285                 queue.splice(index, 1);
3286             }
3287
3288             tweenCount -= 1;
3289             if (tweenCount <= 0) {
3290                 this.stop();
3291             }
3292         };
3293
3294
3295         this.start = function() {
3296             if (thread === null) {
3297                 thread = setInterval(this.run, this.delay);
3298             }
3299         };
3300
3301
3302         this.stop = function(tween) {
3303             if (!tween) {
3304                 clearInterval(thread);
3305
3306                 for (var i = 0, len = queue.length; i < len; ++i) {
3307                     if (queue[0].isAnimated()) {
3308                         this.unRegister(queue[0], 0);
3309                     }
3310                 }
3311
3312                 queue = [];
3313                 thread = null;
3314                 tweenCount = 0;
3315             }
3316             else {
3317                 this.unRegister(tween);
3318             }
3319         };
3320
3321
3322         this.run = function() {
3323             for (var i = 0, len = queue.length; i < len; ++i) {
3324                 var tween = queue[i];
3325                 if (!tween || !tween.isAnimated()) {
3326                     continue;
3327                 }
3328
3329                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3330                 {
3331                     tween.currentFrame += 1;
3332
3333                     if (tween.useSeconds) {
3334                         correctFrame(tween);
3335                     }
3336                     tween._onTween.fire();
3337                 }
3338                 else {
3339                     Roo.lib.AnimMgr.stop(tween, i);
3340                 }
3341             }
3342         };
3343
3344         var getIndex = function(anim) {
3345             for (var i = 0, len = queue.length; i < len; ++i) {
3346                 if (queue[i] == anim) {
3347                     return i;
3348                 }
3349             }
3350             return -1;
3351         };
3352
3353
3354         var correctFrame = function(tween) {
3355             var frames = tween.totalFrames;
3356             var frame = tween.currentFrame;
3357             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3358             var elapsed = (new Date() - tween.getStartTime());
3359             var tweak = 0;
3360
3361             if (elapsed < tween.duration * 1000) {
3362                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3363             } else {
3364                 tweak = frames - (frame + 1);
3365             }
3366             if (tweak > 0 && isFinite(tweak)) {
3367                 if (tween.currentFrame + tweak >= frames) {
3368                     tweak = frames - (frame + 1);
3369                 }
3370
3371                 tween.currentFrame += tweak;
3372             }
3373         };
3374     };/*
3375  * Portions of this file are based on pieces of Yahoo User Interface Library
3376  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3377  * YUI licensed under the BSD License:
3378  * http://developer.yahoo.net/yui/license.txt
3379  * <script type="text/javascript">
3380  *
3381  */
3382 Roo.lib.Bezier = new function() {
3383
3384         this.getPosition = function(points, t) {
3385             var n = points.length;
3386             var tmp = [];
3387
3388             for (var i = 0; i < n; ++i) {
3389                 tmp[i] = [points[i][0], points[i][1]];
3390             }
3391
3392             for (var j = 1; j < n; ++j) {
3393                 for (i = 0; i < n - j; ++i) {
3394                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3395                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3396                 }
3397             }
3398
3399             return [ tmp[0][0], tmp[0][1] ];
3400
3401         };
3402     };/*
3403  * Portions of this file are based on pieces of Yahoo User Interface Library
3404  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3405  * YUI licensed under the BSD License:
3406  * http://developer.yahoo.net/yui/license.txt
3407  * <script type="text/javascript">
3408  *
3409  */
3410 (function() {
3411
3412     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3413         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3414     };
3415
3416     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3417
3418     var fly = Roo.lib.AnimBase.fly;
3419     var Y = Roo.lib;
3420     var superclass = Y.ColorAnim.superclass;
3421     var proto = Y.ColorAnim.prototype;
3422
3423     proto.toString = function() {
3424         var el = this.getEl();
3425         var id = el.id || el.tagName;
3426         return ("ColorAnim " + id);
3427     };
3428
3429     proto.patterns.color = /color$/i;
3430     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3431     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3432     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3433     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3434
3435
3436     proto.parseColor = function(s) {
3437         if (s.length == 3) {
3438             return s;
3439         }
3440
3441         var c = this.patterns.hex.exec(s);
3442         if (c && c.length == 4) {
3443             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3444         }
3445
3446         c = this.patterns.rgb.exec(s);
3447         if (c && c.length == 4) {
3448             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3449         }
3450
3451         c = this.patterns.hex3.exec(s);
3452         if (c && c.length == 4) {
3453             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3454         }
3455
3456         return null;
3457     };
3458     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3459     proto.getAttribute = function(attr) {
3460         var el = this.getEl();
3461         if (this.patterns.color.test(attr)) {
3462             var val = fly(el).getStyle(attr);
3463
3464             if (this.patterns.transparent.test(val)) {
3465                 var parent = el.parentNode;
3466                 val = fly(parent).getStyle(attr);
3467
3468                 while (parent && this.patterns.transparent.test(val)) {
3469                     parent = parent.parentNode;
3470                     val = fly(parent).getStyle(attr);
3471                     if (parent.tagName.toUpperCase() == 'HTML') {
3472                         val = '#fff';
3473                     }
3474                 }
3475             }
3476         } else {
3477             val = superclass.getAttribute.call(this, attr);
3478         }
3479
3480         return val;
3481     };
3482     proto.getAttribute = function(attr) {
3483         var el = this.getEl();
3484         if (this.patterns.color.test(attr)) {
3485             var val = fly(el).getStyle(attr);
3486
3487             if (this.patterns.transparent.test(val)) {
3488                 var parent = el.parentNode;
3489                 val = fly(parent).getStyle(attr);
3490
3491                 while (parent && this.patterns.transparent.test(val)) {
3492                     parent = parent.parentNode;
3493                     val = fly(parent).getStyle(attr);
3494                     if (parent.tagName.toUpperCase() == 'HTML') {
3495                         val = '#fff';
3496                     }
3497                 }
3498             }
3499         } else {
3500             val = superclass.getAttribute.call(this, attr);
3501         }
3502
3503         return val;
3504     };
3505
3506     proto.doMethod = function(attr, start, end) {
3507         var val;
3508
3509         if (this.patterns.color.test(attr)) {
3510             val = [];
3511             for (var i = 0, len = start.length; i < len; ++i) {
3512                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3513             }
3514
3515             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3516         }
3517         else {
3518             val = superclass.doMethod.call(this, attr, start, end);
3519         }
3520
3521         return val;
3522     };
3523
3524     proto.setRuntimeAttribute = function(attr) {
3525         superclass.setRuntimeAttribute.call(this, attr);
3526
3527         if (this.patterns.color.test(attr)) {
3528             var attributes = this.attributes;
3529             var start = this.parseColor(this.runtimeAttributes[attr].start);
3530             var end = this.parseColor(this.runtimeAttributes[attr].end);
3531
3532             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3533                 end = this.parseColor(attributes[attr].by);
3534
3535                 for (var i = 0, len = start.length; i < len; ++i) {
3536                     end[i] = start[i] + end[i];
3537                 }
3538             }
3539
3540             this.runtimeAttributes[attr].start = start;
3541             this.runtimeAttributes[attr].end = end;
3542         }
3543     };
3544 })();
3545
3546 /*
3547  * Portions of this file are based on pieces of Yahoo User Interface Library
3548  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3549  * YUI licensed under the BSD License:
3550  * http://developer.yahoo.net/yui/license.txt
3551  * <script type="text/javascript">
3552  *
3553  */
3554 Roo.lib.Easing = {
3555
3556
3557     easeNone: function (t, b, c, d) {
3558         return c * t / d + b;
3559     },
3560
3561
3562     easeIn: function (t, b, c, d) {
3563         return c * (t /= d) * t + b;
3564     },
3565
3566
3567     easeOut: function (t, b, c, d) {
3568         return -c * (t /= d) * (t - 2) + b;
3569     },
3570
3571
3572     easeBoth: function (t, b, c, d) {
3573         if ((t /= d / 2) < 1) {
3574             return c / 2 * t * t + b;
3575         }
3576
3577         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3578     },
3579
3580
3581     easeInStrong: function (t, b, c, d) {
3582         return c * (t /= d) * t * t * t + b;
3583     },
3584
3585
3586     easeOutStrong: function (t, b, c, d) {
3587         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3588     },
3589
3590
3591     easeBothStrong: function (t, b, c, d) {
3592         if ((t /= d / 2) < 1) {
3593             return c / 2 * t * t * t * t + b;
3594         }
3595
3596         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3597     },
3598
3599
3600
3601     elasticIn: function (t, b, c, d, a, p) {
3602         if (t == 0) {
3603             return b;
3604         }
3605         if ((t /= d) == 1) {
3606             return b + c;
3607         }
3608         if (!p) {
3609             p = d * .3;
3610         }
3611
3612         if (!a || a < Math.abs(c)) {
3613             a = c;
3614             var s = p / 4;
3615         }
3616         else {
3617             var s = p / (2 * Math.PI) * Math.asin(c / a);
3618         }
3619
3620         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3621     },
3622
3623
3624     elasticOut: function (t, b, c, d, a, p) {
3625         if (t == 0) {
3626             return b;
3627         }
3628         if ((t /= d) == 1) {
3629             return b + c;
3630         }
3631         if (!p) {
3632             p = d * .3;
3633         }
3634
3635         if (!a || a < Math.abs(c)) {
3636             a = c;
3637             var s = p / 4;
3638         }
3639         else {
3640             var s = p / (2 * Math.PI) * Math.asin(c / a);
3641         }
3642
3643         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3644     },
3645
3646
3647     elasticBoth: function (t, b, c, d, a, p) {
3648         if (t == 0) {
3649             return b;
3650         }
3651
3652         if ((t /= d / 2) == 2) {
3653             return b + c;
3654         }
3655
3656         if (!p) {
3657             p = d * (.3 * 1.5);
3658         }
3659
3660         if (!a || a < Math.abs(c)) {
3661             a = c;
3662             var s = p / 4;
3663         }
3664         else {
3665             var s = p / (2 * Math.PI) * Math.asin(c / a);
3666         }
3667
3668         if (t < 1) {
3669             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3670                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3671         }
3672         return a * Math.pow(2, -10 * (t -= 1)) *
3673                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3674     },
3675
3676
3677
3678     backIn: function (t, b, c, d, s) {
3679         if (typeof s == 'undefined') {
3680             s = 1.70158;
3681         }
3682         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3683     },
3684
3685
3686     backOut: function (t, b, c, d, s) {
3687         if (typeof s == 'undefined') {
3688             s = 1.70158;
3689         }
3690         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3691     },
3692
3693
3694     backBoth: function (t, b, c, d, s) {
3695         if (typeof s == 'undefined') {
3696             s = 1.70158;
3697         }
3698
3699         if ((t /= d / 2 ) < 1) {
3700             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3701         }
3702         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3703     },
3704
3705
3706     bounceIn: function (t, b, c, d) {
3707         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3708     },
3709
3710
3711     bounceOut: function (t, b, c, d) {
3712         if ((t /= d) < (1 / 2.75)) {
3713             return c * (7.5625 * t * t) + b;
3714         } else if (t < (2 / 2.75)) {
3715             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3716         } else if (t < (2.5 / 2.75)) {
3717             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3718         }
3719         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3720     },
3721
3722
3723     bounceBoth: function (t, b, c, d) {
3724         if (t < d / 2) {
3725             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3726         }
3727         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3728     }
3729 };/*
3730  * Portions of this file are based on pieces of Yahoo User Interface Library
3731  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3732  * YUI licensed under the BSD License:
3733  * http://developer.yahoo.net/yui/license.txt
3734  * <script type="text/javascript">
3735  *
3736  */
3737     (function() {
3738         Roo.lib.Motion = function(el, attributes, duration, method) {
3739             if (el) {
3740                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3741             }
3742         };
3743
3744         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3745
3746
3747         var Y = Roo.lib;
3748         var superclass = Y.Motion.superclass;
3749         var proto = Y.Motion.prototype;
3750
3751         proto.toString = function() {
3752             var el = this.getEl();
3753             var id = el.id || el.tagName;
3754             return ("Motion " + id);
3755         };
3756
3757         proto.patterns.points = /^points$/i;
3758
3759         proto.setAttribute = function(attr, val, unit) {
3760             if (this.patterns.points.test(attr)) {
3761                 unit = unit || 'px';
3762                 superclass.setAttribute.call(this, 'left', val[0], unit);
3763                 superclass.setAttribute.call(this, 'top', val[1], unit);
3764             } else {
3765                 superclass.setAttribute.call(this, attr, val, unit);
3766             }
3767         };
3768
3769         proto.getAttribute = function(attr) {
3770             if (this.patterns.points.test(attr)) {
3771                 var val = [
3772                         superclass.getAttribute.call(this, 'left'),
3773                         superclass.getAttribute.call(this, 'top')
3774                         ];
3775             } else {
3776                 val = superclass.getAttribute.call(this, attr);
3777             }
3778
3779             return val;
3780         };
3781
3782         proto.doMethod = function(attr, start, end) {
3783             var val = null;
3784
3785             if (this.patterns.points.test(attr)) {
3786                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3787                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3788             } else {
3789                 val = superclass.doMethod.call(this, attr, start, end);
3790             }
3791             return val;
3792         };
3793
3794         proto.setRuntimeAttribute = function(attr) {
3795             if (this.patterns.points.test(attr)) {
3796                 var el = this.getEl();
3797                 var attributes = this.attributes;
3798                 var start;
3799                 var control = attributes['points']['control'] || [];
3800                 var end;
3801                 var i, len;
3802
3803                 if (control.length > 0 && !(control[0] instanceof Array)) {
3804                     control = [control];
3805                 } else {
3806                     var tmp = [];
3807                     for (i = 0,len = control.length; i < len; ++i) {
3808                         tmp[i] = control[i];
3809                     }
3810                     control = tmp;
3811                 }
3812
3813                 Roo.fly(el).position();
3814
3815                 if (isset(attributes['points']['from'])) {
3816                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3817                 }
3818                 else {
3819                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3820                 }
3821
3822                 start = this.getAttribute('points');
3823
3824
3825                 if (isset(attributes['points']['to'])) {
3826                     end = translateValues.call(this, attributes['points']['to'], start);
3827
3828                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3829                     for (i = 0,len = control.length; i < len; ++i) {
3830                         control[i] = translateValues.call(this, control[i], start);
3831                     }
3832
3833
3834                 } else if (isset(attributes['points']['by'])) {
3835                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3836
3837                     for (i = 0,len = control.length; i < len; ++i) {
3838                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3839                     }
3840                 }
3841
3842                 this.runtimeAttributes[attr] = [start];
3843
3844                 if (control.length > 0) {
3845                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3846                 }
3847
3848                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3849             }
3850             else {
3851                 superclass.setRuntimeAttribute.call(this, attr);
3852             }
3853         };
3854
3855         var translateValues = function(val, start) {
3856             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3857             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3858
3859             return val;
3860         };
3861
3862         var isset = function(prop) {
3863             return (typeof prop !== 'undefined');
3864         };
3865     })();
3866 /*
3867  * Portions of this file are based on pieces of Yahoo User Interface Library
3868  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3869  * YUI licensed under the BSD License:
3870  * http://developer.yahoo.net/yui/license.txt
3871  * <script type="text/javascript">
3872  *
3873  */
3874     (function() {
3875         Roo.lib.Scroll = function(el, attributes, duration, method) {
3876             if (el) {
3877                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3878             }
3879         };
3880
3881         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3882
3883
3884         var Y = Roo.lib;
3885         var superclass = Y.Scroll.superclass;
3886         var proto = Y.Scroll.prototype;
3887
3888         proto.toString = function() {
3889             var el = this.getEl();
3890             var id = el.id || el.tagName;
3891             return ("Scroll " + id);
3892         };
3893
3894         proto.doMethod = function(attr, start, end) {
3895             var val = null;
3896
3897             if (attr == 'scroll') {
3898                 val = [
3899                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3900                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3901                         ];
3902
3903             } else {
3904                 val = superclass.doMethod.call(this, attr, start, end);
3905             }
3906             return val;
3907         };
3908
3909         proto.getAttribute = function(attr) {
3910             var val = null;
3911             var el = this.getEl();
3912
3913             if (attr == 'scroll') {
3914                 val = [ el.scrollLeft, el.scrollTop ];
3915             } else {
3916                 val = superclass.getAttribute.call(this, attr);
3917             }
3918
3919             return val;
3920         };
3921
3922         proto.setAttribute = function(attr, val, unit) {
3923             var el = this.getEl();
3924
3925             if (attr == 'scroll') {
3926                 el.scrollLeft = val[0];
3927                 el.scrollTop = val[1];
3928             } else {
3929                 superclass.setAttribute.call(this, attr, val, unit);
3930             }
3931         };
3932     })();
3933 /*
3934  * Based on:
3935  * Ext JS Library 1.1.1
3936  * Copyright(c) 2006-2007, Ext JS, LLC.
3937  *
3938  * Originally Released Under LGPL - original licence link has changed is not relivant.
3939  *
3940  * Fork - LGPL
3941  * <script type="text/javascript">
3942  */
3943  
3944
3945 /**
3946  * @class Roo.DomHelper
3947  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3948  * 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>.
3949  * @singleton
3950  */
3951 Roo.DomHelper = function(){
3952     var tempTableEl = null;
3953     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3954     var tableRe = /^table|tbody|tr|td$/i;
3955     var xmlns = {};
3956     // build as innerHTML where available
3957     /** @ignore */
3958     var createHtml = function(o){
3959         if(typeof o == 'string'){
3960             return o;
3961         }
3962         var b = "";
3963         if(!o.tag){
3964             o.tag = "div";
3965         }
3966         b += "<" + o.tag;
3967         for(var attr in o){
3968             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3969             if(attr == "style"){
3970                 var s = o["style"];
3971                 if(typeof s == "function"){
3972                     s = s.call();
3973                 }
3974                 if(typeof s == "string"){
3975                     b += ' style="' + s + '"';
3976                 }else if(typeof s == "object"){
3977                     b += ' style="';
3978                     for(var key in s){
3979                         if(typeof s[key] != "function"){
3980                             b += key + ":" + s[key] + ";";
3981                         }
3982                     }
3983                     b += '"';
3984                 }
3985             }else{
3986                 if(attr == "cls"){
3987                     b += ' class="' + o["cls"] + '"';
3988                 }else if(attr == "htmlFor"){
3989                     b += ' for="' + o["htmlFor"] + '"';
3990                 }else{
3991                     b += " " + attr + '="' + o[attr] + '"';
3992                 }
3993             }
3994         }
3995         if(emptyTags.test(o.tag)){
3996             b += "/>";
3997         }else{
3998             b += ">";
3999             var cn = o.children || o.cn;
4000             if(cn){
4001                 //http://bugs.kde.org/show_bug.cgi?id=71506
4002                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4003                     for(var i = 0, len = cn.length; i < len; i++) {
4004                         b += createHtml(cn[i], b);
4005                     }
4006                 }else{
4007                     b += createHtml(cn, b);
4008                 }
4009             }
4010             if(o.html){
4011                 b += o.html;
4012             }
4013             b += "</" + o.tag + ">";
4014         }
4015         return b;
4016     };
4017
4018     // build as dom
4019     /** @ignore */
4020     var createDom = function(o, parentNode){
4021          
4022         // defininition craeted..
4023         var ns = false;
4024         if (o.ns && o.ns != 'html') {
4025                
4026             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4027                 xmlns[o.ns] = o.xmlns;
4028                 ns = o.xmlns;
4029             }
4030             if (typeof(xmlns[o.ns]) == 'undefined') {
4031                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4032             }
4033             ns = xmlns[o.ns];
4034         }
4035         
4036         
4037         if (typeof(o) == 'string') {
4038             return parentNode.appendChild(document.createTextNode(o));
4039         }
4040         o.tag = o.tag || div;
4041         if (o.ns && Roo.isIE) {
4042             ns = false;
4043             o.tag = o.ns + ':' + o.tag;
4044             
4045         }
4046         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4047         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4048         for(var attr in o){
4049             
4050             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4051                     attr == "style" || typeof o[attr] == "function") continue;
4052                     
4053             if(attr=="cls" && Roo.isIE){
4054                 el.className = o["cls"];
4055             }else{
4056                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4057                 else el[attr] = o[attr];
4058             }
4059         }
4060         Roo.DomHelper.applyStyles(el, o.style);
4061         var cn = o.children || o.cn;
4062         if(cn){
4063             //http://bugs.kde.org/show_bug.cgi?id=71506
4064              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4065                 for(var i = 0, len = cn.length; i < len; i++) {
4066                     createDom(cn[i], el);
4067                 }
4068             }else{
4069                 createDom(cn, el);
4070             }
4071         }
4072         if(o.html){
4073             el.innerHTML = o.html;
4074         }
4075         if(parentNode){
4076            parentNode.appendChild(el);
4077         }
4078         return el;
4079     };
4080
4081     var ieTable = function(depth, s, h, e){
4082         tempTableEl.innerHTML = [s, h, e].join('');
4083         var i = -1, el = tempTableEl;
4084         while(++i < depth){
4085             el = el.firstChild;
4086         }
4087         return el;
4088     };
4089
4090     // kill repeat to save bytes
4091     var ts = '<table>',
4092         te = '</table>',
4093         tbs = ts+'<tbody>',
4094         tbe = '</tbody>'+te,
4095         trs = tbs + '<tr>',
4096         tre = '</tr>'+tbe;
4097
4098     /**
4099      * @ignore
4100      * Nasty code for IE's broken table implementation
4101      */
4102     var insertIntoTable = function(tag, where, el, html){
4103         if(!tempTableEl){
4104             tempTableEl = document.createElement('div');
4105         }
4106         var node;
4107         var before = null;
4108         if(tag == 'td'){
4109             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4110                 return;
4111             }
4112             if(where == 'beforebegin'){
4113                 before = el;
4114                 el = el.parentNode;
4115             } else{
4116                 before = el.nextSibling;
4117                 el = el.parentNode;
4118             }
4119             node = ieTable(4, trs, html, tre);
4120         }
4121         else if(tag == 'tr'){
4122             if(where == 'beforebegin'){
4123                 before = el;
4124                 el = el.parentNode;
4125                 node = ieTable(3, tbs, html, tbe);
4126             } else if(where == 'afterend'){
4127                 before = el.nextSibling;
4128                 el = el.parentNode;
4129                 node = ieTable(3, tbs, html, tbe);
4130             } else{ // INTO a TR
4131                 if(where == 'afterbegin'){
4132                     before = el.firstChild;
4133                 }
4134                 node = ieTable(4, trs, html, tre);
4135             }
4136         } else if(tag == 'tbody'){
4137             if(where == 'beforebegin'){
4138                 before = el;
4139                 el = el.parentNode;
4140                 node = ieTable(2, ts, html, te);
4141             } else if(where == 'afterend'){
4142                 before = el.nextSibling;
4143                 el = el.parentNode;
4144                 node = ieTable(2, ts, html, te);
4145             } else{
4146                 if(where == 'afterbegin'){
4147                     before = el.firstChild;
4148                 }
4149                 node = ieTable(3, tbs, html, tbe);
4150             }
4151         } else{ // TABLE
4152             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4153                 return;
4154             }
4155             if(where == 'afterbegin'){
4156                 before = el.firstChild;
4157             }
4158             node = ieTable(2, ts, html, te);
4159         }
4160         el.insertBefore(node, before);
4161         return node;
4162     };
4163
4164     return {
4165     /** True to force the use of DOM instead of html fragments @type Boolean */
4166     useDom : false,
4167
4168     /**
4169      * Returns the markup for the passed Element(s) config
4170      * @param {Object} o The Dom object spec (and children)
4171      * @return {String}
4172      */
4173     markup : function(o){
4174         return createHtml(o);
4175     },
4176
4177     /**
4178      * Applies a style specification to an element
4179      * @param {String/HTMLElement} el The element to apply styles to
4180      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4181      * a function which returns such a specification.
4182      */
4183     applyStyles : function(el, styles){
4184         if(styles){
4185            el = Roo.fly(el);
4186            if(typeof styles == "string"){
4187                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4188                var matches;
4189                while ((matches = re.exec(styles)) != null){
4190                    el.setStyle(matches[1], matches[2]);
4191                }
4192            }else if (typeof styles == "object"){
4193                for (var style in styles){
4194                   el.setStyle(style, styles[style]);
4195                }
4196            }else if (typeof styles == "function"){
4197                 Roo.DomHelper.applyStyles(el, styles.call());
4198            }
4199         }
4200     },
4201
4202     /**
4203      * Inserts an HTML fragment into the Dom
4204      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4205      * @param {HTMLElement} el The context element
4206      * @param {String} html The HTML fragmenet
4207      * @return {HTMLElement} The new node
4208      */
4209     insertHtml : function(where, el, html){
4210         where = where.toLowerCase();
4211         if(el.insertAdjacentHTML){
4212             if(tableRe.test(el.tagName)){
4213                 var rs;
4214                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4215                     return rs;
4216                 }
4217             }
4218             switch(where){
4219                 case "beforebegin":
4220                     el.insertAdjacentHTML('BeforeBegin', html);
4221                     return el.previousSibling;
4222                 case "afterbegin":
4223                     el.insertAdjacentHTML('AfterBegin', html);
4224                     return el.firstChild;
4225                 case "beforeend":
4226                     el.insertAdjacentHTML('BeforeEnd', html);
4227                     return el.lastChild;
4228                 case "afterend":
4229                     el.insertAdjacentHTML('AfterEnd', html);
4230                     return el.nextSibling;
4231             }
4232             throw 'Illegal insertion point -> "' + where + '"';
4233         }
4234         var range = el.ownerDocument.createRange();
4235         var frag;
4236         switch(where){
4237              case "beforebegin":
4238                 range.setStartBefore(el);
4239                 frag = range.createContextualFragment(html);
4240                 el.parentNode.insertBefore(frag, el);
4241                 return el.previousSibling;
4242              case "afterbegin":
4243                 if(el.firstChild){
4244                     range.setStartBefore(el.firstChild);
4245                     frag = range.createContextualFragment(html);
4246                     el.insertBefore(frag, el.firstChild);
4247                     return el.firstChild;
4248                 }else{
4249                     el.innerHTML = html;
4250                     return el.firstChild;
4251                 }
4252             case "beforeend":
4253                 if(el.lastChild){
4254                     range.setStartAfter(el.lastChild);
4255                     frag = range.createContextualFragment(html);
4256                     el.appendChild(frag);
4257                     return el.lastChild;
4258                 }else{
4259                     el.innerHTML = html;
4260                     return el.lastChild;
4261                 }
4262             case "afterend":
4263                 range.setStartAfter(el);
4264                 frag = range.createContextualFragment(html);
4265                 el.parentNode.insertBefore(frag, el.nextSibling);
4266                 return el.nextSibling;
4267             }
4268             throw 'Illegal insertion point -> "' + where + '"';
4269     },
4270
4271     /**
4272      * Creates new Dom element(s) and inserts them before el
4273      * @param {String/HTMLElement/Element} el The context element
4274      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4275      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4276      * @return {HTMLElement/Roo.Element} The new node
4277      */
4278     insertBefore : function(el, o, returnElement){
4279         return this.doInsert(el, o, returnElement, "beforeBegin");
4280     },
4281
4282     /**
4283      * Creates new Dom element(s) and inserts them after el
4284      * @param {String/HTMLElement/Element} el The context element
4285      * @param {Object} o The Dom object spec (and children)
4286      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4287      * @return {HTMLElement/Roo.Element} The new node
4288      */
4289     insertAfter : function(el, o, returnElement){
4290         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4291     },
4292
4293     /**
4294      * Creates new Dom element(s) and inserts them as the first child of el
4295      * @param {String/HTMLElement/Element} el The context element
4296      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4297      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4298      * @return {HTMLElement/Roo.Element} The new node
4299      */
4300     insertFirst : function(el, o, returnElement){
4301         return this.doInsert(el, o, returnElement, "afterBegin");
4302     },
4303
4304     // private
4305     doInsert : function(el, o, returnElement, pos, sibling){
4306         el = Roo.getDom(el);
4307         var newNode;
4308         if(this.useDom || o.ns){
4309             newNode = createDom(o, null);
4310             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4311         }else{
4312             var html = createHtml(o);
4313             newNode = this.insertHtml(pos, el, html);
4314         }
4315         return returnElement ? Roo.get(newNode, true) : newNode;
4316     },
4317
4318     /**
4319      * Creates new Dom element(s) and appends them to el
4320      * @param {String/HTMLElement/Element} el The context element
4321      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4322      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4323      * @return {HTMLElement/Roo.Element} The new node
4324      */
4325     append : function(el, o, returnElement){
4326         el = Roo.getDom(el);
4327         var newNode;
4328         if(this.useDom || o.ns){
4329             newNode = createDom(o, null);
4330             el.appendChild(newNode);
4331         }else{
4332             var html = createHtml(o);
4333             newNode = this.insertHtml("beforeEnd", el, html);
4334         }
4335         return returnElement ? Roo.get(newNode, true) : newNode;
4336     },
4337
4338     /**
4339      * Creates new Dom element(s) and overwrites the contents of el with them
4340      * @param {String/HTMLElement/Element} el The context element
4341      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4342      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4343      * @return {HTMLElement/Roo.Element} The new node
4344      */
4345     overwrite : function(el, o, returnElement){
4346         el = Roo.getDom(el);
4347         if (o.ns) {
4348           
4349             while (el.childNodes.length) {
4350                 el.removeChild(el.firstChild);
4351             }
4352             createDom(o, el);
4353         } else {
4354             el.innerHTML = createHtml(o);   
4355         }
4356         
4357         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4358     },
4359
4360     /**
4361      * Creates a new Roo.DomHelper.Template from the Dom object spec
4362      * @param {Object} o The Dom object spec (and children)
4363      * @return {Roo.DomHelper.Template} The new template
4364      */
4365     createTemplate : function(o){
4366         var html = createHtml(o);
4367         return new Roo.Template(html);
4368     }
4369     };
4370 }();
4371 /*
4372  * Based on:
4373  * Ext JS Library 1.1.1
4374  * Copyright(c) 2006-2007, Ext JS, LLC.
4375  *
4376  * Originally Released Under LGPL - original licence link has changed is not relivant.
4377  *
4378  * Fork - LGPL
4379  * <script type="text/javascript">
4380  */
4381  
4382 /**
4383 * @class Roo.Template
4384 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4385 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4386 * Usage:
4387 <pre><code>
4388 var t = new Roo.Template(
4389     '&lt;div name="{id}"&gt;',
4390         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
4391     '&lt;/div&gt;'
4392 );
4393 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4394 </code></pre>
4395 * 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>. 
4396 * @constructor
4397 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4398 */
4399 Roo.Template = function(html){
4400     if(html instanceof Array){
4401         html = html.join("");
4402     }else if(arguments.length > 1){
4403         html = Array.prototype.join.call(arguments, "");
4404     }
4405     /**@private*/
4406     this.html = html;
4407     
4408 };
4409 Roo.Template.prototype = {
4410     /**
4411      * Returns an HTML fragment of this template with the specified values applied.
4412      * @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'})
4413      * @return {String} The HTML fragment
4414      */
4415     applyTemplate : function(values){
4416         if(this.compiled){
4417             return this.compiled(values);
4418         }
4419         var useF = this.disableFormats !== true;
4420         var fm = Roo.util.Format, tpl = this;
4421         var fn = function(m, name, format, args){
4422             if(format && useF){
4423                 if(format.substr(0, 5) == "this."){
4424                     return tpl.call(format.substr(5), values[name], values);
4425                 }else{
4426                     if(args){
4427                         // quoted values are required for strings in compiled templates, 
4428                         // but for non compiled we need to strip them
4429                         // quoted reversed for jsmin
4430                         var re = /^\s*['"](.*)["']\s*$/;
4431                         args = args.split(',');
4432                         for(var i = 0, len = args.length; i < len; i++){
4433                             args[i] = args[i].replace(re, "$1");
4434                         }
4435                         args = [values[name]].concat(args);
4436                     }else{
4437                         args = [values[name]];
4438                     }
4439                     return fm[format].apply(fm, args);
4440                 }
4441             }else{
4442                 return values[name] !== undefined ? values[name] : "";
4443             }
4444         };
4445         return this.html.replace(this.re, fn);
4446     },
4447     
4448     /**
4449      * Sets the HTML used as the template and optionally compiles it.
4450      * @param {String} html
4451      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4452      * @return {Roo.Template} this
4453      */
4454     set : function(html, compile){
4455         this.html = html;
4456         this.compiled = null;
4457         if(compile){
4458             this.compile();
4459         }
4460         return this;
4461     },
4462     
4463     /**
4464      * True to disable format functions (defaults to false)
4465      * @type Boolean
4466      */
4467     disableFormats : false,
4468     
4469     /**
4470     * The regular expression used to match template variables 
4471     * @type RegExp
4472     * @property 
4473     */
4474     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4475     
4476     /**
4477      * Compiles the template into an internal function, eliminating the RegEx overhead.
4478      * @return {Roo.Template} this
4479      */
4480     compile : function(){
4481         var fm = Roo.util.Format;
4482         var useF = this.disableFormats !== true;
4483         var sep = Roo.isGecko ? "+" : ",";
4484         var fn = function(m, name, format, args){
4485             if(format && useF){
4486                 args = args ? ',' + args : "";
4487                 if(format.substr(0, 5) != "this."){
4488                     format = "fm." + format + '(';
4489                 }else{
4490                     format = 'this.call("'+ format.substr(5) + '", ';
4491                     args = ", values";
4492                 }
4493             }else{
4494                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4495             }
4496             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4497         };
4498         var body;
4499         // branched to use + in gecko and [].join() in others
4500         if(Roo.isGecko){
4501             body = "this.compiled = function(values){ return '" +
4502                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4503                     "';};";
4504         }else{
4505             body = ["this.compiled = function(values){ return ['"];
4506             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4507             body.push("'].join('');};");
4508             body = body.join('');
4509         }
4510         /**
4511          * eval:var:values
4512          * eval:var:fm
4513          */
4514         eval(body);
4515         return this;
4516     },
4517     
4518     // private function used to call members
4519     call : function(fnName, value, allValues){
4520         return this[fnName](value, allValues);
4521     },
4522     
4523     /**
4524      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4525      * @param {String/HTMLElement/Roo.Element} el The context element
4526      * @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'})
4527      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4528      * @return {HTMLElement/Roo.Element} The new node or Element
4529      */
4530     insertFirst: function(el, values, returnElement){
4531         return this.doInsert('afterBegin', el, values, returnElement);
4532     },
4533
4534     /**
4535      * Applies the supplied values to the template and inserts the new node(s) before el.
4536      * @param {String/HTMLElement/Roo.Element} el The context element
4537      * @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'})
4538      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4539      * @return {HTMLElement/Roo.Element} The new node or Element
4540      */
4541     insertBefore: function(el, values, returnElement){
4542         return this.doInsert('beforeBegin', el, values, returnElement);
4543     },
4544
4545     /**
4546      * Applies the supplied values to the template and inserts the new node(s) after el.
4547      * @param {String/HTMLElement/Roo.Element} el The context element
4548      * @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'})
4549      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4550      * @return {HTMLElement/Roo.Element} The new node or Element
4551      */
4552     insertAfter : function(el, values, returnElement){
4553         return this.doInsert('afterEnd', el, values, returnElement);
4554     },
4555     
4556     /**
4557      * Applies the supplied values to the template and appends the new node(s) to el.
4558      * @param {String/HTMLElement/Roo.Element} el The context element
4559      * @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'})
4560      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4561      * @return {HTMLElement/Roo.Element} The new node or Element
4562      */
4563     append : function(el, values, returnElement){
4564         return this.doInsert('beforeEnd', el, values, returnElement);
4565     },
4566
4567     doInsert : function(where, el, values, returnEl){
4568         el = Roo.getDom(el);
4569         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4570         return returnEl ? Roo.get(newNode, true) : newNode;
4571     },
4572
4573     /**
4574      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4575      * @param {String/HTMLElement/Roo.Element} el The context element
4576      * @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'})
4577      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4578      * @return {HTMLElement/Roo.Element} The new node or Element
4579      */
4580     overwrite : function(el, values, returnElement){
4581         el = Roo.getDom(el);
4582         el.innerHTML = this.applyTemplate(values);
4583         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4584     }
4585 };
4586 /**
4587  * Alias for {@link #applyTemplate}
4588  * @method
4589  */
4590 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4591
4592 // backwards compat
4593 Roo.DomHelper.Template = Roo.Template;
4594
4595 /**
4596  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4597  * @param {String/HTMLElement} el A DOM element or its id
4598  * @returns {Roo.Template} The created template
4599  * @static
4600  */
4601 Roo.Template.from = function(el){
4602     el = Roo.getDom(el);
4603     return new Roo.Template(el.value || el.innerHTML);
4604 };/*
4605  * Based on:
4606  * Ext JS Library 1.1.1
4607  * Copyright(c) 2006-2007, Ext JS, LLC.
4608  *
4609  * Originally Released Under LGPL - original licence link has changed is not relivant.
4610  *
4611  * Fork - LGPL
4612  * <script type="text/javascript">
4613  */
4614  
4615
4616 /*
4617  * This is code is also distributed under MIT license for use
4618  * with jQuery and prototype JavaScript libraries.
4619  */
4620 /**
4621  * @class Roo.DomQuery
4622 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).
4623 <p>
4624 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>
4625
4626 <p>
4627 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.
4628 </p>
4629 <h4>Element Selectors:</h4>
4630 <ul class="list">
4631     <li> <b>*</b> any element</li>
4632     <li> <b>E</b> an element with the tag E</li>
4633     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4634     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4635     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4636     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4637 </ul>
4638 <h4>Attribute Selectors:</h4>
4639 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4640 <ul class="list">
4641     <li> <b>E[foo]</b> has an attribute "foo"</li>
4642     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4643     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4644     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4645     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4646     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4647     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4648 </ul>
4649 <h4>Pseudo Classes:</h4>
4650 <ul class="list">
4651     <li> <b>E:first-child</b> E is the first child of its parent</li>
4652     <li> <b>E:last-child</b> E is the last child of its parent</li>
4653     <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>
4654     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4655     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4656     <li> <b>E:only-child</b> E is the only child of its parent</li>
4657     <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>
4658     <li> <b>E:first</b> the first E in the resultset</li>
4659     <li> <b>E:last</b> the last E in the resultset</li>
4660     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4661     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4662     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4663     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4664     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4665     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4666     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4667     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4668     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4669 </ul>
4670 <h4>CSS Value Selectors:</h4>
4671 <ul class="list">
4672     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4673     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4674     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4675     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4676     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4677     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4678 </ul>
4679  * @singleton
4680  */
4681 Roo.DomQuery = function(){
4682     var cache = {}, simpleCache = {}, valueCache = {};
4683     var nonSpace = /\S/;
4684     var trimRe = /^\s+|\s+$/g;
4685     var tplRe = /\{(\d+)\}/g;
4686     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4687     var tagTokenRe = /^(#)?([\w-\*]+)/;
4688     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4689
4690     function child(p, index){
4691         var i = 0;
4692         var n = p.firstChild;
4693         while(n){
4694             if(n.nodeType == 1){
4695                if(++i == index){
4696                    return n;
4697                }
4698             }
4699             n = n.nextSibling;
4700         }
4701         return null;
4702     };
4703
4704     function next(n){
4705         while((n = n.nextSibling) && n.nodeType != 1);
4706         return n;
4707     };
4708
4709     function prev(n){
4710         while((n = n.previousSibling) && n.nodeType != 1);
4711         return n;
4712     };
4713
4714     function children(d){
4715         var n = d.firstChild, ni = -1;
4716             while(n){
4717                 var nx = n.nextSibling;
4718                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4719                     d.removeChild(n);
4720                 }else{
4721                     n.nodeIndex = ++ni;
4722                 }
4723                 n = nx;
4724             }
4725             return this;
4726         };
4727
4728     function byClassName(c, a, v){
4729         if(!v){
4730             return c;
4731         }
4732         var r = [], ri = -1, cn;
4733         for(var i = 0, ci; ci = c[i]; i++){
4734             if((' '+ci.className+' ').indexOf(v) != -1){
4735                 r[++ri] = ci;
4736             }
4737         }
4738         return r;
4739     };
4740
4741     function attrValue(n, attr){
4742         if(!n.tagName && typeof n.length != "undefined"){
4743             n = n[0];
4744         }
4745         if(!n){
4746             return null;
4747         }
4748         if(attr == "for"){
4749             return n.htmlFor;
4750         }
4751         if(attr == "class" || attr == "className"){
4752             return n.className;
4753         }
4754         return n.getAttribute(attr) || n[attr];
4755
4756     };
4757
4758     function getNodes(ns, mode, tagName){
4759         var result = [], ri = -1, cs;
4760         if(!ns){
4761             return result;
4762         }
4763         tagName = tagName || "*";
4764         if(typeof ns.getElementsByTagName != "undefined"){
4765             ns = [ns];
4766         }
4767         if(!mode){
4768             for(var i = 0, ni; ni = ns[i]; i++){
4769                 cs = ni.getElementsByTagName(tagName);
4770                 for(var j = 0, ci; ci = cs[j]; j++){
4771                     result[++ri] = ci;
4772                 }
4773             }
4774         }else if(mode == "/" || mode == ">"){
4775             var utag = tagName.toUpperCase();
4776             for(var i = 0, ni, cn; ni = ns[i]; i++){
4777                 cn = ni.children || ni.childNodes;
4778                 for(var j = 0, cj; cj = cn[j]; j++){
4779                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4780                         result[++ri] = cj;
4781                     }
4782                 }
4783             }
4784         }else if(mode == "+"){
4785             var utag = tagName.toUpperCase();
4786             for(var i = 0, n; n = ns[i]; i++){
4787                 while((n = n.nextSibling) && n.nodeType != 1);
4788                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4789                     result[++ri] = n;
4790                 }
4791             }
4792         }else if(mode == "~"){
4793             for(var i = 0, n; n = ns[i]; i++){
4794                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4795                 if(n){
4796                     result[++ri] = n;
4797                 }
4798             }
4799         }
4800         return result;
4801     };
4802
4803     function concat(a, b){
4804         if(b.slice){
4805             return a.concat(b);
4806         }
4807         for(var i = 0, l = b.length; i < l; i++){
4808             a[a.length] = b[i];
4809         }
4810         return a;
4811     }
4812
4813     function byTag(cs, tagName){
4814         if(cs.tagName || cs == document){
4815             cs = [cs];
4816         }
4817         if(!tagName){
4818             return cs;
4819         }
4820         var r = [], ri = -1;
4821         tagName = tagName.toLowerCase();
4822         for(var i = 0, ci; ci = cs[i]; i++){
4823             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4824                 r[++ri] = ci;
4825             }
4826         }
4827         return r;
4828     };
4829
4830     function byId(cs, attr, id){
4831         if(cs.tagName || cs == document){
4832             cs = [cs];
4833         }
4834         if(!id){
4835             return cs;
4836         }
4837         var r = [], ri = -1;
4838         for(var i = 0,ci; ci = cs[i]; i++){
4839             if(ci && ci.id == id){
4840                 r[++ri] = ci;
4841                 return r;
4842             }
4843         }
4844         return r;
4845     };
4846
4847     function byAttribute(cs, attr, value, op, custom){
4848         var r = [], ri = -1, st = custom=="{";
4849         var f = Roo.DomQuery.operators[op];
4850         for(var i = 0, ci; ci = cs[i]; i++){
4851             var a;
4852             if(st){
4853                 a = Roo.DomQuery.getStyle(ci, attr);
4854             }
4855             else if(attr == "class" || attr == "className"){
4856                 a = ci.className;
4857             }else if(attr == "for"){
4858                 a = ci.htmlFor;
4859             }else if(attr == "href"){
4860                 a = ci.getAttribute("href", 2);
4861             }else{
4862                 a = ci.getAttribute(attr);
4863             }
4864             if((f && f(a, value)) || (!f && a)){
4865                 r[++ri] = ci;
4866             }
4867         }
4868         return r;
4869     };
4870
4871     function byPseudo(cs, name, value){
4872         return Roo.DomQuery.pseudos[name](cs, value);
4873     };
4874
4875     // This is for IE MSXML which does not support expandos.
4876     // IE runs the same speed using setAttribute, however FF slows way down
4877     // and Safari completely fails so they need to continue to use expandos.
4878     var isIE = window.ActiveXObject ? true : false;
4879
4880     // this eval is stop the compressor from
4881     // renaming the variable to something shorter
4882     
4883     /** eval:var:batch */
4884     var batch = 30803; 
4885
4886     var key = 30803;
4887
4888     function nodupIEXml(cs){
4889         var d = ++key;
4890         cs[0].setAttribute("_nodup", d);
4891         var r = [cs[0]];
4892         for(var i = 1, len = cs.length; i < len; i++){
4893             var c = cs[i];
4894             if(!c.getAttribute("_nodup") != d){
4895                 c.setAttribute("_nodup", d);
4896                 r[r.length] = c;
4897             }
4898         }
4899         for(var i = 0, len = cs.length; i < len; i++){
4900             cs[i].removeAttribute("_nodup");
4901         }
4902         return r;
4903     }
4904
4905     function nodup(cs){
4906         if(!cs){
4907             return [];
4908         }
4909         var len = cs.length, c, i, r = cs, cj, ri = -1;
4910         if(!len || typeof cs.nodeType != "undefined" || len == 1){
4911             return cs;
4912         }
4913         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4914             return nodupIEXml(cs);
4915         }
4916         var d = ++key;
4917         cs[0]._nodup = d;
4918         for(i = 1; c = cs[i]; i++){
4919             if(c._nodup != d){
4920                 c._nodup = d;
4921             }else{
4922                 r = [];
4923                 for(var j = 0; j < i; j++){
4924                     r[++ri] = cs[j];
4925                 }
4926                 for(j = i+1; cj = cs[j]; j++){
4927                     if(cj._nodup != d){
4928                         cj._nodup = d;
4929                         r[++ri] = cj;
4930                     }
4931                 }
4932                 return r;
4933             }
4934         }
4935         return r;
4936     }
4937
4938     function quickDiffIEXml(c1, c2){
4939         var d = ++key;
4940         for(var i = 0, len = c1.length; i < len; i++){
4941             c1[i].setAttribute("_qdiff", d);
4942         }
4943         var r = [];
4944         for(var i = 0, len = c2.length; i < len; i++){
4945             if(c2[i].getAttribute("_qdiff") != d){
4946                 r[r.length] = c2[i];
4947             }
4948         }
4949         for(var i = 0, len = c1.length; i < len; i++){
4950            c1[i].removeAttribute("_qdiff");
4951         }
4952         return r;
4953     }
4954
4955     function quickDiff(c1, c2){
4956         var len1 = c1.length;
4957         if(!len1){
4958             return c2;
4959         }
4960         if(isIE && c1[0].selectSingleNode){
4961             return quickDiffIEXml(c1, c2);
4962         }
4963         var d = ++key;
4964         for(var i = 0; i < len1; i++){
4965             c1[i]._qdiff = d;
4966         }
4967         var r = [];
4968         for(var i = 0, len = c2.length; i < len; i++){
4969             if(c2[i]._qdiff != d){
4970                 r[r.length] = c2[i];
4971             }
4972         }
4973         return r;
4974     }
4975
4976     function quickId(ns, mode, root, id){
4977         if(ns == root){
4978            var d = root.ownerDocument || root;
4979            return d.getElementById(id);
4980         }
4981         ns = getNodes(ns, mode, "*");
4982         return byId(ns, null, id);
4983     }
4984
4985     return {
4986         getStyle : function(el, name){
4987             return Roo.fly(el).getStyle(name);
4988         },
4989         /**
4990          * Compiles a selector/xpath query into a reusable function. The returned function
4991          * takes one parameter "root" (optional), which is the context node from where the query should start.
4992          * @param {String} selector The selector/xpath query
4993          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4994          * @return {Function}
4995          */
4996         compile : function(path, type){
4997             type = type || "select";
4998             
4999             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5000             var q = path, mode, lq;
5001             var tk = Roo.DomQuery.matchers;
5002             var tklen = tk.length;
5003             var mm;
5004
5005             // accept leading mode switch
5006             var lmode = q.match(modeRe);
5007             if(lmode && lmode[1]){
5008                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5009                 q = q.replace(lmode[1], "");
5010             }
5011             // strip leading slashes
5012             while(path.substr(0, 1)=="/"){
5013                 path = path.substr(1);
5014             }
5015
5016             while(q && lq != q){
5017                 lq = q;
5018                 var tm = q.match(tagTokenRe);
5019                 if(type == "select"){
5020                     if(tm){
5021                         if(tm[1] == "#"){
5022                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5023                         }else{
5024                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5025                         }
5026                         q = q.replace(tm[0], "");
5027                     }else if(q.substr(0, 1) != '@'){
5028                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5029                     }
5030                 }else{
5031                     if(tm){
5032                         if(tm[1] == "#"){
5033                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5034                         }else{
5035                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5036                         }
5037                         q = q.replace(tm[0], "");
5038                     }
5039                 }
5040                 while(!(mm = q.match(modeRe))){
5041                     var matched = false;
5042                     for(var j = 0; j < tklen; j++){
5043                         var t = tk[j];
5044                         var m = q.match(t.re);
5045                         if(m){
5046                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5047                                                     return m[i];
5048                                                 });
5049                             q = q.replace(m[0], "");
5050                             matched = true;
5051                             break;
5052                         }
5053                     }
5054                     // prevent infinite loop on bad selector
5055                     if(!matched){
5056                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5057                     }
5058                 }
5059                 if(mm[1]){
5060                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5061                     q = q.replace(mm[1], "");
5062                 }
5063             }
5064             fn[fn.length] = "return nodup(n);\n}";
5065             
5066              /** 
5067               * list of variables that need from compression as they are used by eval.
5068              *  eval:var:batch 
5069              *  eval:var:nodup
5070              *  eval:var:byTag
5071              *  eval:var:ById
5072              *  eval:var:getNodes
5073              *  eval:var:quickId
5074              *  eval:var:mode
5075              *  eval:var:root
5076              *  eval:var:n
5077              *  eval:var:byClassName
5078              *  eval:var:byPseudo
5079              *  eval:var:byAttribute
5080              *  eval:var:attrValue
5081              * 
5082              **/ 
5083             eval(fn.join(""));
5084             return f;
5085         },
5086
5087         /**
5088          * Selects a group of elements.
5089          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5090          * @param {Node} root (optional) The start of the query (defaults to document).
5091          * @return {Array}
5092          */
5093         select : function(path, root, type){
5094             if(!root || root == document){
5095                 root = document;
5096             }
5097             if(typeof root == "string"){
5098                 root = document.getElementById(root);
5099             }
5100             var paths = path.split(",");
5101             var results = [];
5102             for(var i = 0, len = paths.length; i < len; i++){
5103                 var p = paths[i].replace(trimRe, "");
5104                 if(!cache[p]){
5105                     cache[p] = Roo.DomQuery.compile(p);
5106                     if(!cache[p]){
5107                         throw p + " is not a valid selector";
5108                     }
5109                 }
5110                 var result = cache[p](root);
5111                 if(result && result != document){
5112                     results = results.concat(result);
5113                 }
5114             }
5115             if(paths.length > 1){
5116                 return nodup(results);
5117             }
5118             return results;
5119         },
5120
5121         /**
5122          * Selects a single element.
5123          * @param {String} selector The selector/xpath query
5124          * @param {Node} root (optional) The start of the query (defaults to document).
5125          * @return {Element}
5126          */
5127         selectNode : function(path, root){
5128             return Roo.DomQuery.select(path, root)[0];
5129         },
5130
5131         /**
5132          * Selects the value of a node, optionally replacing null with the defaultValue.
5133          * @param {String} selector The selector/xpath query
5134          * @param {Node} root (optional) The start of the query (defaults to document).
5135          * @param {String} defaultValue
5136          */
5137         selectValue : function(path, root, defaultValue){
5138             path = path.replace(trimRe, "");
5139             if(!valueCache[path]){
5140                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5141             }
5142             var n = valueCache[path](root);
5143             n = n[0] ? n[0] : n;
5144             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5145             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5146         },
5147
5148         /**
5149          * Selects the value of a node, parsing integers and floats.
5150          * @param {String} selector The selector/xpath query
5151          * @param {Node} root (optional) The start of the query (defaults to document).
5152          * @param {Number} defaultValue
5153          * @return {Number}
5154          */
5155         selectNumber : function(path, root, defaultValue){
5156             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5157             return parseFloat(v);
5158         },
5159
5160         /**
5161          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5162          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5163          * @param {String} selector The simple selector to test
5164          * @return {Boolean}
5165          */
5166         is : function(el, ss){
5167             if(typeof el == "string"){
5168                 el = document.getElementById(el);
5169             }
5170             var isArray = (el instanceof Array);
5171             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5172             return isArray ? (result.length == el.length) : (result.length > 0);
5173         },
5174
5175         /**
5176          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5177          * @param {Array} el An array of elements to filter
5178          * @param {String} selector The simple selector to test
5179          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5180          * the selector instead of the ones that match
5181          * @return {Array}
5182          */
5183         filter : function(els, ss, nonMatches){
5184             ss = ss.replace(trimRe, "");
5185             if(!simpleCache[ss]){
5186                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5187             }
5188             var result = simpleCache[ss](els);
5189             return nonMatches ? quickDiff(result, els) : result;
5190         },
5191
5192         /**
5193          * Collection of matching regular expressions and code snippets.
5194          */
5195         matchers : [{
5196                 re: /^\.([\w-]+)/,
5197                 select: 'n = byClassName(n, null, " {1} ");'
5198             }, {
5199                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5200                 select: 'n = byPseudo(n, "{1}", "{2}");'
5201             },{
5202                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5203                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5204             }, {
5205                 re: /^#([\w-]+)/,
5206                 select: 'n = byId(n, null, "{1}");'
5207             },{
5208                 re: /^@([\w-]+)/,
5209                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5210             }
5211         ],
5212
5213         /**
5214          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5215          * 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;.
5216          */
5217         operators : {
5218             "=" : function(a, v){
5219                 return a == v;
5220             },
5221             "!=" : function(a, v){
5222                 return a != v;
5223             },
5224             "^=" : function(a, v){
5225                 return a && a.substr(0, v.length) == v;
5226             },
5227             "$=" : function(a, v){
5228                 return a && a.substr(a.length-v.length) == v;
5229             },
5230             "*=" : function(a, v){
5231                 return a && a.indexOf(v) !== -1;
5232             },
5233             "%=" : function(a, v){
5234                 return (a % v) == 0;
5235             },
5236             "|=" : function(a, v){
5237                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5238             },
5239             "~=" : function(a, v){
5240                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5241             }
5242         },
5243
5244         /**
5245          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5246          * and the argument (if any) supplied in the selector.
5247          */
5248         pseudos : {
5249             "first-child" : function(c){
5250                 var r = [], ri = -1, n;
5251                 for(var i = 0, ci; ci = n = c[i]; i++){
5252                     while((n = n.previousSibling) && n.nodeType != 1);
5253                     if(!n){
5254                         r[++ri] = ci;
5255                     }
5256                 }
5257                 return r;
5258             },
5259
5260             "last-child" : function(c){
5261                 var r = [], ri = -1, n;
5262                 for(var i = 0, ci; ci = n = c[i]; i++){
5263                     while((n = n.nextSibling) && n.nodeType != 1);
5264                     if(!n){
5265                         r[++ri] = ci;
5266                     }
5267                 }
5268                 return r;
5269             },
5270
5271             "nth-child" : function(c, a) {
5272                 var r = [], ri = -1;
5273                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5274                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5275                 for(var i = 0, n; n = c[i]; i++){
5276                     var pn = n.parentNode;
5277                     if (batch != pn._batch) {
5278                         var j = 0;
5279                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5280                             if(cn.nodeType == 1){
5281                                cn.nodeIndex = ++j;
5282                             }
5283                         }
5284                         pn._batch = batch;
5285                     }
5286                     if (f == 1) {
5287                         if (l == 0 || n.nodeIndex == l){
5288                             r[++ri] = n;
5289                         }
5290                     } else if ((n.nodeIndex + l) % f == 0){
5291                         r[++ri] = n;
5292                     }
5293                 }
5294
5295                 return r;
5296             },
5297
5298             "only-child" : function(c){
5299                 var r = [], ri = -1;;
5300                 for(var i = 0, ci; ci = c[i]; i++){
5301                     if(!prev(ci) && !next(ci)){
5302                         r[++ri] = ci;
5303                     }
5304                 }
5305                 return r;
5306             },
5307
5308             "empty" : function(c){
5309                 var r = [], ri = -1;
5310                 for(var i = 0, ci; ci = c[i]; i++){
5311                     var cns = ci.childNodes, j = 0, cn, empty = true;
5312                     while(cn = cns[j]){
5313                         ++j;
5314                         if(cn.nodeType == 1 || cn.nodeType == 3){
5315                             empty = false;
5316                             break;
5317                         }
5318                     }
5319                     if(empty){
5320                         r[++ri] = ci;
5321                     }
5322                 }
5323                 return r;
5324             },
5325
5326             "contains" : function(c, v){
5327                 var r = [], ri = -1;
5328                 for(var i = 0, ci; ci = c[i]; i++){
5329                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5330                         r[++ri] = ci;
5331                     }
5332                 }
5333                 return r;
5334             },
5335
5336             "nodeValue" : function(c, v){
5337                 var r = [], ri = -1;
5338                 for(var i = 0, ci; ci = c[i]; i++){
5339                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5340                         r[++ri] = ci;
5341                     }
5342                 }
5343                 return r;
5344             },
5345
5346             "checked" : function(c){
5347                 var r = [], ri = -1;
5348                 for(var i = 0, ci; ci = c[i]; i++){
5349                     if(ci.checked == true){
5350                         r[++ri] = ci;
5351                     }
5352                 }
5353                 return r;
5354             },
5355
5356             "not" : function(c, ss){
5357                 return Roo.DomQuery.filter(c, ss, true);
5358             },
5359
5360             "odd" : function(c){
5361                 return this["nth-child"](c, "odd");
5362             },
5363
5364             "even" : function(c){
5365                 return this["nth-child"](c, "even");
5366             },
5367
5368             "nth" : function(c, a){
5369                 return c[a-1] || [];
5370             },
5371
5372             "first" : function(c){
5373                 return c[0] || [];
5374             },
5375
5376             "last" : function(c){
5377                 return c[c.length-1] || [];
5378             },
5379
5380             "has" : function(c, ss){
5381                 var s = Roo.DomQuery.select;
5382                 var r = [], ri = -1;
5383                 for(var i = 0, ci; ci = c[i]; i++){
5384                     if(s(ss, ci).length > 0){
5385                         r[++ri] = ci;
5386                     }
5387                 }
5388                 return r;
5389             },
5390
5391             "next" : function(c, ss){
5392                 var is = Roo.DomQuery.is;
5393                 var r = [], ri = -1;
5394                 for(var i = 0, ci; ci = c[i]; i++){
5395                     var n = next(ci);
5396                     if(n && is(n, ss)){
5397                         r[++ri] = ci;
5398                     }
5399                 }
5400                 return r;
5401             },
5402
5403             "prev" : function(c, ss){
5404                 var is = Roo.DomQuery.is;
5405                 var r = [], ri = -1;
5406                 for(var i = 0, ci; ci = c[i]; i++){
5407                     var n = prev(ci);
5408                     if(n && is(n, ss)){
5409                         r[++ri] = ci;
5410                     }
5411                 }
5412                 return r;
5413             }
5414         }
5415     };
5416 }();
5417
5418 /**
5419  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5420  * @param {String} path The selector/xpath query
5421  * @param {Node} root (optional) The start of the query (defaults to document).
5422  * @return {Array}
5423  * @member Roo
5424  * @method query
5425  */
5426 Roo.query = Roo.DomQuery.select;
5427 /*
5428  * Based on:
5429  * Ext JS Library 1.1.1
5430  * Copyright(c) 2006-2007, Ext JS, LLC.
5431  *
5432  * Originally Released Under LGPL - original licence link has changed is not relivant.
5433  *
5434  * Fork - LGPL
5435  * <script type="text/javascript">
5436  */
5437
5438 /**
5439  * @class Roo.util.Observable
5440  * Base class that provides a common interface for publishing events. Subclasses are expected to
5441  * to have a property "events" with all the events defined.<br>
5442  * For example:
5443  * <pre><code>
5444  Employee = function(name){
5445     this.name = name;
5446     this.addEvents({
5447         "fired" : true,
5448         "quit" : true
5449     });
5450  }
5451  Roo.extend(Employee, Roo.util.Observable);
5452 </code></pre>
5453  * @param {Object} config properties to use (incuding events / listeners)
5454  */
5455
5456 Roo.util.Observable = function(cfg){
5457     
5458     cfg = cfg|| {};
5459     this.addEvents(cfg.events || {});
5460     if (cfg.events) {
5461         delete cfg.events; // make sure
5462     }
5463      
5464     Roo.apply(this, cfg);
5465     
5466     if(this.listeners){
5467         this.on(this.listeners);
5468         delete this.listeners;
5469     }
5470 };
5471 Roo.util.Observable.prototype = {
5472     /** 
5473  * @cfg {Object} listeners  list of events and functions to call for this object, 
5474  * For example :
5475  * <pre><code>
5476     listeners :  { 
5477        'click' : function(e) {
5478            ..... 
5479         } ,
5480         .... 
5481     } 
5482   </code></pre>
5483  */
5484     
5485     
5486     /**
5487      * Fires the specified event with the passed parameters (minus the event name).
5488      * @param {String} eventName
5489      * @param {Object...} args Variable number of parameters are passed to handlers
5490      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5491      */
5492     fireEvent : function(){
5493         var ce = this.events[arguments[0].toLowerCase()];
5494         if(typeof ce == "object"){
5495             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5496         }else{
5497             return true;
5498         }
5499     },
5500
5501     // private
5502     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5503
5504     /**
5505      * Appends an event handler to this component
5506      * @param {String}   eventName The type of event to listen for
5507      * @param {Function} handler The method the event invokes
5508      * @param {Object}   scope (optional) The scope in which to execute the handler
5509      * function. The handler function's "this" context.
5510      * @param {Object}   options (optional) An object containing handler configuration
5511      * properties. This may contain any of the following properties:<ul>
5512      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5513      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5514      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5515      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5516      * by the specified number of milliseconds. If the event fires again within that time, the original
5517      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5518      * </ul><br>
5519      * <p>
5520      * <b>Combining Options</b><br>
5521      * Using the options argument, it is possible to combine different types of listeners:<br>
5522      * <br>
5523      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5524                 <pre><code>
5525                 el.on('click', this.onClick, this, {
5526                         single: true,
5527                 delay: 100,
5528                 forumId: 4
5529                 });
5530                 </code></pre>
5531      * <p>
5532      * <b>Attaching multiple handlers in 1 call</b><br>
5533      * The method also allows for a single argument to be passed which is a config object containing properties
5534      * which specify multiple handlers.
5535      * <pre><code>
5536                 el.on({
5537                         'click': {
5538                         fn: this.onClick,
5539                         scope: this,
5540                         delay: 100
5541                 }, 
5542                 'mouseover': {
5543                         fn: this.onMouseOver,
5544                         scope: this
5545                 },
5546                 'mouseout': {
5547                         fn: this.onMouseOut,
5548                         scope: this
5549                 }
5550                 });
5551                 </code></pre>
5552      * <p>
5553      * Or a shorthand syntax which passes the same scope object to all handlers:
5554         <pre><code>
5555                 el.on({
5556                         'click': this.onClick,
5557                 'mouseover': this.onMouseOver,
5558                 'mouseout': this.onMouseOut,
5559                 scope: this
5560                 });
5561                 </code></pre>
5562      */
5563     addListener : function(eventName, fn, scope, o){
5564         if(typeof eventName == "object"){
5565             o = eventName;
5566             for(var e in o){
5567                 if(this.filterOptRe.test(e)){
5568                     continue;
5569                 }
5570                 if(typeof o[e] == "function"){
5571                     // shared options
5572                     this.addListener(e, o[e], o.scope,  o);
5573                 }else{
5574                     // individual options
5575                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5576                 }
5577             }
5578             return;
5579         }
5580         o = (!o || typeof o == "boolean") ? {} : o;
5581         eventName = eventName.toLowerCase();
5582         var ce = this.events[eventName] || true;
5583         if(typeof ce == "boolean"){
5584             ce = new Roo.util.Event(this, eventName);
5585             this.events[eventName] = ce;
5586         }
5587         ce.addListener(fn, scope, o);
5588     },
5589
5590     /**
5591      * Removes a listener
5592      * @param {String}   eventName     The type of event to listen for
5593      * @param {Function} handler        The handler to remove
5594      * @param {Object}   scope  (optional) The scope (this object) for the handler
5595      */
5596     removeListener : function(eventName, fn, scope){
5597         var ce = this.events[eventName.toLowerCase()];
5598         if(typeof ce == "object"){
5599             ce.removeListener(fn, scope);
5600         }
5601     },
5602
5603     /**
5604      * Removes all listeners for this object
5605      */
5606     purgeListeners : function(){
5607         for(var evt in this.events){
5608             if(typeof this.events[evt] == "object"){
5609                  this.events[evt].clearListeners();
5610             }
5611         }
5612     },
5613
5614     relayEvents : function(o, events){
5615         var createHandler = function(ename){
5616             return function(){
5617                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5618             };
5619         };
5620         for(var i = 0, len = events.length; i < len; i++){
5621             var ename = events[i];
5622             if(!this.events[ename]){ this.events[ename] = true; };
5623             o.on(ename, createHandler(ename), this);
5624         }
5625     },
5626
5627     /**
5628      * Used to define events on this Observable
5629      * @param {Object} object The object with the events defined
5630      */
5631     addEvents : function(o){
5632         if(!this.events){
5633             this.events = {};
5634         }
5635         Roo.applyIf(this.events, o);
5636     },
5637
5638     /**
5639      * Checks to see if this object has any listeners for a specified event
5640      * @param {String} eventName The name of the event to check for
5641      * @return {Boolean} True if the event is being listened for, else false
5642      */
5643     hasListener : function(eventName){
5644         var e = this.events[eventName];
5645         return typeof e == "object" && e.listeners.length > 0;
5646     }
5647 };
5648 /**
5649  * Appends an event handler to this element (shorthand for addListener)
5650  * @param {String}   eventName     The type of event to listen for
5651  * @param {Function} handler        The method the event invokes
5652  * @param {Object}   scope (optional) The scope in which to execute the handler
5653  * function. The handler function's "this" context.
5654  * @param {Object}   options  (optional)
5655  * @method
5656  */
5657 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5658 /**
5659  * Removes a listener (shorthand for removeListener)
5660  * @param {String}   eventName     The type of event to listen for
5661  * @param {Function} handler        The handler to remove
5662  * @param {Object}   scope  (optional) The scope (this object) for the handler
5663  * @method
5664  */
5665 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5666
5667 /**
5668  * Starts capture on the specified Observable. All events will be passed
5669  * to the supplied function with the event name + standard signature of the event
5670  * <b>before</b> the event is fired. If the supplied function returns false,
5671  * the event will not fire.
5672  * @param {Observable} o The Observable to capture
5673  * @param {Function} fn The function to call
5674  * @param {Object} scope (optional) The scope (this object) for the fn
5675  * @static
5676  */
5677 Roo.util.Observable.capture = function(o, fn, scope){
5678     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5679 };
5680
5681 /**
5682  * Removes <b>all</b> added captures from the Observable.
5683  * @param {Observable} o The Observable to release
5684  * @static
5685  */
5686 Roo.util.Observable.releaseCapture = function(o){
5687     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5688 };
5689
5690 (function(){
5691
5692     var createBuffered = function(h, o, scope){
5693         var task = new Roo.util.DelayedTask();
5694         return function(){
5695             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5696         };
5697     };
5698
5699     var createSingle = function(h, e, fn, scope){
5700         return function(){
5701             e.removeListener(fn, scope);
5702             return h.apply(scope, arguments);
5703         };
5704     };
5705
5706     var createDelayed = function(h, o, scope){
5707         return function(){
5708             var args = Array.prototype.slice.call(arguments, 0);
5709             setTimeout(function(){
5710                 h.apply(scope, args);
5711             }, o.delay || 10);
5712         };
5713     };
5714
5715     Roo.util.Event = function(obj, name){
5716         this.name = name;
5717         this.obj = obj;
5718         this.listeners = [];
5719     };
5720
5721     Roo.util.Event.prototype = {
5722         addListener : function(fn, scope, options){
5723             var o = options || {};
5724             scope = scope || this.obj;
5725             if(!this.isListening(fn, scope)){
5726                 var l = {fn: fn, scope: scope, options: o};
5727                 var h = fn;
5728                 if(o.delay){
5729                     h = createDelayed(h, o, scope);
5730                 }
5731                 if(o.single){
5732                     h = createSingle(h, this, fn, scope);
5733                 }
5734                 if(o.buffer){
5735                     h = createBuffered(h, o, scope);
5736                 }
5737                 l.fireFn = h;
5738                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5739                     this.listeners.push(l);
5740                 }else{
5741                     this.listeners = this.listeners.slice(0);
5742                     this.listeners.push(l);
5743                 }
5744             }
5745         },
5746
5747         findListener : function(fn, scope){
5748             scope = scope || this.obj;
5749             var ls = this.listeners;
5750             for(var i = 0, len = ls.length; i < len; i++){
5751                 var l = ls[i];
5752                 if(l.fn == fn && l.scope == scope){
5753                     return i;
5754                 }
5755             }
5756             return -1;
5757         },
5758
5759         isListening : function(fn, scope){
5760             return this.findListener(fn, scope) != -1;
5761         },
5762
5763         removeListener : function(fn, scope){
5764             var index;
5765             if((index = this.findListener(fn, scope)) != -1){
5766                 if(!this.firing){
5767                     this.listeners.splice(index, 1);
5768                 }else{
5769                     this.listeners = this.listeners.slice(0);
5770                     this.listeners.splice(index, 1);
5771                 }
5772                 return true;
5773             }
5774             return false;
5775         },
5776
5777         clearListeners : function(){
5778             this.listeners = [];
5779         },
5780
5781         fire : function(){
5782             var ls = this.listeners, scope, len = ls.length;
5783             if(len > 0){
5784                 this.firing = true;
5785                 var args = Array.prototype.slice.call(arguments, 0);
5786                 for(var i = 0; i < len; i++){
5787                     var l = ls[i];
5788                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5789                         this.firing = false;
5790                         return false;
5791                     }
5792                 }
5793                 this.firing = false;
5794             }
5795             return true;
5796         }
5797     };
5798 })();/*
5799  * Based on:
5800  * Ext JS Library 1.1.1
5801  * Copyright(c) 2006-2007, Ext JS, LLC.
5802  *
5803  * Originally Released Under LGPL - original licence link has changed is not relivant.
5804  *
5805  * Fork - LGPL
5806  * <script type="text/javascript">
5807  */
5808
5809 /**
5810  * @class Roo.EventManager
5811  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5812  * several useful events directly.
5813  * See {@link Roo.EventObject} for more details on normalized event objects.
5814  * @singleton
5815  */
5816 Roo.EventManager = function(){
5817     var docReadyEvent, docReadyProcId, docReadyState = false;
5818     var resizeEvent, resizeTask, textEvent, textSize;
5819     var E = Roo.lib.Event;
5820     var D = Roo.lib.Dom;
5821
5822
5823     var fireDocReady = function(){
5824         if(!docReadyState){
5825             docReadyState = true;
5826             Roo.isReady = true;
5827             if(docReadyProcId){
5828                 clearInterval(docReadyProcId);
5829             }
5830             if(Roo.isGecko || Roo.isOpera) {
5831                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5832             }
5833             if(Roo.isIE){
5834                 var defer = document.getElementById("ie-deferred-loader");
5835                 if(defer){
5836                     defer.onreadystatechange = null;
5837                     defer.parentNode.removeChild(defer);
5838                 }
5839             }
5840             if(docReadyEvent){
5841                 docReadyEvent.fire();
5842                 docReadyEvent.clearListeners();
5843             }
5844         }
5845     };
5846     
5847     var initDocReady = function(){
5848         docReadyEvent = new Roo.util.Event();
5849         if(Roo.isGecko || Roo.isOpera) {
5850             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5851         }else if(Roo.isIE){
5852             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5853             var defer = document.getElementById("ie-deferred-loader");
5854             defer.onreadystatechange = function(){
5855                 if(this.readyState == "complete"){
5856                     fireDocReady();
5857                 }
5858             };
5859         }else if(Roo.isSafari){ 
5860             docReadyProcId = setInterval(function(){
5861                 var rs = document.readyState;
5862                 if(rs == "complete") {
5863                     fireDocReady();     
5864                  }
5865             }, 10);
5866         }
5867         // no matter what, make sure it fires on load
5868         E.on(window, "load", fireDocReady);
5869     };
5870
5871     var createBuffered = function(h, o){
5872         var task = new Roo.util.DelayedTask(h);
5873         return function(e){
5874             // create new event object impl so new events don't wipe out properties
5875             e = new Roo.EventObjectImpl(e);
5876             task.delay(o.buffer, h, null, [e]);
5877         };
5878     };
5879
5880     var createSingle = function(h, el, ename, fn){
5881         return function(e){
5882             Roo.EventManager.removeListener(el, ename, fn);
5883             h(e);
5884         };
5885     };
5886
5887     var createDelayed = function(h, o){
5888         return function(e){
5889             // create new event object impl so new events don't wipe out properties
5890             e = new Roo.EventObjectImpl(e);
5891             setTimeout(function(){
5892                 h(e);
5893             }, o.delay || 10);
5894         };
5895     };
5896
5897     var listen = function(element, ename, opt, fn, scope){
5898         var o = (!opt || typeof opt == "boolean") ? {} : opt;
5899         fn = fn || o.fn; scope = scope || o.scope;
5900         var el = Roo.getDom(element);
5901         if(!el){
5902             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5903         }
5904         var h = function(e){
5905             e = Roo.EventObject.setEvent(e);
5906             var t;
5907             if(o.delegate){
5908                 t = e.getTarget(o.delegate, el);
5909                 if(!t){
5910                     return;
5911                 }
5912             }else{
5913                 t = e.target;
5914             }
5915             if(o.stopEvent === true){
5916                 e.stopEvent();
5917             }
5918             if(o.preventDefault === true){
5919                e.preventDefault();
5920             }
5921             if(o.stopPropagation === true){
5922                 e.stopPropagation();
5923             }
5924
5925             if(o.normalized === false){
5926                 e = e.browserEvent;
5927             }
5928
5929             fn.call(scope || el, e, t, o);
5930         };
5931         if(o.delay){
5932             h = createDelayed(h, o);
5933         }
5934         if(o.single){
5935             h = createSingle(h, el, ename, fn);
5936         }
5937         if(o.buffer){
5938             h = createBuffered(h, o);
5939         }
5940         fn._handlers = fn._handlers || [];
5941         fn._handlers.push([Roo.id(el), ename, h]);
5942
5943         E.on(el, ename, h);
5944         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5945             el.addEventListener("DOMMouseScroll", h, false);
5946             E.on(window, 'unload', function(){
5947                 el.removeEventListener("DOMMouseScroll", h, false);
5948             });
5949         }
5950         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5951             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5952         }
5953         return h;
5954     };
5955
5956     var stopListening = function(el, ename, fn){
5957         var id = Roo.id(el), hds = fn._handlers, hd = fn;
5958         if(hds){
5959             for(var i = 0, len = hds.length; i < len; i++){
5960                 var h = hds[i];
5961                 if(h[0] == id && h[1] == ename){
5962                     hd = h[2];
5963                     hds.splice(i, 1);
5964                     break;
5965                 }
5966             }
5967         }
5968         E.un(el, ename, hd);
5969         el = Roo.getDom(el);
5970         if(ename == "mousewheel" && el.addEventListener){
5971             el.removeEventListener("DOMMouseScroll", hd, false);
5972         }
5973         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5974             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5975         }
5976     };
5977
5978     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5979     
5980     var pub = {
5981         
5982         
5983         /** 
5984          * Fix for doc tools
5985          * @scope Roo.EventManager
5986          */
5987         
5988         
5989         /** 
5990          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5991          * object with a Roo.EventObject
5992          * @param {Function} fn        The method the event invokes
5993          * @param {Object}   scope    An object that becomes the scope of the handler
5994          * @param {boolean}  override If true, the obj passed in becomes
5995          *                             the execution scope of the listener
5996          * @return {Function} The wrapped function
5997          * @deprecated
5998          */
5999         wrap : function(fn, scope, override){
6000             return function(e){
6001                 Roo.EventObject.setEvent(e);
6002                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6003             };
6004         },
6005         
6006         /**
6007      * Appends an event handler to an element (shorthand for addListener)
6008      * @param {String/HTMLElement}   element        The html element or id to assign the
6009      * @param {String}   eventName The type of event to listen for
6010      * @param {Function} handler The method the event invokes
6011      * @param {Object}   scope (optional) The scope in which to execute the handler
6012      * function. The handler function's "this" context.
6013      * @param {Object}   options (optional) An object containing handler configuration
6014      * properties. This may contain any of the following properties:<ul>
6015      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6016      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6017      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6018      * <li>preventDefault {Boolean} True to prevent the default action</li>
6019      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6020      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6021      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6022      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6023      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6024      * by the specified number of milliseconds. If the event fires again within that time, the original
6025      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6026      * </ul><br>
6027      * <p>
6028      * <b>Combining Options</b><br>
6029      * Using the options argument, it is possible to combine different types of listeners:<br>
6030      * <br>
6031      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6032      * Code:<pre><code>
6033 el.on('click', this.onClick, this, {
6034     single: true,
6035     delay: 100,
6036     stopEvent : true,
6037     forumId: 4
6038 });</code></pre>
6039      * <p>
6040      * <b>Attaching multiple handlers in 1 call</b><br>
6041       * The method also allows for a single argument to be passed which is a config object containing properties
6042      * which specify multiple handlers.
6043      * <p>
6044      * Code:<pre><code>
6045 el.on({
6046     'click' : {
6047         fn: this.onClick
6048         scope: this,
6049         delay: 100
6050     },
6051     'mouseover' : {
6052         fn: this.onMouseOver
6053         scope: this
6054     },
6055     'mouseout' : {
6056         fn: this.onMouseOut
6057         scope: this
6058     }
6059 });</code></pre>
6060      * <p>
6061      * Or a shorthand syntax:<br>
6062      * Code:<pre><code>
6063 el.on({
6064     'click' : this.onClick,
6065     'mouseover' : this.onMouseOver,
6066     'mouseout' : this.onMouseOut
6067     scope: this
6068 });</code></pre>
6069      */
6070         addListener : function(element, eventName, fn, scope, options){
6071             if(typeof eventName == "object"){
6072                 var o = eventName;
6073                 for(var e in o){
6074                     if(propRe.test(e)){
6075                         continue;
6076                     }
6077                     if(typeof o[e] == "function"){
6078                         // shared options
6079                         listen(element, e, o, o[e], o.scope);
6080                     }else{
6081                         // individual options
6082                         listen(element, e, o[e]);
6083                     }
6084                 }
6085                 return;
6086             }
6087             return listen(element, eventName, options, fn, scope);
6088         },
6089         
6090         /**
6091          * Removes an event handler
6092          *
6093          * @param {String/HTMLElement}   element        The id or html element to remove the 
6094          *                             event from
6095          * @param {String}   eventName     The type of event
6096          * @param {Function} fn
6097          * @return {Boolean} True if a listener was actually removed
6098          */
6099         removeListener : function(element, eventName, fn){
6100             return stopListening(element, eventName, fn);
6101         },
6102         
6103         /**
6104          * Fires when the document is ready (before onload and before images are loaded). Can be 
6105          * accessed shorthanded Roo.onReady().
6106          * @param {Function} fn        The method the event invokes
6107          * @param {Object}   scope    An  object that becomes the scope of the handler
6108          * @param {boolean}  options
6109          */
6110         onDocumentReady : function(fn, scope, options){
6111             if(docReadyState){ // if it already fired
6112                 docReadyEvent.addListener(fn, scope, options);
6113                 docReadyEvent.fire();
6114                 docReadyEvent.clearListeners();
6115                 return;
6116             }
6117             if(!docReadyEvent){
6118                 initDocReady();
6119             }
6120             docReadyEvent.addListener(fn, scope, options);
6121         },
6122         
6123         /**
6124          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6125          * @param {Function} fn        The method the event invokes
6126          * @param {Object}   scope    An object that becomes the scope of the handler
6127          * @param {boolean}  options
6128          */
6129         onWindowResize : function(fn, scope, options){
6130             if(!resizeEvent){
6131                 resizeEvent = new Roo.util.Event();
6132                 resizeTask = new Roo.util.DelayedTask(function(){
6133                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6134                 });
6135                 E.on(window, "resize", function(){
6136                     if(Roo.isIE){
6137                         resizeTask.delay(50);
6138                     }else{
6139                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6140                     }
6141                 });
6142             }
6143             resizeEvent.addListener(fn, scope, options);
6144         },
6145
6146         /**
6147          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6148          * @param {Function} fn        The method the event invokes
6149          * @param {Object}   scope    An object that becomes the scope of the handler
6150          * @param {boolean}  options
6151          */
6152         onTextResize : function(fn, scope, options){
6153             if(!textEvent){
6154                 textEvent = new Roo.util.Event();
6155                 var textEl = new Roo.Element(document.createElement('div'));
6156                 textEl.dom.className = 'x-text-resize';
6157                 textEl.dom.innerHTML = 'X';
6158                 textEl.appendTo(document.body);
6159                 textSize = textEl.dom.offsetHeight;
6160                 setInterval(function(){
6161                     if(textEl.dom.offsetHeight != textSize){
6162                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6163                     }
6164                 }, this.textResizeInterval);
6165             }
6166             textEvent.addListener(fn, scope, options);
6167         },
6168
6169         /**
6170          * Removes the passed window resize listener.
6171          * @param {Function} fn        The method the event invokes
6172          * @param {Object}   scope    The scope of handler
6173          */
6174         removeResizeListener : function(fn, scope){
6175             if(resizeEvent){
6176                 resizeEvent.removeListener(fn, scope);
6177             }
6178         },
6179
6180         // private
6181         fireResize : function(){
6182             if(resizeEvent){
6183                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6184             }   
6185         },
6186         /**
6187          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6188          */
6189         ieDeferSrc : false,
6190         /**
6191          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6192          */
6193         textResizeInterval : 50
6194     };
6195     
6196     /**
6197      * Fix for doc tools
6198      * @scopeAlias pub=Roo.EventManager
6199      */
6200     
6201      /**
6202      * Appends an event handler to an element (shorthand for addListener)
6203      * @param {String/HTMLElement}   element        The html element or id to assign the
6204      * @param {String}   eventName The type of event to listen for
6205      * @param {Function} handler The method the event invokes
6206      * @param {Object}   scope (optional) The scope in which to execute the handler
6207      * function. The handler function's "this" context.
6208      * @param {Object}   options (optional) An object containing handler configuration
6209      * properties. This may contain any of the following properties:<ul>
6210      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6211      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6212      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6213      * <li>preventDefault {Boolean} True to prevent the default action</li>
6214      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6215      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6216      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6217      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6218      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6219      * by the specified number of milliseconds. If the event fires again within that time, the original
6220      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6221      * </ul><br>
6222      * <p>
6223      * <b>Combining Options</b><br>
6224      * Using the options argument, it is possible to combine different types of listeners:<br>
6225      * <br>
6226      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6227      * Code:<pre><code>
6228 el.on('click', this.onClick, this, {
6229     single: true,
6230     delay: 100,
6231     stopEvent : true,
6232     forumId: 4
6233 });</code></pre>
6234      * <p>
6235      * <b>Attaching multiple handlers in 1 call</b><br>
6236       * The method also allows for a single argument to be passed which is a config object containing properties
6237      * which specify multiple handlers.
6238      * <p>
6239      * Code:<pre><code>
6240 el.on({
6241     'click' : {
6242         fn: this.onClick
6243         scope: this,
6244         delay: 100
6245     },
6246     'mouseover' : {
6247         fn: this.onMouseOver
6248         scope: this
6249     },
6250     'mouseout' : {
6251         fn: this.onMouseOut
6252         scope: this
6253     }
6254 });</code></pre>
6255      * <p>
6256      * Or a shorthand syntax:<br>
6257      * Code:<pre><code>
6258 el.on({
6259     'click' : this.onClick,
6260     'mouseover' : this.onMouseOver,
6261     'mouseout' : this.onMouseOut
6262     scope: this
6263 });</code></pre>
6264      */
6265     pub.on = pub.addListener;
6266     pub.un = pub.removeListener;
6267
6268     pub.stoppedMouseDownEvent = new Roo.util.Event();
6269     return pub;
6270 }();
6271 /**
6272   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6273   * @param {Function} fn        The method the event invokes
6274   * @param {Object}   scope    An  object that becomes the scope of the handler
6275   * @param {boolean}  override If true, the obj passed in becomes
6276   *                             the execution scope of the listener
6277   * @member Roo
6278   * @method onReady
6279  */
6280 Roo.onReady = Roo.EventManager.onDocumentReady;
6281
6282 Roo.onReady(function(){
6283     var bd = Roo.get(document.body);
6284     if(!bd){ return; }
6285
6286     var cls = [
6287             Roo.isIE ? "roo-ie"
6288             : Roo.isGecko ? "roo-gecko"
6289             : Roo.isOpera ? "roo-opera"
6290             : Roo.isSafari ? "roo-safari" : ""];
6291
6292     if(Roo.isMac){
6293         cls.push("roo-mac");
6294     }
6295     if(Roo.isLinux){
6296         cls.push("roo-linux");
6297     }
6298     if(Roo.isBorderBox){
6299         cls.push('roo-border-box');
6300     }
6301     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6302         var p = bd.dom.parentNode;
6303         if(p){
6304             p.className += ' roo-strict';
6305         }
6306     }
6307     bd.addClass(cls.join(' '));
6308 });
6309
6310 /**
6311  * @class Roo.EventObject
6312  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6313  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6314  * Example:
6315  * <pre><code>
6316  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6317     e.preventDefault();
6318     var target = e.getTarget();
6319     ...
6320  }
6321  var myDiv = Roo.get("myDiv");
6322  myDiv.on("click", handleClick);
6323  //or
6324  Roo.EventManager.on("myDiv", 'click', handleClick);
6325  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6326  </code></pre>
6327  * @singleton
6328  */
6329 Roo.EventObject = function(){
6330     
6331     var E = Roo.lib.Event;
6332     
6333     // safari keypress events for special keys return bad keycodes
6334     var safariKeys = {
6335         63234 : 37, // left
6336         63235 : 39, // right
6337         63232 : 38, // up
6338         63233 : 40, // down
6339         63276 : 33, // page up
6340         63277 : 34, // page down
6341         63272 : 46, // delete
6342         63273 : 36, // home
6343         63275 : 35  // end
6344     };
6345
6346     // normalize button clicks
6347     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6348                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6349
6350     Roo.EventObjectImpl = function(e){
6351         if(e){
6352             this.setEvent(e.browserEvent || e);
6353         }
6354     };
6355     Roo.EventObjectImpl.prototype = {
6356         /**
6357          * Used to fix doc tools.
6358          * @scope Roo.EventObject.prototype
6359          */
6360             
6361
6362         
6363         
6364         /** The normal browser event */
6365         browserEvent : null,
6366         /** The button pressed in a mouse event */
6367         button : -1,
6368         /** True if the shift key was down during the event */
6369         shiftKey : false,
6370         /** True if the control key was down during the event */
6371         ctrlKey : false,
6372         /** True if the alt key was down during the event */
6373         altKey : false,
6374
6375         /** Key constant 
6376         * @type Number */
6377         BACKSPACE : 8,
6378         /** Key constant 
6379         * @type Number */
6380         TAB : 9,
6381         /** Key constant 
6382         * @type Number */
6383         RETURN : 13,
6384         /** Key constant 
6385         * @type Number */
6386         ENTER : 13,
6387         /** Key constant 
6388         * @type Number */
6389         SHIFT : 16,
6390         /** Key constant 
6391         * @type Number */
6392         CONTROL : 17,
6393         /** Key constant 
6394         * @type Number */
6395         ESC : 27,
6396         /** Key constant 
6397         * @type Number */
6398         SPACE : 32,
6399         /** Key constant 
6400         * @type Number */
6401         PAGEUP : 33,
6402         /** Key constant 
6403         * @type Number */
6404         PAGEDOWN : 34,
6405         /** Key constant 
6406         * @type Number */
6407         END : 35,
6408         /** Key constant 
6409         * @type Number */
6410         HOME : 36,
6411         /** Key constant 
6412         * @type Number */
6413         LEFT : 37,
6414         /** Key constant 
6415         * @type Number */
6416         UP : 38,
6417         /** Key constant 
6418         * @type Number */
6419         RIGHT : 39,
6420         /** Key constant 
6421         * @type Number */
6422         DOWN : 40,
6423         /** Key constant 
6424         * @type Number */
6425         DELETE : 46,
6426         /** Key constant 
6427         * @type Number */
6428         F5 : 116,
6429
6430            /** @private */
6431         setEvent : function(e){
6432             if(e == this || (e && e.browserEvent)){ // already wrapped
6433                 return e;
6434             }
6435             this.browserEvent = e;
6436             if(e){
6437                 // normalize buttons
6438                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6439                 if(e.type == 'click' && this.button == -1){
6440                     this.button = 0;
6441                 }
6442                 this.type = e.type;
6443                 this.shiftKey = e.shiftKey;
6444                 // mac metaKey behaves like ctrlKey
6445                 this.ctrlKey = e.ctrlKey || e.metaKey;
6446                 this.altKey = e.altKey;
6447                 // in getKey these will be normalized for the mac
6448                 this.keyCode = e.keyCode;
6449                 // keyup warnings on firefox.
6450                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6451                 // cache the target for the delayed and or buffered events
6452                 this.target = E.getTarget(e);
6453                 // same for XY
6454                 this.xy = E.getXY(e);
6455             }else{
6456                 this.button = -1;
6457                 this.shiftKey = false;
6458                 this.ctrlKey = false;
6459                 this.altKey = false;
6460                 this.keyCode = 0;
6461                 this.charCode =0;
6462                 this.target = null;
6463                 this.xy = [0, 0];
6464             }
6465             return this;
6466         },
6467
6468         /**
6469          * Stop the event (preventDefault and stopPropagation)
6470          */
6471         stopEvent : function(){
6472             if(this.browserEvent){
6473                 if(this.browserEvent.type == 'mousedown'){
6474                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6475                 }
6476                 E.stopEvent(this.browserEvent);
6477             }
6478         },
6479
6480         /**
6481          * Prevents the browsers default handling of the event.
6482          */
6483         preventDefault : function(){
6484             if(this.browserEvent){
6485                 E.preventDefault(this.browserEvent);
6486             }
6487         },
6488
6489         /** @private */
6490         isNavKeyPress : function(){
6491             var k = this.keyCode;
6492             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6493             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6494         },
6495
6496         isSpecialKey : function(){
6497             var k = this.keyCode;
6498             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6499             (k == 16) || (k == 17) ||
6500             (k >= 18 && k <= 20) ||
6501             (k >= 33 && k <= 35) ||
6502             (k >= 36 && k <= 39) ||
6503             (k >= 44 && k <= 45);
6504         },
6505         /**
6506          * Cancels bubbling of the event.
6507          */
6508         stopPropagation : function(){
6509             if(this.browserEvent){
6510                 if(this.type == 'mousedown'){
6511                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6512                 }
6513                 E.stopPropagation(this.browserEvent);
6514             }
6515         },
6516
6517         /**
6518          * Gets the key code for the event.
6519          * @return {Number}
6520          */
6521         getCharCode : function(){
6522             return this.charCode || this.keyCode;
6523         },
6524
6525         /**
6526          * Returns a normalized keyCode for the event.
6527          * @return {Number} The key code
6528          */
6529         getKey : function(){
6530             var k = this.keyCode || this.charCode;
6531             return Roo.isSafari ? (safariKeys[k] || k) : k;
6532         },
6533
6534         /**
6535          * Gets the x coordinate of the event.
6536          * @return {Number}
6537          */
6538         getPageX : function(){
6539             return this.xy[0];
6540         },
6541
6542         /**
6543          * Gets the y coordinate of the event.
6544          * @return {Number}
6545          */
6546         getPageY : function(){
6547             return this.xy[1];
6548         },
6549
6550         /**
6551          * Gets the time of the event.
6552          * @return {Number}
6553          */
6554         getTime : function(){
6555             if(this.browserEvent){
6556                 return E.getTime(this.browserEvent);
6557             }
6558             return null;
6559         },
6560
6561         /**
6562          * Gets the page coordinates of the event.
6563          * @return {Array} The xy values like [x, y]
6564          */
6565         getXY : function(){
6566             return this.xy;
6567         },
6568
6569         /**
6570          * Gets the target for the event.
6571          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6572          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6573                 search as a number or element (defaults to 10 || document.body)
6574          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6575          * @return {HTMLelement}
6576          */
6577         getTarget : function(selector, maxDepth, returnEl){
6578             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6579         },
6580         /**
6581          * Gets the related target.
6582          * @return {HTMLElement}
6583          */
6584         getRelatedTarget : function(){
6585             if(this.browserEvent){
6586                 return E.getRelatedTarget(this.browserEvent);
6587             }
6588             return null;
6589         },
6590
6591         /**
6592          * Normalizes mouse wheel delta across browsers
6593          * @return {Number} The delta
6594          */
6595         getWheelDelta : function(){
6596             var e = this.browserEvent;
6597             var delta = 0;
6598             if(e.wheelDelta){ /* IE/Opera. */
6599                 delta = e.wheelDelta/120;
6600             }else if(e.detail){ /* Mozilla case. */
6601                 delta = -e.detail/3;
6602             }
6603             return delta;
6604         },
6605
6606         /**
6607          * Returns true if the control, meta, shift or alt key was pressed during this event.
6608          * @return {Boolean}
6609          */
6610         hasModifier : function(){
6611             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6612         },
6613
6614         /**
6615          * Returns true if the target of this event equals el or is a child of el
6616          * @param {String/HTMLElement/Element} el
6617          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6618          * @return {Boolean}
6619          */
6620         within : function(el, related){
6621             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6622             return t && Roo.fly(el).contains(t);
6623         },
6624
6625         getPoint : function(){
6626             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6627         }
6628     };
6629
6630     return new Roo.EventObjectImpl();
6631 }();
6632             
6633     /*
6634  * Based on:
6635  * Ext JS Library 1.1.1
6636  * Copyright(c) 2006-2007, Ext JS, LLC.
6637  *
6638  * Originally Released Under LGPL - original licence link has changed is not relivant.
6639  *
6640  * Fork - LGPL
6641  * <script type="text/javascript">
6642  */
6643
6644  
6645 // was in Composite Element!??!?!
6646  
6647 (function(){
6648     var D = Roo.lib.Dom;
6649     var E = Roo.lib.Event;
6650     var A = Roo.lib.Anim;
6651
6652     // local style camelizing for speed
6653     var propCache = {};
6654     var camelRe = /(-[a-z])/gi;
6655     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6656     var view = document.defaultView;
6657
6658 /**
6659  * @class Roo.Element
6660  * Represents an Element in the DOM.<br><br>
6661  * Usage:<br>
6662 <pre><code>
6663 var el = Roo.get("my-div");
6664
6665 // or with getEl
6666 var el = getEl("my-div");
6667
6668 // or with a DOM element
6669 var el = Roo.get(myDivElement);
6670 </code></pre>
6671  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6672  * each call instead of constructing a new one.<br><br>
6673  * <b>Animations</b><br />
6674  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6675  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6676 <pre>
6677 Option    Default   Description
6678 --------- --------  ---------------------------------------------
6679 duration  .35       The duration of the animation in seconds
6680 easing    easeOut   The YUI easing method
6681 callback  none      A function to execute when the anim completes
6682 scope     this      The scope (this) of the callback function
6683 </pre>
6684 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6685 * manipulate the animation. Here's an example:
6686 <pre><code>
6687 var el = Roo.get("my-div");
6688
6689 // no animation
6690 el.setWidth(100);
6691
6692 // default animation
6693 el.setWidth(100, true);
6694
6695 // animation with some options set
6696 el.setWidth(100, {
6697     duration: 1,
6698     callback: this.foo,
6699     scope: this
6700 });
6701
6702 // using the "anim" property to get the Anim object
6703 var opt = {
6704     duration: 1,
6705     callback: this.foo,
6706     scope: this
6707 };
6708 el.setWidth(100, opt);
6709 ...
6710 if(opt.anim.isAnimated()){
6711     opt.anim.stop();
6712 }
6713 </code></pre>
6714 * <b> Composite (Collections of) Elements</b><br />
6715  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6716  * @constructor Create a new Element directly.
6717  * @param {String/HTMLElement} element
6718  * @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).
6719  */
6720     Roo.Element = function(element, forceNew){
6721         var dom = typeof element == "string" ?
6722                 document.getElementById(element) : element;
6723         if(!dom){ // invalid id/element
6724             return null;
6725         }
6726         var id = dom.id;
6727         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6728             return Roo.Element.cache[id];
6729         }
6730
6731         /**
6732          * The DOM element
6733          * @type HTMLElement
6734          */
6735         this.dom = dom;
6736
6737         /**
6738          * The DOM element ID
6739          * @type String
6740          */
6741         this.id = id || Roo.id(dom);
6742     };
6743
6744     var El = Roo.Element;
6745
6746     El.prototype = {
6747         /**
6748          * The element's default display mode  (defaults to "")
6749          * @type String
6750          */
6751         originalDisplay : "",
6752
6753         visibilityMode : 1,
6754         /**
6755          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6756          * @type String
6757          */
6758         defaultUnit : "px",
6759         /**
6760          * Sets the element's visibility mode. When setVisible() is called it
6761          * will use this to determine whether to set the visibility or the display property.
6762          * @param visMode Element.VISIBILITY or Element.DISPLAY
6763          * @return {Roo.Element} this
6764          */
6765         setVisibilityMode : function(visMode){
6766             this.visibilityMode = visMode;
6767             return this;
6768         },
6769         /**
6770          * Convenience method for setVisibilityMode(Element.DISPLAY)
6771          * @param {String} display (optional) What to set display to when visible
6772          * @return {Roo.Element} this
6773          */
6774         enableDisplayMode : function(display){
6775             this.setVisibilityMode(El.DISPLAY);
6776             if(typeof display != "undefined") this.originalDisplay = display;
6777             return this;
6778         },
6779
6780         /**
6781          * 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)
6782          * @param {String} selector The simple selector to test
6783          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6784                 search as a number or element (defaults to 10 || document.body)
6785          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6786          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6787          */
6788         findParent : function(simpleSelector, maxDepth, returnEl){
6789             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6790             maxDepth = maxDepth || 50;
6791             if(typeof maxDepth != "number"){
6792                 stopEl = Roo.getDom(maxDepth);
6793                 maxDepth = 10;
6794             }
6795             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6796                 if(dq.is(p, simpleSelector)){
6797                     return returnEl ? Roo.get(p) : p;
6798                 }
6799                 depth++;
6800                 p = p.parentNode;
6801             }
6802             return null;
6803         },
6804
6805
6806         /**
6807          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6808          * @param {String} selector The simple selector to test
6809          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6810                 search as a number or element (defaults to 10 || document.body)
6811          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6812          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6813          */
6814         findParentNode : function(simpleSelector, maxDepth, returnEl){
6815             var p = Roo.fly(this.dom.parentNode, '_internal');
6816             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6817         },
6818
6819         /**
6820          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6821          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6822          * @param {String} selector The simple selector to test
6823          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6824                 search as a number or element (defaults to 10 || document.body)
6825          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6826          */
6827         up : function(simpleSelector, maxDepth){
6828             return this.findParentNode(simpleSelector, maxDepth, true);
6829         },
6830
6831
6832
6833         /**
6834          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6835          * @param {String} selector The simple selector to test
6836          * @return {Boolean} True if this element matches the selector, else false
6837          */
6838         is : function(simpleSelector){
6839             return Roo.DomQuery.is(this.dom, simpleSelector);
6840         },
6841
6842         /**
6843          * Perform animation on this element.
6844          * @param {Object} args The YUI animation control args
6845          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6846          * @param {Function} onComplete (optional) Function to call when animation completes
6847          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6848          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6849          * @return {Roo.Element} this
6850          */
6851         animate : function(args, duration, onComplete, easing, animType){
6852             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6853             return this;
6854         },
6855
6856         /*
6857          * @private Internal animation call
6858          */
6859         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6860             animType = animType || 'run';
6861             opt = opt || {};
6862             var anim = Roo.lib.Anim[animType](
6863                 this.dom, args,
6864                 (opt.duration || defaultDur) || .35,
6865                 (opt.easing || defaultEase) || 'easeOut',
6866                 function(){
6867                     Roo.callback(cb, this);
6868                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6869                 },
6870                 this
6871             );
6872             opt.anim = anim;
6873             return anim;
6874         },
6875
6876         // private legacy anim prep
6877         preanim : function(a, i){
6878             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6879         },
6880
6881         /**
6882          * Removes worthless text nodes
6883          * @param {Boolean} forceReclean (optional) By default the element
6884          * keeps track if it has been cleaned already so
6885          * you can call this over and over. However, if you update the element and
6886          * need to force a reclean, you can pass true.
6887          */
6888         clean : function(forceReclean){
6889             if(this.isCleaned && forceReclean !== true){
6890                 return this;
6891             }
6892             var ns = /\S/;
6893             var d = this.dom, n = d.firstChild, ni = -1;
6894             while(n){
6895                 var nx = n.nextSibling;
6896                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6897                     d.removeChild(n);
6898                 }else{
6899                     n.nodeIndex = ++ni;
6900                 }
6901                 n = nx;
6902             }
6903             this.isCleaned = true;
6904             return this;
6905         },
6906
6907         // private
6908         calcOffsetsTo : function(el){
6909             el = Roo.get(el);
6910             var d = el.dom;
6911             var restorePos = false;
6912             if(el.getStyle('position') == 'static'){
6913                 el.position('relative');
6914                 restorePos = true;
6915             }
6916             var x = 0, y =0;
6917             var op = this.dom;
6918             while(op && op != d && op.tagName != 'HTML'){
6919                 x+= op.offsetLeft;
6920                 y+= op.offsetTop;
6921                 op = op.offsetParent;
6922             }
6923             if(restorePos){
6924                 el.position('static');
6925             }
6926             return [x, y];
6927         },
6928
6929         /**
6930          * Scrolls this element into view within the passed container.
6931          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6932          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6933          * @return {Roo.Element} this
6934          */
6935         scrollIntoView : function(container, hscroll){
6936             var c = Roo.getDom(container) || document.body;
6937             var el = this.dom;
6938
6939             var o = this.calcOffsetsTo(c),
6940                 l = o[0],
6941                 t = o[1],
6942                 b = t+el.offsetHeight,
6943                 r = l+el.offsetWidth;
6944
6945             var ch = c.clientHeight;
6946             var ct = parseInt(c.scrollTop, 10);
6947             var cl = parseInt(c.scrollLeft, 10);
6948             var cb = ct + ch;
6949             var cr = cl + c.clientWidth;
6950
6951             if(t < ct){
6952                 c.scrollTop = t;
6953             }else if(b > cb){
6954                 c.scrollTop = b-ch;
6955             }
6956
6957             if(hscroll !== false){
6958                 if(l < cl){
6959                     c.scrollLeft = l;
6960                 }else if(r > cr){
6961                     c.scrollLeft = r-c.clientWidth;
6962                 }
6963             }
6964             return this;
6965         },
6966
6967         // private
6968         scrollChildIntoView : function(child, hscroll){
6969             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6970         },
6971
6972         /**
6973          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6974          * the new height may not be available immediately.
6975          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6976          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6977          * @param {Function} onComplete (optional) Function to call when animation completes
6978          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6979          * @return {Roo.Element} this
6980          */
6981         autoHeight : function(animate, duration, onComplete, easing){
6982             var oldHeight = this.getHeight();
6983             this.clip();
6984             this.setHeight(1); // force clipping
6985             setTimeout(function(){
6986                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6987                 if(!animate){
6988                     this.setHeight(height);
6989                     this.unclip();
6990                     if(typeof onComplete == "function"){
6991                         onComplete();
6992                     }
6993                 }else{
6994                     this.setHeight(oldHeight); // restore original height
6995                     this.setHeight(height, animate, duration, function(){
6996                         this.unclip();
6997                         if(typeof onComplete == "function") onComplete();
6998                     }.createDelegate(this), easing);
6999                 }
7000             }.createDelegate(this), 0);
7001             return this;
7002         },
7003
7004         /**
7005          * Returns true if this element is an ancestor of the passed element
7006          * @param {HTMLElement/String} el The element to check
7007          * @return {Boolean} True if this element is an ancestor of el, else false
7008          */
7009         contains : function(el){
7010             if(!el){return false;}
7011             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7012         },
7013
7014         /**
7015          * Checks whether the element is currently visible using both visibility and display properties.
7016          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7017          * @return {Boolean} True if the element is currently visible, else false
7018          */
7019         isVisible : function(deep) {
7020             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7021             if(deep !== true || !vis){
7022                 return vis;
7023             }
7024             var p = this.dom.parentNode;
7025             while(p && p.tagName.toLowerCase() != "body"){
7026                 if(!Roo.fly(p, '_isVisible').isVisible()){
7027                     return false;
7028                 }
7029                 p = p.parentNode;
7030             }
7031             return true;
7032         },
7033
7034         /**
7035          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7036          * @param {String} selector The CSS selector
7037          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7038          * @return {CompositeElement/CompositeElementLite} The composite element
7039          */
7040         select : function(selector, unique){
7041             return El.select(selector, unique, this.dom);
7042         },
7043
7044         /**
7045          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7046          * @param {String} selector The CSS selector
7047          * @return {Array} An array of the matched nodes
7048          */
7049         query : function(selector, unique){
7050             return Roo.DomQuery.select(selector, this.dom);
7051         },
7052
7053         /**
7054          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7055          * @param {String} selector The CSS selector
7056          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7057          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7058          */
7059         child : function(selector, returnDom){
7060             var n = Roo.DomQuery.selectNode(selector, this.dom);
7061             return returnDom ? n : Roo.get(n);
7062         },
7063
7064         /**
7065          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7066          * @param {String} selector The CSS selector
7067          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7068          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7069          */
7070         down : function(selector, returnDom){
7071             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7072             return returnDom ? n : Roo.get(n);
7073         },
7074
7075         /**
7076          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7077          * @param {String} group The group the DD object is member of
7078          * @param {Object} config The DD config object
7079          * @param {Object} overrides An object containing methods to override/implement on the DD object
7080          * @return {Roo.dd.DD} The DD object
7081          */
7082         initDD : function(group, config, overrides){
7083             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7084             return Roo.apply(dd, overrides);
7085         },
7086
7087         /**
7088          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7089          * @param {String} group The group the DDProxy object is member of
7090          * @param {Object} config The DDProxy config object
7091          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7092          * @return {Roo.dd.DDProxy} The DDProxy object
7093          */
7094         initDDProxy : function(group, config, overrides){
7095             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7096             return Roo.apply(dd, overrides);
7097         },
7098
7099         /**
7100          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7101          * @param {String} group The group the DDTarget object is member of
7102          * @param {Object} config The DDTarget config object
7103          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7104          * @return {Roo.dd.DDTarget} The DDTarget object
7105          */
7106         initDDTarget : function(group, config, overrides){
7107             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7108             return Roo.apply(dd, overrides);
7109         },
7110
7111         /**
7112          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7113          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7114          * @param {Boolean} visible Whether the element is visible
7115          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7116          * @return {Roo.Element} this
7117          */
7118          setVisible : function(visible, animate){
7119             if(!animate || !A){
7120                 if(this.visibilityMode == El.DISPLAY){
7121                     this.setDisplayed(visible);
7122                 }else{
7123                     this.fixDisplay();
7124                     this.dom.style.visibility = visible ? "visible" : "hidden";
7125                 }
7126             }else{
7127                 // closure for composites
7128                 var dom = this.dom;
7129                 var visMode = this.visibilityMode;
7130                 if(visible){
7131                     this.setOpacity(.01);
7132                     this.setVisible(true);
7133                 }
7134                 this.anim({opacity: { to: (visible?1:0) }},
7135                       this.preanim(arguments, 1),
7136                       null, .35, 'easeIn', function(){
7137                          if(!visible){
7138                              if(visMode == El.DISPLAY){
7139                                  dom.style.display = "none";
7140                              }else{
7141                                  dom.style.visibility = "hidden";
7142                              }
7143                              Roo.get(dom).setOpacity(1);
7144                          }
7145                      });
7146             }
7147             return this;
7148         },
7149
7150         /**
7151          * Returns true if display is not "none"
7152          * @return {Boolean}
7153          */
7154         isDisplayed : function() {
7155             return this.getStyle("display") != "none";
7156         },
7157
7158         /**
7159          * Toggles the element's visibility or display, depending on visibility mode.
7160          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7161          * @return {Roo.Element} this
7162          */
7163         toggle : function(animate){
7164             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7165             return this;
7166         },
7167
7168         /**
7169          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7170          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7171          * @return {Roo.Element} this
7172          */
7173         setDisplayed : function(value) {
7174             if(typeof value == "boolean"){
7175                value = value ? this.originalDisplay : "none";
7176             }
7177             this.setStyle("display", value);
7178             return this;
7179         },
7180
7181         /**
7182          * Tries to focus the element. Any exceptions are caught and ignored.
7183          * @return {Roo.Element} this
7184          */
7185         focus : function() {
7186             try{
7187                 this.dom.focus();
7188             }catch(e){}
7189             return this;
7190         },
7191
7192         /**
7193          * Tries to blur the element. Any exceptions are caught and ignored.
7194          * @return {Roo.Element} this
7195          */
7196         blur : function() {
7197             try{
7198                 this.dom.blur();
7199             }catch(e){}
7200             return this;
7201         },
7202
7203         /**
7204          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7205          * @param {String/Array} className The CSS class to add, or an array of classes
7206          * @return {Roo.Element} this
7207          */
7208         addClass : function(className){
7209             if(className instanceof Array){
7210                 for(var i = 0, len = className.length; i < len; i++) {
7211                     this.addClass(className[i]);
7212                 }
7213             }else{
7214                 if(className && !this.hasClass(className)){
7215                     this.dom.className = this.dom.className + " " + className;
7216                 }
7217             }
7218             return this;
7219         },
7220
7221         /**
7222          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7223          * @param {String/Array} className The CSS class to add, or an array of classes
7224          * @return {Roo.Element} this
7225          */
7226         radioClass : function(className){
7227             var siblings = this.dom.parentNode.childNodes;
7228             for(var i = 0; i < siblings.length; i++) {
7229                 var s = siblings[i];
7230                 if(s.nodeType == 1){
7231                     Roo.get(s).removeClass(className);
7232                 }
7233             }
7234             this.addClass(className);
7235             return this;
7236         },
7237
7238         /**
7239          * Removes one or more CSS classes from the element.
7240          * @param {String/Array} className The CSS class to remove, or an array of classes
7241          * @return {Roo.Element} this
7242          */
7243         removeClass : function(className){
7244             if(!className || !this.dom.className){
7245                 return this;
7246             }
7247             if(className instanceof Array){
7248                 for(var i = 0, len = className.length; i < len; i++) {
7249                     this.removeClass(className[i]);
7250                 }
7251             }else{
7252                 if(this.hasClass(className)){
7253                     var re = this.classReCache[className];
7254                     if (!re) {
7255                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7256                        this.classReCache[className] = re;
7257                     }
7258                     this.dom.className =
7259                         this.dom.className.replace(re, " ");
7260                 }
7261             }
7262             return this;
7263         },
7264
7265         // private
7266         classReCache: {},
7267
7268         /**
7269          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7270          * @param {String} className The CSS class to toggle
7271          * @return {Roo.Element} this
7272          */
7273         toggleClass : function(className){
7274             if(this.hasClass(className)){
7275                 this.removeClass(className);
7276             }else{
7277                 this.addClass(className);
7278             }
7279             return this;
7280         },
7281
7282         /**
7283          * Checks if the specified CSS class exists on this element's DOM node.
7284          * @param {String} className The CSS class to check for
7285          * @return {Boolean} True if the class exists, else false
7286          */
7287         hasClass : function(className){
7288             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7289         },
7290
7291         /**
7292          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7293          * @param {String} oldClassName The CSS class to replace
7294          * @param {String} newClassName The replacement CSS class
7295          * @return {Roo.Element} this
7296          */
7297         replaceClass : function(oldClassName, newClassName){
7298             this.removeClass(oldClassName);
7299             this.addClass(newClassName);
7300             return this;
7301         },
7302
7303         /**
7304          * Returns an object with properties matching the styles requested.
7305          * For example, el.getStyles('color', 'font-size', 'width') might return
7306          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7307          * @param {String} style1 A style name
7308          * @param {String} style2 A style name
7309          * @param {String} etc.
7310          * @return {Object} The style object
7311          */
7312         getStyles : function(){
7313             var a = arguments, len = a.length, r = {};
7314             for(var i = 0; i < len; i++){
7315                 r[a[i]] = this.getStyle(a[i]);
7316             }
7317             return r;
7318         },
7319
7320         /**
7321          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7322          * @param {String} property The style property whose value is returned.
7323          * @return {String} The current value of the style property for this element.
7324          */
7325         getStyle : function(){
7326             return view && view.getComputedStyle ?
7327                 function(prop){
7328                     var el = this.dom, v, cs, camel;
7329                     if(prop == 'float'){
7330                         prop = "cssFloat";
7331                     }
7332                     if(el.style && (v = el.style[prop])){
7333                         return v;
7334                     }
7335                     if(cs = view.getComputedStyle(el, "")){
7336                         if(!(camel = propCache[prop])){
7337                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7338                         }
7339                         return cs[camel];
7340                     }
7341                     return null;
7342                 } :
7343                 function(prop){
7344                     var el = this.dom, v, cs, camel;
7345                     if(prop == 'opacity'){
7346                         if(typeof el.style.filter == 'string'){
7347                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7348                             if(m){
7349                                 var fv = parseFloat(m[1]);
7350                                 if(!isNaN(fv)){
7351                                     return fv ? fv / 100 : 0;
7352                                 }
7353                             }
7354                         }
7355                         return 1;
7356                     }else if(prop == 'float'){
7357                         prop = "styleFloat";
7358                     }
7359                     if(!(camel = propCache[prop])){
7360                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7361                     }
7362                     if(v = el.style[camel]){
7363                         return v;
7364                     }
7365                     if(cs = el.currentStyle){
7366                         return cs[camel];
7367                     }
7368                     return null;
7369                 };
7370         }(),
7371
7372         /**
7373          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7374          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7375          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7376          * @return {Roo.Element} this
7377          */
7378         setStyle : function(prop, value){
7379             if(typeof prop == "string"){
7380                 var camel;
7381                 if(!(camel = propCache[prop])){
7382                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7383                 }
7384                 if(camel == 'opacity') {
7385                     this.setOpacity(value);
7386                 }else{
7387                     this.dom.style[camel] = value;
7388                 }
7389             }else{
7390                 for(var style in prop){
7391                     if(typeof prop[style] != "function"){
7392                        this.setStyle(style, prop[style]);
7393                     }
7394                 }
7395             }
7396             return this;
7397         },
7398
7399         /**
7400          * More flexible version of {@link #setStyle} for setting style properties.
7401          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7402          * a function which returns such a specification.
7403          * @return {Roo.Element} this
7404          */
7405         applyStyles : function(style){
7406             Roo.DomHelper.applyStyles(this.dom, style);
7407             return this;
7408         },
7409
7410         /**
7411           * 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).
7412           * @return {Number} The X position of the element
7413           */
7414         getX : function(){
7415             return D.getX(this.dom);
7416         },
7417
7418         /**
7419           * 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).
7420           * @return {Number} The Y position of the element
7421           */
7422         getY : function(){
7423             return D.getY(this.dom);
7424         },
7425
7426         /**
7427           * 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).
7428           * @return {Array} The XY position of the element
7429           */
7430         getXY : function(){
7431             return D.getXY(this.dom);
7432         },
7433
7434         /**
7435          * 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).
7436          * @param {Number} The X position of the element
7437          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7438          * @return {Roo.Element} this
7439          */
7440         setX : function(x, animate){
7441             if(!animate || !A){
7442                 D.setX(this.dom, x);
7443             }else{
7444                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7445             }
7446             return this;
7447         },
7448
7449         /**
7450          * 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).
7451          * @param {Number} The Y position of the element
7452          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7453          * @return {Roo.Element} this
7454          */
7455         setY : function(y, animate){
7456             if(!animate || !A){
7457                 D.setY(this.dom, y);
7458             }else{
7459                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7460             }
7461             return this;
7462         },
7463
7464         /**
7465          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7466          * @param {String} left The left CSS property value
7467          * @return {Roo.Element} this
7468          */
7469         setLeft : function(left){
7470             this.setStyle("left", this.addUnits(left));
7471             return this;
7472         },
7473
7474         /**
7475          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7476          * @param {String} top The top CSS property value
7477          * @return {Roo.Element} this
7478          */
7479         setTop : function(top){
7480             this.setStyle("top", this.addUnits(top));
7481             return this;
7482         },
7483
7484         /**
7485          * Sets the element's CSS right style.
7486          * @param {String} right The right CSS property value
7487          * @return {Roo.Element} this
7488          */
7489         setRight : function(right){
7490             this.setStyle("right", this.addUnits(right));
7491             return this;
7492         },
7493
7494         /**
7495          * Sets the element's CSS bottom style.
7496          * @param {String} bottom The bottom CSS property value
7497          * @return {Roo.Element} this
7498          */
7499         setBottom : function(bottom){
7500             this.setStyle("bottom", this.addUnits(bottom));
7501             return this;
7502         },
7503
7504         /**
7505          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7506          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7507          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7508          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7509          * @return {Roo.Element} this
7510          */
7511         setXY : function(pos, animate){
7512             if(!animate || !A){
7513                 D.setXY(this.dom, pos);
7514             }else{
7515                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7516             }
7517             return this;
7518         },
7519
7520         /**
7521          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7522          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7523          * @param {Number} x X value for new position (coordinates are page-based)
7524          * @param {Number} y Y value for new position (coordinates are page-based)
7525          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7526          * @return {Roo.Element} this
7527          */
7528         setLocation : function(x, y, animate){
7529             this.setXY([x, y], this.preanim(arguments, 2));
7530             return this;
7531         },
7532
7533         /**
7534          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7535          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7536          * @param {Number} x X value for new position (coordinates are page-based)
7537          * @param {Number} y Y value for new position (coordinates are page-based)
7538          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7539          * @return {Roo.Element} this
7540          */
7541         moveTo : function(x, y, animate){
7542             this.setXY([x, y], this.preanim(arguments, 2));
7543             return this;
7544         },
7545
7546         /**
7547          * Returns the region of the given element.
7548          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7549          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7550          */
7551         getRegion : function(){
7552             return D.getRegion(this.dom);
7553         },
7554
7555         /**
7556          * Returns the offset height of the element
7557          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7558          * @return {Number} The element's height
7559          */
7560         getHeight : function(contentHeight){
7561             var h = this.dom.offsetHeight || 0;
7562             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7563         },
7564
7565         /**
7566          * Returns the offset width of the element
7567          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7568          * @return {Number} The element's width
7569          */
7570         getWidth : function(contentWidth){
7571             var w = this.dom.offsetWidth || 0;
7572             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7573         },
7574
7575         /**
7576          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7577          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7578          * if a height has not been set using CSS.
7579          * @return {Number}
7580          */
7581         getComputedHeight : function(){
7582             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7583             if(!h){
7584                 h = parseInt(this.getStyle('height'), 10) || 0;
7585                 if(!this.isBorderBox()){
7586                     h += this.getFrameWidth('tb');
7587                 }
7588             }
7589             return h;
7590         },
7591
7592         /**
7593          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7594          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7595          * if a width has not been set using CSS.
7596          * @return {Number}
7597          */
7598         getComputedWidth : function(){
7599             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7600             if(!w){
7601                 w = parseInt(this.getStyle('width'), 10) || 0;
7602                 if(!this.isBorderBox()){
7603                     w += this.getFrameWidth('lr');
7604                 }
7605             }
7606             return w;
7607         },
7608
7609         /**
7610          * Returns the size of the element.
7611          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7612          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7613          */
7614         getSize : function(contentSize){
7615             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7616         },
7617
7618         /**
7619          * Returns the width and height of the viewport.
7620          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7621          */
7622         getViewSize : function(){
7623             var d = this.dom, doc = document, aw = 0, ah = 0;
7624             if(d == doc || d == doc.body){
7625                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7626             }else{
7627                 return {
7628                     width : d.clientWidth,
7629                     height: d.clientHeight
7630                 };
7631             }
7632         },
7633
7634         /**
7635          * Returns the value of the "value" attribute
7636          * @param {Boolean} asNumber true to parse the value as a number
7637          * @return {String/Number}
7638          */
7639         getValue : function(asNumber){
7640             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7641         },
7642
7643         // private
7644         adjustWidth : function(width){
7645             if(typeof width == "number"){
7646                 if(this.autoBoxAdjust && !this.isBorderBox()){
7647                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7648                 }
7649                 if(width < 0){
7650                     width = 0;
7651                 }
7652             }
7653             return width;
7654         },
7655
7656         // private
7657         adjustHeight : function(height){
7658             if(typeof height == "number"){
7659                if(this.autoBoxAdjust && !this.isBorderBox()){
7660                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7661                }
7662                if(height < 0){
7663                    height = 0;
7664                }
7665             }
7666             return height;
7667         },
7668
7669         /**
7670          * Set the width of the element
7671          * @param {Number} width The new width
7672          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7673          * @return {Roo.Element} this
7674          */
7675         setWidth : function(width, animate){
7676             width = this.adjustWidth(width);
7677             if(!animate || !A){
7678                 this.dom.style.width = this.addUnits(width);
7679             }else{
7680                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7681             }
7682             return this;
7683         },
7684
7685         /**
7686          * Set the height of the element
7687          * @param {Number} height The new height
7688          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7689          * @return {Roo.Element} this
7690          */
7691          setHeight : function(height, animate){
7692             height = this.adjustHeight(height);
7693             if(!animate || !A){
7694                 this.dom.style.height = this.addUnits(height);
7695             }else{
7696                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7697             }
7698             return this;
7699         },
7700
7701         /**
7702          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7703          * @param {Number} width The new width
7704          * @param {Number} height The new height
7705          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7706          * @return {Roo.Element} this
7707          */
7708          setSize : function(width, height, animate){
7709             if(typeof width == "object"){ // in case of object from getSize()
7710                 height = width.height; width = width.width;
7711             }
7712             width = this.adjustWidth(width); height = this.adjustHeight(height);
7713             if(!animate || !A){
7714                 this.dom.style.width = this.addUnits(width);
7715                 this.dom.style.height = this.addUnits(height);
7716             }else{
7717                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7718             }
7719             return this;
7720         },
7721
7722         /**
7723          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7724          * @param {Number} x X value for new position (coordinates are page-based)
7725          * @param {Number} y Y value for new position (coordinates are page-based)
7726          * @param {Number} width The new width
7727          * @param {Number} height The new height
7728          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7729          * @return {Roo.Element} this
7730          */
7731         setBounds : function(x, y, width, height, animate){
7732             if(!animate || !A){
7733                 this.setSize(width, height);
7734                 this.setLocation(x, y);
7735             }else{
7736                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7737                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7738                               this.preanim(arguments, 4), 'motion');
7739             }
7740             return this;
7741         },
7742
7743         /**
7744          * 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.
7745          * @param {Roo.lib.Region} region The region to fill
7746          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7747          * @return {Roo.Element} this
7748          */
7749         setRegion : function(region, animate){
7750             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7751             return this;
7752         },
7753
7754         /**
7755          * Appends an event handler
7756          *
7757          * @param {String}   eventName     The type of event to append
7758          * @param {Function} fn        The method the event invokes
7759          * @param {Object} scope       (optional) The scope (this object) of the fn
7760          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7761          */
7762         addListener : function(eventName, fn, scope, options){
7763             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7764         },
7765
7766         /**
7767          * Removes an event handler from this element
7768          * @param {String} eventName the type of event to remove
7769          * @param {Function} fn the method the event invokes
7770          * @return {Roo.Element} this
7771          */
7772         removeListener : function(eventName, fn){
7773             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7774             return this;
7775         },
7776
7777         /**
7778          * Removes all previous added listeners from this element
7779          * @return {Roo.Element} this
7780          */
7781         removeAllListeners : function(){
7782             E.purgeElement(this.dom);
7783             return this;
7784         },
7785
7786         relayEvent : function(eventName, observable){
7787             this.on(eventName, function(e){
7788                 observable.fireEvent(eventName, e);
7789             });
7790         },
7791
7792         /**
7793          * Set the opacity of the element
7794          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7795          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7796          * @return {Roo.Element} this
7797          */
7798          setOpacity : function(opacity, animate){
7799             if(!animate || !A){
7800                 var s = this.dom.style;
7801                 if(Roo.isIE){
7802                     s.zoom = 1;
7803                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7804                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7805                 }else{
7806                     s.opacity = opacity;
7807                 }
7808             }else{
7809                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7810             }
7811             return this;
7812         },
7813
7814         /**
7815          * Gets the left X coordinate
7816          * @param {Boolean} local True to get the local css position instead of page coordinate
7817          * @return {Number}
7818          */
7819         getLeft : function(local){
7820             if(!local){
7821                 return this.getX();
7822             }else{
7823                 return parseInt(this.getStyle("left"), 10) || 0;
7824             }
7825         },
7826
7827         /**
7828          * Gets the right X coordinate of the element (element X position + element width)
7829          * @param {Boolean} local True to get the local css position instead of page coordinate
7830          * @return {Number}
7831          */
7832         getRight : function(local){
7833             if(!local){
7834                 return this.getX() + this.getWidth();
7835             }else{
7836                 return (this.getLeft(true) + this.getWidth()) || 0;
7837             }
7838         },
7839
7840         /**
7841          * Gets the top Y coordinate
7842          * @param {Boolean} local True to get the local css position instead of page coordinate
7843          * @return {Number}
7844          */
7845         getTop : function(local) {
7846             if(!local){
7847                 return this.getY();
7848             }else{
7849                 return parseInt(this.getStyle("top"), 10) || 0;
7850             }
7851         },
7852
7853         /**
7854          * Gets the bottom Y coordinate of the element (element Y position + element height)
7855          * @param {Boolean} local True to get the local css position instead of page coordinate
7856          * @return {Number}
7857          */
7858         getBottom : function(local){
7859             if(!local){
7860                 return this.getY() + this.getHeight();
7861             }else{
7862                 return (this.getTop(true) + this.getHeight()) || 0;
7863             }
7864         },
7865
7866         /**
7867         * Initializes positioning on this element. If a desired position is not passed, it will make the
7868         * the element positioned relative IF it is not already positioned.
7869         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7870         * @param {Number} zIndex (optional) The zIndex to apply
7871         * @param {Number} x (optional) Set the page X position
7872         * @param {Number} y (optional) Set the page Y position
7873         */
7874         position : function(pos, zIndex, x, y){
7875             if(!pos){
7876                if(this.getStyle('position') == 'static'){
7877                    this.setStyle('position', 'relative');
7878                }
7879             }else{
7880                 this.setStyle("position", pos);
7881             }
7882             if(zIndex){
7883                 this.setStyle("z-index", zIndex);
7884             }
7885             if(x !== undefined && y !== undefined){
7886                 this.setXY([x, y]);
7887             }else if(x !== undefined){
7888                 this.setX(x);
7889             }else if(y !== undefined){
7890                 this.setY(y);
7891             }
7892         },
7893
7894         /**
7895         * Clear positioning back to the default when the document was loaded
7896         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7897         * @return {Roo.Element} this
7898          */
7899         clearPositioning : function(value){
7900             value = value ||'';
7901             this.setStyle({
7902                 "left": value,
7903                 "right": value,
7904                 "top": value,
7905                 "bottom": value,
7906                 "z-index": "",
7907                 "position" : "static"
7908             });
7909             return this;
7910         },
7911
7912         /**
7913         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7914         * snapshot before performing an update and then restoring the element.
7915         * @return {Object}
7916         */
7917         getPositioning : function(){
7918             var l = this.getStyle("left");
7919             var t = this.getStyle("top");
7920             return {
7921                 "position" : this.getStyle("position"),
7922                 "left" : l,
7923                 "right" : l ? "" : this.getStyle("right"),
7924                 "top" : t,
7925                 "bottom" : t ? "" : this.getStyle("bottom"),
7926                 "z-index" : this.getStyle("z-index")
7927             };
7928         },
7929
7930         /**
7931          * Gets the width of the border(s) for the specified side(s)
7932          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7933          * passing lr would get the border (l)eft width + the border (r)ight width.
7934          * @return {Number} The width of the sides passed added together
7935          */
7936         getBorderWidth : function(side){
7937             return this.addStyles(side, El.borders);
7938         },
7939
7940         /**
7941          * Gets the width of the padding(s) for the specified side(s)
7942          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7943          * passing lr would get the padding (l)eft + the padding (r)ight.
7944          * @return {Number} The padding of the sides passed added together
7945          */
7946         getPadding : function(side){
7947             return this.addStyles(side, El.paddings);
7948         },
7949
7950         /**
7951         * Set positioning with an object returned by getPositioning().
7952         * @param {Object} posCfg
7953         * @return {Roo.Element} this
7954          */
7955         setPositioning : function(pc){
7956             this.applyStyles(pc);
7957             if(pc.right == "auto"){
7958                 this.dom.style.right = "";
7959             }
7960             if(pc.bottom == "auto"){
7961                 this.dom.style.bottom = "";
7962             }
7963             return this;
7964         },
7965
7966         // private
7967         fixDisplay : function(){
7968             if(this.getStyle("display") == "none"){
7969                 this.setStyle("visibility", "hidden");
7970                 this.setStyle("display", this.originalDisplay); // first try reverting to default
7971                 if(this.getStyle("display") == "none"){ // if that fails, default to block
7972                     this.setStyle("display", "block");
7973                 }
7974             }
7975         },
7976
7977         /**
7978          * Quick set left and top adding default units
7979          * @param {String} left The left CSS property value
7980          * @param {String} top The top CSS property value
7981          * @return {Roo.Element} this
7982          */
7983          setLeftTop : function(left, top){
7984             this.dom.style.left = this.addUnits(left);
7985             this.dom.style.top = this.addUnits(top);
7986             return this;
7987         },
7988
7989         /**
7990          * Move this element relative to its current position.
7991          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7992          * @param {Number} distance How far to move the element in pixels
7993          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7994          * @return {Roo.Element} this
7995          */
7996          move : function(direction, distance, animate){
7997             var xy = this.getXY();
7998             direction = direction.toLowerCase();
7999             switch(direction){
8000                 case "l":
8001                 case "left":
8002                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8003                     break;
8004                case "r":
8005                case "right":
8006                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8007                     break;
8008                case "t":
8009                case "top":
8010                case "up":
8011                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8012                     break;
8013                case "b":
8014                case "bottom":
8015                case "down":
8016                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8017                     break;
8018             }
8019             return this;
8020         },
8021
8022         /**
8023          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8024          * @return {Roo.Element} this
8025          */
8026         clip : function(){
8027             if(!this.isClipped){
8028                this.isClipped = true;
8029                this.originalClip = {
8030                    "o": this.getStyle("overflow"),
8031                    "x": this.getStyle("overflow-x"),
8032                    "y": this.getStyle("overflow-y")
8033                };
8034                this.setStyle("overflow", "hidden");
8035                this.setStyle("overflow-x", "hidden");
8036                this.setStyle("overflow-y", "hidden");
8037             }
8038             return this;
8039         },
8040
8041         /**
8042          *  Return clipping (overflow) to original clipping before clip() was called
8043          * @return {Roo.Element} this
8044          */
8045         unclip : function(){
8046             if(this.isClipped){
8047                 this.isClipped = false;
8048                 var o = this.originalClip;
8049                 if(o.o){this.setStyle("overflow", o.o);}
8050                 if(o.x){this.setStyle("overflow-x", o.x);}
8051                 if(o.y){this.setStyle("overflow-y", o.y);}
8052             }
8053             return this;
8054         },
8055
8056
8057         /**
8058          * Gets the x,y coordinates specified by the anchor position on the element.
8059          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8060          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8061          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8062          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8063          * @return {Array} [x, y] An array containing the element's x and y coordinates
8064          */
8065         getAnchorXY : function(anchor, local, s){
8066             //Passing a different size is useful for pre-calculating anchors,
8067             //especially for anchored animations that change the el size.
8068
8069             var w, h, vp = false;
8070             if(!s){
8071                 var d = this.dom;
8072                 if(d == document.body || d == document){
8073                     vp = true;
8074                     w = D.getViewWidth(); h = D.getViewHeight();
8075                 }else{
8076                     w = this.getWidth(); h = this.getHeight();
8077                 }
8078             }else{
8079                 w = s.width;  h = s.height;
8080             }
8081             var x = 0, y = 0, r = Math.round;
8082             switch((anchor || "tl").toLowerCase()){
8083                 case "c":
8084                     x = r(w*.5);
8085                     y = r(h*.5);
8086                 break;
8087                 case "t":
8088                     x = r(w*.5);
8089                     y = 0;
8090                 break;
8091                 case "l":
8092                     x = 0;
8093                     y = r(h*.5);
8094                 break;
8095                 case "r":
8096                     x = w;
8097                     y = r(h*.5);
8098                 break;
8099                 case "b":
8100                     x = r(w*.5);
8101                     y = h;
8102                 break;
8103                 case "tl":
8104                     x = 0;
8105                     y = 0;
8106                 break;
8107                 case "bl":
8108                     x = 0;
8109                     y = h;
8110                 break;
8111                 case "br":
8112                     x = w;
8113                     y = h;
8114                 break;
8115                 case "tr":
8116                     x = w;
8117                     y = 0;
8118                 break;
8119             }
8120             if(local === true){
8121                 return [x, y];
8122             }
8123             if(vp){
8124                 var sc = this.getScroll();
8125                 return [x + sc.left, y + sc.top];
8126             }
8127             //Add the element's offset xy
8128             var o = this.getXY();
8129             return [x+o[0], y+o[1]];
8130         },
8131
8132         /**
8133          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8134          * supported position values.
8135          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8136          * @param {String} position The position to align to.
8137          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8138          * @return {Array} [x, y]
8139          */
8140         getAlignToXY : function(el, p, o){
8141             el = Roo.get(el);
8142             var d = this.dom;
8143             if(!el.dom){
8144                 throw "Element.alignTo with an element that doesn't exist";
8145             }
8146             var c = false; //constrain to viewport
8147             var p1 = "", p2 = "";
8148             o = o || [0,0];
8149
8150             if(!p){
8151                 p = "tl-bl";
8152             }else if(p == "?"){
8153                 p = "tl-bl?";
8154             }else if(p.indexOf("-") == -1){
8155                 p = "tl-" + p;
8156             }
8157             p = p.toLowerCase();
8158             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8159             if(!m){
8160                throw "Element.alignTo with an invalid alignment " + p;
8161             }
8162             p1 = m[1]; p2 = m[2]; c = !!m[3];
8163
8164             //Subtract the aligned el's internal xy from the target's offset xy
8165             //plus custom offset to get the aligned el's new offset xy
8166             var a1 = this.getAnchorXY(p1, true);
8167             var a2 = el.getAnchorXY(p2, false);
8168             var x = a2[0] - a1[0] + o[0];
8169             var y = a2[1] - a1[1] + o[1];
8170             if(c){
8171                 //constrain the aligned el to viewport if necessary
8172                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8173                 // 5px of margin for ie
8174                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8175
8176                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8177                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8178                 //otherwise swap the aligned el to the opposite border of the target.
8179                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8180                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8181                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8182                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8183
8184                var doc = document;
8185                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8186                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8187
8188                if((x+w) > dw + scrollX){
8189                     x = swapX ? r.left-w : dw+scrollX-w;
8190                 }
8191                if(x < scrollX){
8192                    x = swapX ? r.right : scrollX;
8193                }
8194                if((y+h) > dh + scrollY){
8195                     y = swapY ? r.top-h : dh+scrollY-h;
8196                 }
8197                if (y < scrollY){
8198                    y = swapY ? r.bottom : scrollY;
8199                }
8200             }
8201             return [x,y];
8202         },
8203
8204         // private
8205         getConstrainToXY : function(){
8206             var os = {top:0, left:0, bottom:0, right: 0};
8207
8208             return function(el, local, offsets, proposedXY){
8209                 el = Roo.get(el);
8210                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8211
8212                 var vw, vh, vx = 0, vy = 0;
8213                 if(el.dom == document.body || el.dom == document){
8214                     vw = Roo.lib.Dom.getViewWidth();
8215                     vh = Roo.lib.Dom.getViewHeight();
8216                 }else{
8217                     vw = el.dom.clientWidth;
8218                     vh = el.dom.clientHeight;
8219                     if(!local){
8220                         var vxy = el.getXY();
8221                         vx = vxy[0];
8222                         vy = vxy[1];
8223                     }
8224                 }
8225
8226                 var s = el.getScroll();
8227
8228                 vx += offsets.left + s.left;
8229                 vy += offsets.top + s.top;
8230
8231                 vw -= offsets.right;
8232                 vh -= offsets.bottom;
8233
8234                 var vr = vx+vw;
8235                 var vb = vy+vh;
8236
8237                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8238                 var x = xy[0], y = xy[1];
8239                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8240
8241                 // only move it if it needs it
8242                 var moved = false;
8243
8244                 // first validate right/bottom
8245                 if((x + w) > vr){
8246                     x = vr - w;
8247                     moved = true;
8248                 }
8249                 if((y + h) > vb){
8250                     y = vb - h;
8251                     moved = true;
8252                 }
8253                 // then make sure top/left isn't negative
8254                 if(x < vx){
8255                     x = vx;
8256                     moved = true;
8257                 }
8258                 if(y < vy){
8259                     y = vy;
8260                     moved = true;
8261                 }
8262                 return moved ? [x, y] : false;
8263             };
8264         }(),
8265
8266         // private
8267         adjustForConstraints : function(xy, parent, offsets){
8268             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8269         },
8270
8271         /**
8272          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8273          * document it aligns it to the viewport.
8274          * The position parameter is optional, and can be specified in any one of the following formats:
8275          * <ul>
8276          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8277          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8278          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8279          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8280          *   <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
8281          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8282          * </ul>
8283          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8284          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8285          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8286          * that specified in order to enforce the viewport constraints.
8287          * Following are all of the supported anchor positions:
8288     <pre>
8289     Value  Description
8290     -----  -----------------------------
8291     tl     The top left corner (default)
8292     t      The center of the top edge
8293     tr     The top right corner
8294     l      The center of the left edge
8295     c      In the center of the element
8296     r      The center of the right edge
8297     bl     The bottom left corner
8298     b      The center of the bottom edge
8299     br     The bottom right corner
8300     </pre>
8301     Example Usage:
8302     <pre><code>
8303     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8304     el.alignTo("other-el");
8305
8306     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8307     el.alignTo("other-el", "tr?");
8308
8309     // align the bottom right corner of el with the center left edge of other-el
8310     el.alignTo("other-el", "br-l?");
8311
8312     // align the center of el with the bottom left corner of other-el and
8313     // adjust the x position by -6 pixels (and the y position by 0)
8314     el.alignTo("other-el", "c-bl", [-6, 0]);
8315     </code></pre>
8316          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8317          * @param {String} position The position to align to.
8318          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8319          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8320          * @return {Roo.Element} this
8321          */
8322         alignTo : function(element, position, offsets, animate){
8323             var xy = this.getAlignToXY(element, position, offsets);
8324             this.setXY(xy, this.preanim(arguments, 3));
8325             return this;
8326         },
8327
8328         /**
8329          * Anchors an element to another element and realigns it when the window is resized.
8330          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8331          * @param {String} position The position to align to.
8332          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8333          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8334          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8335          * is a number, it is used as the buffer delay (defaults to 50ms).
8336          * @param {Function} callback The function to call after the animation finishes
8337          * @return {Roo.Element} this
8338          */
8339         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8340             var action = function(){
8341                 this.alignTo(el, alignment, offsets, animate);
8342                 Roo.callback(callback, this);
8343             };
8344             Roo.EventManager.onWindowResize(action, this);
8345             var tm = typeof monitorScroll;
8346             if(tm != 'undefined'){
8347                 Roo.EventManager.on(window, 'scroll', action, this,
8348                     {buffer: tm == 'number' ? monitorScroll : 50});
8349             }
8350             action.call(this); // align immediately
8351             return this;
8352         },
8353         /**
8354          * Clears any opacity settings from this element. Required in some cases for IE.
8355          * @return {Roo.Element} this
8356          */
8357         clearOpacity : function(){
8358             if (window.ActiveXObject) {
8359                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8360                     this.dom.style.filter = "";
8361                 }
8362             } else {
8363                 this.dom.style.opacity = "";
8364                 this.dom.style["-moz-opacity"] = "";
8365                 this.dom.style["-khtml-opacity"] = "";
8366             }
8367             return this;
8368         },
8369
8370         /**
8371          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8372          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8373          * @return {Roo.Element} this
8374          */
8375         hide : function(animate){
8376             this.setVisible(false, this.preanim(arguments, 0));
8377             return this;
8378         },
8379
8380         /**
8381         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8382         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8383          * @return {Roo.Element} this
8384          */
8385         show : function(animate){
8386             this.setVisible(true, this.preanim(arguments, 0));
8387             return this;
8388         },
8389
8390         /**
8391          * @private Test if size has a unit, otherwise appends the default
8392          */
8393         addUnits : function(size){
8394             return Roo.Element.addUnits(size, this.defaultUnit);
8395         },
8396
8397         /**
8398          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8399          * @return {Roo.Element} this
8400          */
8401         beginMeasure : function(){
8402             var el = this.dom;
8403             if(el.offsetWidth || el.offsetHeight){
8404                 return this; // offsets work already
8405             }
8406             var changed = [];
8407             var p = this.dom, b = document.body; // start with this element
8408             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8409                 var pe = Roo.get(p);
8410                 if(pe.getStyle('display') == 'none'){
8411                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8412                     p.style.visibility = "hidden";
8413                     p.style.display = "block";
8414                 }
8415                 p = p.parentNode;
8416             }
8417             this._measureChanged = changed;
8418             return this;
8419
8420         },
8421
8422         /**
8423          * Restores displays to before beginMeasure was called
8424          * @return {Roo.Element} this
8425          */
8426         endMeasure : function(){
8427             var changed = this._measureChanged;
8428             if(changed){
8429                 for(var i = 0, len = changed.length; i < len; i++) {
8430                     var r = changed[i];
8431                     r.el.style.visibility = r.visibility;
8432                     r.el.style.display = "none";
8433                 }
8434                 this._measureChanged = null;
8435             }
8436             return this;
8437         },
8438
8439         /**
8440         * Update the innerHTML of this element, optionally searching for and processing scripts
8441         * @param {String} html The new HTML
8442         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8443         * @param {Function} callback For async script loading you can be noticed when the update completes
8444         * @return {Roo.Element} this
8445          */
8446         update : function(html, loadScripts, callback){
8447             if(typeof html == "undefined"){
8448                 html = "";
8449             }
8450             if(loadScripts !== true){
8451                 this.dom.innerHTML = html;
8452                 if(typeof callback == "function"){
8453                     callback();
8454                 }
8455                 return this;
8456             }
8457             var id = Roo.id();
8458             var dom = this.dom;
8459
8460             html += '<span id="' + id + '"></span>';
8461
8462             E.onAvailable(id, function(){
8463                 var hd = document.getElementsByTagName("head")[0];
8464                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8465                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8466                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8467
8468                 var match;
8469                 while(match = re.exec(html)){
8470                     var attrs = match[1];
8471                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8472                     if(srcMatch && srcMatch[2]){
8473                        var s = document.createElement("script");
8474                        s.src = srcMatch[2];
8475                        var typeMatch = attrs.match(typeRe);
8476                        if(typeMatch && typeMatch[2]){
8477                            s.type = typeMatch[2];
8478                        }
8479                        hd.appendChild(s);
8480                     }else if(match[2] && match[2].length > 0){
8481                         if(window.execScript) {
8482                            window.execScript(match[2]);
8483                         } else {
8484                             /**
8485                              * eval:var:id
8486                              * eval:var:dom
8487                              * eval:var:html
8488                              * 
8489                              */
8490                            window.eval(match[2]);
8491                         }
8492                     }
8493                 }
8494                 var el = document.getElementById(id);
8495                 if(el){el.parentNode.removeChild(el);}
8496                 if(typeof callback == "function"){
8497                     callback();
8498                 }
8499             });
8500             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8501             return this;
8502         },
8503
8504         /**
8505          * Direct access to the UpdateManager update() method (takes the same parameters).
8506          * @param {String/Function} url The url for this request or a function to call to get the url
8507          * @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}
8508          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8509          * @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.
8510          * @return {Roo.Element} this
8511          */
8512         load : function(){
8513             var um = this.getUpdateManager();
8514             um.update.apply(um, arguments);
8515             return this;
8516         },
8517
8518         /**
8519         * Gets this element's UpdateManager
8520         * @return {Roo.UpdateManager} The UpdateManager
8521         */
8522         getUpdateManager : function(){
8523             if(!this.updateManager){
8524                 this.updateManager = new Roo.UpdateManager(this);
8525             }
8526             return this.updateManager;
8527         },
8528
8529         /**
8530          * Disables text selection for this element (normalized across browsers)
8531          * @return {Roo.Element} this
8532          */
8533         unselectable : function(){
8534             this.dom.unselectable = "on";
8535             this.swallowEvent("selectstart", true);
8536             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8537             this.addClass("x-unselectable");
8538             return this;
8539         },
8540
8541         /**
8542         * Calculates the x, y to center this element on the screen
8543         * @return {Array} The x, y values [x, y]
8544         */
8545         getCenterXY : function(){
8546             return this.getAlignToXY(document, 'c-c');
8547         },
8548
8549         /**
8550         * Centers the Element in either the viewport, or another Element.
8551         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8552         */
8553         center : function(centerIn){
8554             this.alignTo(centerIn || document, 'c-c');
8555             return this;
8556         },
8557
8558         /**
8559          * Tests various css rules/browsers to determine if this element uses a border box
8560          * @return {Boolean}
8561          */
8562         isBorderBox : function(){
8563             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8564         },
8565
8566         /**
8567          * Return a box {x, y, width, height} that can be used to set another elements
8568          * size/location to match this element.
8569          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8570          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8571          * @return {Object} box An object in the format {x, y, width, height}
8572          */
8573         getBox : function(contentBox, local){
8574             var xy;
8575             if(!local){
8576                 xy = this.getXY();
8577             }else{
8578                 var left = parseInt(this.getStyle("left"), 10) || 0;
8579                 var top = parseInt(this.getStyle("top"), 10) || 0;
8580                 xy = [left, top];
8581             }
8582             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8583             if(!contentBox){
8584                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8585             }else{
8586                 var l = this.getBorderWidth("l")+this.getPadding("l");
8587                 var r = this.getBorderWidth("r")+this.getPadding("r");
8588                 var t = this.getBorderWidth("t")+this.getPadding("t");
8589                 var b = this.getBorderWidth("b")+this.getPadding("b");
8590                 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)};
8591             }
8592             bx.right = bx.x + bx.width;
8593             bx.bottom = bx.y + bx.height;
8594             return bx;
8595         },
8596
8597         /**
8598          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8599          for more information about the sides.
8600          * @param {String} sides
8601          * @return {Number}
8602          */
8603         getFrameWidth : function(sides, onlyContentBox){
8604             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8605         },
8606
8607         /**
8608          * 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.
8609          * @param {Object} box The box to fill {x, y, width, height}
8610          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8611          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8612          * @return {Roo.Element} this
8613          */
8614         setBox : function(box, adjust, animate){
8615             var w = box.width, h = box.height;
8616             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8617                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8618                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8619             }
8620             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8621             return this;
8622         },
8623
8624         /**
8625          * Forces the browser to repaint this element
8626          * @return {Roo.Element} this
8627          */
8628          repaint : function(){
8629             var dom = this.dom;
8630             this.addClass("x-repaint");
8631             setTimeout(function(){
8632                 Roo.get(dom).removeClass("x-repaint");
8633             }, 1);
8634             return this;
8635         },
8636
8637         /**
8638          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8639          * then it returns the calculated width of the sides (see getPadding)
8640          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8641          * @return {Object/Number}
8642          */
8643         getMargins : function(side){
8644             if(!side){
8645                 return {
8646                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8647                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8648                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8649                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8650                 };
8651             }else{
8652                 return this.addStyles(side, El.margins);
8653              }
8654         },
8655
8656         // private
8657         addStyles : function(sides, styles){
8658             var val = 0, v, w;
8659             for(var i = 0, len = sides.length; i < len; i++){
8660                 v = this.getStyle(styles[sides.charAt(i)]);
8661                 if(v){
8662                      w = parseInt(v, 10);
8663                      if(w){ val += w; }
8664                 }
8665             }
8666             return val;
8667         },
8668
8669         /**
8670          * Creates a proxy element of this element
8671          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8672          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8673          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8674          * @return {Roo.Element} The new proxy element
8675          */
8676         createProxy : function(config, renderTo, matchBox){
8677             if(renderTo){
8678                 renderTo = Roo.getDom(renderTo);
8679             }else{
8680                 renderTo = document.body;
8681             }
8682             config = typeof config == "object" ?
8683                 config : {tag : "div", cls: config};
8684             var proxy = Roo.DomHelper.append(renderTo, config, true);
8685             if(matchBox){
8686                proxy.setBox(this.getBox());
8687             }
8688             return proxy;
8689         },
8690
8691         /**
8692          * Puts a mask over this element to disable user interaction. Requires core.css.
8693          * This method can only be applied to elements which accept child nodes.
8694          * @param {String} msg (optional) A message to display in the mask
8695          * @param {String} msgCls (optional) A css class to apply to the msg element
8696          * @return {Element} The mask  element
8697          */
8698         mask : function(msg, msgCls){
8699             if(this.getStyle("position") == "static"){
8700                 this.setStyle("position", "relative");
8701             }
8702             if(!this._mask){
8703                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8704             }
8705             this.addClass("x-masked");
8706             this._mask.setDisplayed(true);
8707             if(typeof msg == 'string'){
8708                 if(!this._maskMsg){
8709                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8710                 }
8711                 var mm = this._maskMsg;
8712                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8713                 mm.dom.firstChild.innerHTML = msg;
8714                 mm.setDisplayed(true);
8715                 mm.center(this);
8716             }
8717             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8718                 this._mask.setHeight(this.getHeight());
8719             }
8720             return this._mask;
8721         },
8722
8723         /**
8724          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8725          * it is cached for reuse.
8726          */
8727         unmask : function(removeEl){
8728             if(this._mask){
8729                 if(removeEl === true){
8730                     this._mask.remove();
8731                     delete this._mask;
8732                     if(this._maskMsg){
8733                         this._maskMsg.remove();
8734                         delete this._maskMsg;
8735                     }
8736                 }else{
8737                     this._mask.setDisplayed(false);
8738                     if(this._maskMsg){
8739                         this._maskMsg.setDisplayed(false);
8740                     }
8741                 }
8742             }
8743             this.removeClass("x-masked");
8744         },
8745
8746         /**
8747          * Returns true if this element is masked
8748          * @return {Boolean}
8749          */
8750         isMasked : function(){
8751             return this._mask && this._mask.isVisible();
8752         },
8753
8754         /**
8755          * Creates an iframe shim for this element to keep selects and other windowed objects from
8756          * showing through.
8757          * @return {Roo.Element} The new shim element
8758          */
8759         createShim : function(){
8760             var el = document.createElement('iframe');
8761             el.frameBorder = 'no';
8762             el.className = 'roo-shim';
8763             if(Roo.isIE && Roo.isSecure){
8764                 el.src = Roo.SSL_SECURE_URL;
8765             }
8766             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8767             shim.autoBoxAdjust = false;
8768             return shim;
8769         },
8770
8771         /**
8772          * Removes this element from the DOM and deletes it from the cache
8773          */
8774         remove : function(){
8775             if(this.dom.parentNode){
8776                 this.dom.parentNode.removeChild(this.dom);
8777             }
8778             delete El.cache[this.dom.id];
8779         },
8780
8781         /**
8782          * Sets up event handlers to add and remove a css class when the mouse is over this element
8783          * @param {String} className
8784          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8785          * mouseout events for children elements
8786          * @return {Roo.Element} this
8787          */
8788         addClassOnOver : function(className, preventFlicker){
8789             this.on("mouseover", function(){
8790                 Roo.fly(this, '_internal').addClass(className);
8791             }, this.dom);
8792             var removeFn = function(e){
8793                 if(preventFlicker !== true || !e.within(this, true)){
8794                     Roo.fly(this, '_internal').removeClass(className);
8795                 }
8796             };
8797             this.on("mouseout", removeFn, this.dom);
8798             return this;
8799         },
8800
8801         /**
8802          * Sets up event handlers to add and remove a css class when this element has the focus
8803          * @param {String} className
8804          * @return {Roo.Element} this
8805          */
8806         addClassOnFocus : function(className){
8807             this.on("focus", function(){
8808                 Roo.fly(this, '_internal').addClass(className);
8809             }, this.dom);
8810             this.on("blur", function(){
8811                 Roo.fly(this, '_internal').removeClass(className);
8812             }, this.dom);
8813             return this;
8814         },
8815         /**
8816          * 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)
8817          * @param {String} className
8818          * @return {Roo.Element} this
8819          */
8820         addClassOnClick : function(className){
8821             var dom = this.dom;
8822             this.on("mousedown", function(){
8823                 Roo.fly(dom, '_internal').addClass(className);
8824                 var d = Roo.get(document);
8825                 var fn = function(){
8826                     Roo.fly(dom, '_internal').removeClass(className);
8827                     d.removeListener("mouseup", fn);
8828                 };
8829                 d.on("mouseup", fn);
8830             });
8831             return this;
8832         },
8833
8834         /**
8835          * Stops the specified event from bubbling and optionally prevents the default action
8836          * @param {String} eventName
8837          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8838          * @return {Roo.Element} this
8839          */
8840         swallowEvent : function(eventName, preventDefault){
8841             var fn = function(e){
8842                 e.stopPropagation();
8843                 if(preventDefault){
8844                     e.preventDefault();
8845                 }
8846             };
8847             if(eventName instanceof Array){
8848                 for(var i = 0, len = eventName.length; i < len; i++){
8849                      this.on(eventName[i], fn);
8850                 }
8851                 return this;
8852             }
8853             this.on(eventName, fn);
8854             return this;
8855         },
8856
8857         /**
8858          * @private
8859          */
8860       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8861
8862         /**
8863          * Sizes this element to its parent element's dimensions performing
8864          * neccessary box adjustments.
8865          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8866          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8867          * @return {Roo.Element} this
8868          */
8869         fitToParent : function(monitorResize, targetParent) {
8870           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8871           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8872           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8873             return;
8874           }
8875           var p = Roo.get(targetParent || this.dom.parentNode);
8876           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8877           if (monitorResize === true) {
8878             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8879             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8880           }
8881           return this;
8882         },
8883
8884         /**
8885          * Gets the next sibling, skipping text nodes
8886          * @return {HTMLElement} The next sibling or null
8887          */
8888         getNextSibling : function(){
8889             var n = this.dom.nextSibling;
8890             while(n && n.nodeType != 1){
8891                 n = n.nextSibling;
8892             }
8893             return n;
8894         },
8895
8896         /**
8897          * Gets the previous sibling, skipping text nodes
8898          * @return {HTMLElement} The previous sibling or null
8899          */
8900         getPrevSibling : function(){
8901             var n = this.dom.previousSibling;
8902             while(n && n.nodeType != 1){
8903                 n = n.previousSibling;
8904             }
8905             return n;
8906         },
8907
8908
8909         /**
8910          * Appends the passed element(s) to this element
8911          * @param {String/HTMLElement/Array/Element/CompositeElement} el
8912          * @return {Roo.Element} this
8913          */
8914         appendChild: function(el){
8915             el = Roo.get(el);
8916             el.appendTo(this);
8917             return this;
8918         },
8919
8920         /**
8921          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8922          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
8923          * automatically generated with the specified attributes.
8924          * @param {HTMLElement} insertBefore (optional) a child element of this element
8925          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8926          * @return {Roo.Element} The new child element
8927          */
8928         createChild: function(config, insertBefore, returnDom){
8929             config = config || {tag:'div'};
8930             if(insertBefore){
8931                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8932             }
8933             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
8934         },
8935
8936         /**
8937          * Appends this element to the passed element
8938          * @param {String/HTMLElement/Element} el The new parent element
8939          * @return {Roo.Element} this
8940          */
8941         appendTo: function(el){
8942             el = Roo.getDom(el);
8943             el.appendChild(this.dom);
8944             return this;
8945         },
8946
8947         /**
8948          * Inserts this element before the passed element in the DOM
8949          * @param {String/HTMLElement/Element} el The element to insert before
8950          * @return {Roo.Element} this
8951          */
8952         insertBefore: function(el){
8953             el = Roo.getDom(el);
8954             el.parentNode.insertBefore(this.dom, el);
8955             return this;
8956         },
8957
8958         /**
8959          * Inserts this element after the passed element in the DOM
8960          * @param {String/HTMLElement/Element} el The element to insert after
8961          * @return {Roo.Element} this
8962          */
8963         insertAfter: function(el){
8964             el = Roo.getDom(el);
8965             el.parentNode.insertBefore(this.dom, el.nextSibling);
8966             return this;
8967         },
8968
8969         /**
8970          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8971          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8972          * @return {Roo.Element} The new child
8973          */
8974         insertFirst: function(el, returnDom){
8975             el = el || {};
8976             if(typeof el == 'object' && !el.nodeType){ // dh config
8977                 return this.createChild(el, this.dom.firstChild, returnDom);
8978             }else{
8979                 el = Roo.getDom(el);
8980                 this.dom.insertBefore(el, this.dom.firstChild);
8981                 return !returnDom ? Roo.get(el) : el;
8982             }
8983         },
8984
8985         /**
8986          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8987          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8988          * @param {String} where (optional) 'before' or 'after' defaults to before
8989          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8990          * @return {Roo.Element} the inserted Element
8991          */
8992         insertSibling: function(el, where, returnDom){
8993             where = where ? where.toLowerCase() : 'before';
8994             el = el || {};
8995             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8996
8997             if(typeof el == 'object' && !el.nodeType){ // dh config
8998                 if(where == 'after' && !this.dom.nextSibling){
8999                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9000                 }else{
9001                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9002                 }
9003
9004             }else{
9005                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9006                             where == 'before' ? this.dom : this.dom.nextSibling);
9007                 if(!returnDom){
9008                     rt = Roo.get(rt);
9009                 }
9010             }
9011             return rt;
9012         },
9013
9014         /**
9015          * Creates and wraps this element with another element
9016          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9017          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9018          * @return {HTMLElement/Element} The newly created wrapper element
9019          */
9020         wrap: function(config, returnDom){
9021             if(!config){
9022                 config = {tag: "div"};
9023             }
9024             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9025             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9026             return newEl;
9027         },
9028
9029         /**
9030          * Replaces the passed element with this element
9031          * @param {String/HTMLElement/Element} el The element to replace
9032          * @return {Roo.Element} this
9033          */
9034         replace: function(el){
9035             el = Roo.get(el);
9036             this.insertBefore(el);
9037             el.remove();
9038             return this;
9039         },
9040
9041         /**
9042          * Inserts an html fragment into this element
9043          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9044          * @param {String} html The HTML fragment
9045          * @param {Boolean} returnEl True to return an Roo.Element
9046          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9047          */
9048         insertHtml : function(where, html, returnEl){
9049             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9050             return returnEl ? Roo.get(el) : el;
9051         },
9052
9053         /**
9054          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9055          * @param {Object} o The object with the attributes
9056          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9057          * @return {Roo.Element} this
9058          */
9059         set : function(o, useSet){
9060             var el = this.dom;
9061             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9062             for(var attr in o){
9063                 if(attr == "style" || typeof o[attr] == "function") continue;
9064                 if(attr=="cls"){
9065                     el.className = o["cls"];
9066                 }else{
9067                     if(useSet) el.setAttribute(attr, o[attr]);
9068                     else el[attr] = o[attr];
9069                 }
9070             }
9071             if(o.style){
9072                 Roo.DomHelper.applyStyles(el, o.style);
9073             }
9074             return this;
9075         },
9076
9077         /**
9078          * Convenience method for constructing a KeyMap
9079          * @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:
9080          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9081          * @param {Function} fn The function to call
9082          * @param {Object} scope (optional) The scope of the function
9083          * @return {Roo.KeyMap} The KeyMap created
9084          */
9085         addKeyListener : function(key, fn, scope){
9086             var config;
9087             if(typeof key != "object" || key instanceof Array){
9088                 config = {
9089                     key: key,
9090                     fn: fn,
9091                     scope: scope
9092                 };
9093             }else{
9094                 config = {
9095                     key : key.key,
9096                     shift : key.shift,
9097                     ctrl : key.ctrl,
9098                     alt : key.alt,
9099                     fn: fn,
9100                     scope: scope
9101                 };
9102             }
9103             return new Roo.KeyMap(this, config);
9104         },
9105
9106         /**
9107          * Creates a KeyMap for this element
9108          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9109          * @return {Roo.KeyMap} The KeyMap created
9110          */
9111         addKeyMap : function(config){
9112             return new Roo.KeyMap(this, config);
9113         },
9114
9115         /**
9116          * Returns true if this element is scrollable.
9117          * @return {Boolean}
9118          */
9119          isScrollable : function(){
9120             var dom = this.dom;
9121             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9122         },
9123
9124         /**
9125          * 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().
9126          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9127          * @param {Number} value The new scroll value
9128          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9129          * @return {Element} this
9130          */
9131
9132         scrollTo : function(side, value, animate){
9133             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9134             if(!animate || !A){
9135                 this.dom[prop] = value;
9136             }else{
9137                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9138                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9139             }
9140             return this;
9141         },
9142
9143         /**
9144          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9145          * within this element's scrollable range.
9146          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9147          * @param {Number} distance How far to scroll the element in pixels
9148          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9149          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9150          * was scrolled as far as it could go.
9151          */
9152          scroll : function(direction, distance, animate){
9153              if(!this.isScrollable()){
9154                  return;
9155              }
9156              var el = this.dom;
9157              var l = el.scrollLeft, t = el.scrollTop;
9158              var w = el.scrollWidth, h = el.scrollHeight;
9159              var cw = el.clientWidth, ch = el.clientHeight;
9160              direction = direction.toLowerCase();
9161              var scrolled = false;
9162              var a = this.preanim(arguments, 2);
9163              switch(direction){
9164                  case "l":
9165                  case "left":
9166                      if(w - l > cw){
9167                          var v = Math.min(l + distance, w-cw);
9168                          this.scrollTo("left", v, a);
9169                          scrolled = true;
9170                      }
9171                      break;
9172                 case "r":
9173                 case "right":
9174                      if(l > 0){
9175                          var v = Math.max(l - distance, 0);
9176                          this.scrollTo("left", v, a);
9177                          scrolled = true;
9178                      }
9179                      break;
9180                 case "t":
9181                 case "top":
9182                 case "up":
9183                      if(t > 0){
9184                          var v = Math.max(t - distance, 0);
9185                          this.scrollTo("top", v, a);
9186                          scrolled = true;
9187                      }
9188                      break;
9189                 case "b":
9190                 case "bottom":
9191                 case "down":
9192                      if(h - t > ch){
9193                          var v = Math.min(t + distance, h-ch);
9194                          this.scrollTo("top", v, a);
9195                          scrolled = true;
9196                      }
9197                      break;
9198              }
9199              return scrolled;
9200         },
9201
9202         /**
9203          * Translates the passed page coordinates into left/top css values for this element
9204          * @param {Number/Array} x The page x or an array containing [x, y]
9205          * @param {Number} y The page y
9206          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9207          */
9208         translatePoints : function(x, y){
9209             if(typeof x == 'object' || x instanceof Array){
9210                 y = x[1]; x = x[0];
9211             }
9212             var p = this.getStyle('position');
9213             var o = this.getXY();
9214
9215             var l = parseInt(this.getStyle('left'), 10);
9216             var t = parseInt(this.getStyle('top'), 10);
9217
9218             if(isNaN(l)){
9219                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9220             }
9221             if(isNaN(t)){
9222                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9223             }
9224
9225             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9226         },
9227
9228         /**
9229          * Returns the current scroll position of the element.
9230          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9231          */
9232         getScroll : function(){
9233             var d = this.dom, doc = document;
9234             if(d == doc || d == doc.body){
9235                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9236                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9237                 return {left: l, top: t};
9238             }else{
9239                 return {left: d.scrollLeft, top: d.scrollTop};
9240             }
9241         },
9242
9243         /**
9244          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9245          * are convert to standard 6 digit hex color.
9246          * @param {String} attr The css attribute
9247          * @param {String} defaultValue The default value to use when a valid color isn't found
9248          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9249          * YUI color anims.
9250          */
9251         getColor : function(attr, defaultValue, prefix){
9252             var v = this.getStyle(attr);
9253             if(!v || v == "transparent" || v == "inherit") {
9254                 return defaultValue;
9255             }
9256             var color = typeof prefix == "undefined" ? "#" : prefix;
9257             if(v.substr(0, 4) == "rgb("){
9258                 var rvs = v.slice(4, v.length -1).split(",");
9259                 for(var i = 0; i < 3; i++){
9260                     var h = parseInt(rvs[i]).toString(16);
9261                     if(h < 16){
9262                         h = "0" + h;
9263                     }
9264                     color += h;
9265                 }
9266             } else {
9267                 if(v.substr(0, 1) == "#"){
9268                     if(v.length == 4) {
9269                         for(var i = 1; i < 4; i++){
9270                             var c = v.charAt(i);
9271                             color +=  c + c;
9272                         }
9273                     }else if(v.length == 7){
9274                         color += v.substr(1);
9275                     }
9276                 }
9277             }
9278             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9279         },
9280
9281         /**
9282          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9283          * gradient background, rounded corners and a 4-way shadow.
9284          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9285          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9286          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9287          * @return {Roo.Element} this
9288          */
9289         boxWrap : function(cls){
9290             cls = cls || 'x-box';
9291             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9292             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9293             return el;
9294         },
9295
9296         /**
9297          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9298          * @param {String} namespace The namespace in which to look for the attribute
9299          * @param {String} name The attribute name
9300          * @return {String} The attribute value
9301          */
9302         getAttributeNS : Roo.isIE ? function(ns, name){
9303             var d = this.dom;
9304             var type = typeof d[ns+":"+name];
9305             if(type != 'undefined' && type != 'unknown'){
9306                 return d[ns+":"+name];
9307             }
9308             return d[name];
9309         } : function(ns, name){
9310             var d = this.dom;
9311             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9312         }
9313     };
9314
9315     var ep = El.prototype;
9316
9317     /**
9318      * Appends an event handler (Shorthand for addListener)
9319      * @param {String}   eventName     The type of event to append
9320      * @param {Function} fn        The method the event invokes
9321      * @param {Object} scope       (optional) The scope (this object) of the fn
9322      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9323      * @method
9324      */
9325     ep.on = ep.addListener;
9326         // backwards compat
9327     ep.mon = ep.addListener;
9328
9329     /**
9330      * Removes an event handler from this element (shorthand for removeListener)
9331      * @param {String} eventName the type of event to remove
9332      * @param {Function} fn the method the event invokes
9333      * @return {Roo.Element} this
9334      * @method
9335      */
9336     ep.un = ep.removeListener;
9337
9338     /**
9339      * true to automatically adjust width and height settings for box-model issues (default to true)
9340      */
9341     ep.autoBoxAdjust = true;
9342
9343     // private
9344     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9345
9346     // private
9347     El.addUnits = function(v, defaultUnit){
9348         if(v === "" || v == "auto"){
9349             return v;
9350         }
9351         if(v === undefined){
9352             return '';
9353         }
9354         if(typeof v == "number" || !El.unitPattern.test(v)){
9355             return v + (defaultUnit || 'px');
9356         }
9357         return v;
9358     };
9359
9360     // special markup used throughout Roo when box wrapping elements
9361     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>';
9362     /**
9363      * Visibility mode constant - Use visibility to hide element
9364      * @static
9365      * @type Number
9366      */
9367     El.VISIBILITY = 1;
9368     /**
9369      * Visibility mode constant - Use display to hide element
9370      * @static
9371      * @type Number
9372      */
9373     El.DISPLAY = 2;
9374
9375     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9376     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9377     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9378
9379
9380
9381     /**
9382      * @private
9383      */
9384     El.cache = {};
9385
9386     var docEl;
9387
9388     /**
9389      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9390      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9391      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9392      * @return {Element} The Element object
9393      * @static
9394      */
9395     El.get = function(el){
9396         var ex, elm, id;
9397         if(!el){ return null; }
9398         if(typeof el == "string"){ // element id
9399             if(!(elm = document.getElementById(el))){
9400                 return null;
9401             }
9402             if(ex = El.cache[el]){
9403                 ex.dom = elm;
9404             }else{
9405                 ex = El.cache[el] = new El(elm);
9406             }
9407             return ex;
9408         }else if(el.tagName){ // dom element
9409             if(!(id = el.id)){
9410                 id = Roo.id(el);
9411             }
9412             if(ex = El.cache[id]){
9413                 ex.dom = el;
9414             }else{
9415                 ex = El.cache[id] = new El(el);
9416             }
9417             return ex;
9418         }else if(el instanceof El){
9419             if(el != docEl){
9420                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9421                                                               // catch case where it hasn't been appended
9422                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9423             }
9424             return el;
9425         }else if(el.isComposite){
9426             return el;
9427         }else if(el instanceof Array){
9428             return El.select(el);
9429         }else if(el == document){
9430             // create a bogus element object representing the document object
9431             if(!docEl){
9432                 var f = function(){};
9433                 f.prototype = El.prototype;
9434                 docEl = new f();
9435                 docEl.dom = document;
9436             }
9437             return docEl;
9438         }
9439         return null;
9440     };
9441
9442     // private
9443     El.uncache = function(el){
9444         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9445             if(a[i]){
9446                 delete El.cache[a[i].id || a[i]];
9447             }
9448         }
9449     };
9450
9451     // private
9452     // Garbage collection - uncache elements/purge listeners on orphaned elements
9453     // so we don't hold a reference and cause the browser to retain them
9454     El.garbageCollect = function(){
9455         if(!Roo.enableGarbageCollector){
9456             clearInterval(El.collectorThread);
9457             return;
9458         }
9459         for(var eid in El.cache){
9460             var el = El.cache[eid], d = el.dom;
9461             // -------------------------------------------------------
9462             // Determining what is garbage:
9463             // -------------------------------------------------------
9464             // !d
9465             // dom node is null, definitely garbage
9466             // -------------------------------------------------------
9467             // !d.parentNode
9468             // no parentNode == direct orphan, definitely garbage
9469             // -------------------------------------------------------
9470             // !d.offsetParent && !document.getElementById(eid)
9471             // display none elements have no offsetParent so we will
9472             // also try to look it up by it's id. However, check
9473             // offsetParent first so we don't do unneeded lookups.
9474             // This enables collection of elements that are not orphans
9475             // directly, but somewhere up the line they have an orphan
9476             // parent.
9477             // -------------------------------------------------------
9478             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9479                 delete El.cache[eid];
9480                 if(d && Roo.enableListenerCollection){
9481                     E.purgeElement(d);
9482                 }
9483             }
9484         }
9485     }
9486     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9487
9488
9489     // dom is optional
9490     El.Flyweight = function(dom){
9491         this.dom = dom;
9492     };
9493     El.Flyweight.prototype = El.prototype;
9494
9495     El._flyweights = {};
9496     /**
9497      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9498      * the dom node can be overwritten by other code.
9499      * @param {String/HTMLElement} el The dom node or id
9500      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9501      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9502      * @static
9503      * @return {Element} The shared Element object
9504      */
9505     El.fly = function(el, named){
9506         named = named || '_global';
9507         el = Roo.getDom(el);
9508         if(!el){
9509             return null;
9510         }
9511         if(!El._flyweights[named]){
9512             El._flyweights[named] = new El.Flyweight();
9513         }
9514         El._flyweights[named].dom = el;
9515         return El._flyweights[named];
9516     };
9517
9518     /**
9519      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9520      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9521      * Shorthand of {@link Roo.Element#get}
9522      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9523      * @return {Element} The Element object
9524      * @member Roo
9525      * @method get
9526      */
9527     Roo.get = El.get;
9528     /**
9529      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9530      * the dom node can be overwritten by other code.
9531      * Shorthand of {@link Roo.Element#fly}
9532      * @param {String/HTMLElement} el The dom node or id
9533      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9534      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9535      * @static
9536      * @return {Element} The shared Element object
9537      * @member Roo
9538      * @method fly
9539      */
9540     Roo.fly = El.fly;
9541
9542     // speedy lookup for elements never to box adjust
9543     var noBoxAdjust = Roo.isStrict ? {
9544         select:1
9545     } : {
9546         input:1, select:1, textarea:1
9547     };
9548     if(Roo.isIE || Roo.isGecko){
9549         noBoxAdjust['button'] = 1;
9550     }
9551
9552
9553     Roo.EventManager.on(window, 'unload', function(){
9554         delete El.cache;
9555         delete El._flyweights;
9556     });
9557 })();
9558
9559
9560
9561
9562 if(Roo.DomQuery){
9563     Roo.Element.selectorFunction = Roo.DomQuery.select;
9564 }
9565
9566 Roo.Element.select = function(selector, unique, root){
9567     var els;
9568     if(typeof selector == "string"){
9569         els = Roo.Element.selectorFunction(selector, root);
9570     }else if(selector.length !== undefined){
9571         els = selector;
9572     }else{
9573         throw "Invalid selector";
9574     }
9575     if(unique === true){
9576         return new Roo.CompositeElement(els);
9577     }else{
9578         return new Roo.CompositeElementLite(els);
9579     }
9580 };
9581 /**
9582  * Selects elements based on the passed CSS selector to enable working on them as 1.
9583  * @param {String/Array} selector The CSS selector or an array of elements
9584  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9585  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9586  * @return {CompositeElementLite/CompositeElement}
9587  * @member Roo
9588  * @method select
9589  */
9590 Roo.select = Roo.Element.select;
9591
9592
9593
9594
9595
9596
9597
9598
9599
9600
9601
9602
9603
9604