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