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