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