roojs-debug.js
[roojs1] / roojs-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88
89         /**
90          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
91          * @type Boolean
92          */
93         enableGarbageCollector : true,
94
95         /**
96          * True to automatically purge event listeners after uncaching an element (defaults to false).
97          * Note: this only happens if enableGarbageCollector is true.
98          * @type Boolean
99          */
100         enableListenerCollection:false,
101
102         /**
103          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104          * the IE insecure content warning (defaults to javascript:false).
105          * @type String
106          */
107         SSL_SECURE_URL : "javascript:false",
108
109         /**
110          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
112          * @type String
113          */
114         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
115
116         emptyFn : function(){},
117
118         /**
119          * Copies all the properties of config to obj if they don't already exist.
120          * @param {Object} obj The receiver of the properties
121          * @param {Object} config The source of the properties
122          * @return {Object} returns obj
123          */
124         applyIf : function(o, c){
125             if(o && c){
126                 for(var p in c){
127                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
128                 }
129             }
130             return o;
131         },
132
133         /**
134          * Applies event listeners to elements by selectors when the document is ready.
135          * The event name is specified with an @ suffix.
136 <pre><code>
137 Roo.addBehaviors({
138    // add a listener for click on all anchors in element with id foo
139    '#foo a@click' : function(e, t){
140        // do something
141    },
142
143    // add the same listener to multiple selectors (separated by comma BEFORE the @)
144    '#foo a, #bar span.some-class@mouseover' : function(){
145        // do something
146    }
147 });
148 </code></pre>
149          * @param {Object} obj The list of behaviors to apply
150          */
151         addBehaviors : function(o){
152             if(!Roo.isReady){
153                 Roo.onReady(function(){
154                     Roo.addBehaviors(o);
155                 });
156                 return;
157             }
158             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
159             for(var b in o){
160                 var parts = b.split('@');
161                 if(parts[1]){ // for Object prototype breakers
162                     var s = parts[0];
163                     if(!cache[s]){
164                         cache[s] = Roo.select(s);
165                     }
166                     cache[s].on(parts[1], o[b]);
167                 }
168             }
169             cache = null;
170         },
171
172         /**
173          * Generates unique ids. If the element already has an id, it is unchanged
174          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176          * @return {String} The generated Id.
177          */
178         id : function(el, prefix){
179             prefix = prefix || "roo-gen";
180             el = Roo.getDom(el);
181             var id = prefix + (++idSeed);
182             return el ? (el.id ? el.id : (el.id = id)) : id;
183         },
184          
185        
186         /**
187          * Extends one class with another class and optionally overrides members with the passed literal. This class
188          * also adds the function "override()" to the class that can be used to override
189          * members on an instance.
190          * @param {Object} subclass The class inheriting the functionality
191          * @param {Object} superclass The class being extended
192          * @param {Object} overrides (optional) A literal with members
193          * @method extend
194          */
195         extend : function(){
196             // inline overrides
197             var io = function(o){
198                 for(var m in o){
199                     this[m] = o[m];
200                 }
201             };
202             return function(sb, sp, overrides){
203                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
204                     overrides = sp;
205                     sp = sb;
206                     sb = function(){sp.apply(this, arguments);};
207                 }
208                 var F = function(){}, sbp, spp = sp.prototype;
209                 F.prototype = spp;
210                 sbp = sb.prototype = new F();
211                 sbp.constructor=sb;
212                 sb.superclass=spp;
213                 
214                 if(spp.constructor == Object.prototype.constructor){
215                     spp.constructor=sp;
216                    
217                 }
218                 
219                 sb.override = function(o){
220                     Roo.override(sb, o);
221                 };
222                 sbp.override = io;
223                 Roo.override(sb, overrides);
224                 return sb;
225             };
226         }(),
227
228         /**
229          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
230          * Usage:<pre><code>
231 Roo.override(MyClass, {
232     newMethod1: function(){
233         // etc.
234     },
235     newMethod2: function(foo){
236         // etc.
237     }
238 });
239  </code></pre>
240          * @param {Object} origclass The class to override
241          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
242          * containing one or more methods.
243          * @method override
244          */
245         override : function(origclass, overrides){
246             if(overrides){
247                 var p = origclass.prototype;
248                 for(var method in overrides){
249                     p[method] = overrides[method];
250                 }
251             }
252         },
253         /**
254          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
255          * <pre><code>
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
259 </code></pre>
260          * @param {String} namespace1
261          * @param {String} namespace2
262          * @param {String} etc
263          * @method namespace
264          */
265         namespace : function(){
266             var a=arguments, o=null, i, j, d, rt;
267             for (i=0; i<a.length; ++i) {
268                 d=a[i].split(".");
269                 rt = d[0];
270                 /** eval:var:o */
271                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272                 for (j=1; j<d.length; ++j) {
273                     o[d[j]]=o[d[j]] || {};
274                     o=o[d[j]];
275                 }
276             }
277         },
278         /**
279          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
280          * <pre><code>
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
283 </code></pre>
284          * @param {String} classname
285          * @param {String} namespace (optional)
286          * @method factory
287          */
288          
289         factory : function(c, ns)
290         {
291             // no xtype, no ns or c.xns - or forced off by c.xns
292             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
293                 return c;
294             }
295             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296             if (c.constructor == ns[c.xtype]) {// already created...
297                 return c;
298             }
299             if (ns[c.xtype]) {
300                 console.log("Roo.Factory(" + c.xtype + ")");
301                 var ret = new ns[c.xtype](c);
302                 ret.xns = false;
303                 return ret;
304             }
305             c.xns = false; // prevent recursion..
306             return c;
307         },
308          
309         /**
310          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
311          * @param {Object} o
312          * @return {String}
313          */
314         urlEncode : function(o){
315             if(!o){
316                 return "";
317             }
318             var buf = [];
319             for(var key in o){
320                 var ov = o[key], k = encodeURIComponent(key);
321                 var type = typeof ov;
322                 if(type == 'undefined'){
323                     buf.push(k, "=&");
324                 }else if(type != "function" && type != "object"){
325                     buf.push(k, "=", encodeURIComponent(ov), "&");
326                 }else if(ov instanceof Array){
327                     if (ov.length) {
328                             for(var i = 0, len = ov.length; i < len; i++) {
329                                 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
330                             }
331                         } else {
332                             buf.push(k, "=&");
333                         }
334                 }
335             }
336             buf.pop();
337             return buf.join("");
338         },
339
340         /**
341          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
342          * @param {String} string
343          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344          * @return {Object} A literal with members
345          */
346         urlDecode : function(string, overwrite){
347             if(!string || !string.length){
348                 return {};
349             }
350             var obj = {};
351             var pairs = string.split('&');
352             var pair, name, value;
353             for(var i = 0, len = pairs.length; i < len; i++){
354                 pair = pairs[i].split('=');
355                 name = decodeURIComponent(pair[0]);
356                 value = decodeURIComponent(pair[1]);
357                 if(overwrite !== true){
358                     if(typeof obj[name] == "undefined"){
359                         obj[name] = value;
360                     }else if(typeof obj[name] == "string"){
361                         obj[name] = [obj[name]];
362                         obj[name].push(value);
363                     }else{
364                         obj[name].push(value);
365                     }
366                 }else{
367                     obj[name] = value;
368                 }
369             }
370             return obj;
371         },
372
373         /**
374          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375          * passed array is not really an array, your function is called once with it.
376          * The supplied function is called with (Object item, Number index, Array allItems).
377          * @param {Array/NodeList/Mixed} array
378          * @param {Function} fn
379          * @param {Object} scope
380          */
381         each : function(array, fn, scope){
382             if(typeof array.length == "undefined" || typeof array == "string"){
383                 array = [array];
384             }
385             for(var i = 0, len = array.length; i < len; i++){
386                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
387             }
388         },
389
390         // deprecated
391         combine : function(){
392             var as = arguments, l = as.length, r = [];
393             for(var i = 0; i < l; i++){
394                 var a = as[i];
395                 if(a instanceof Array){
396                     r = r.concat(a);
397                 }else if(a.length !== undefined && !a.substr){
398                     r = r.concat(Array.prototype.slice.call(a, 0));
399                 }else{
400                     r.push(a);
401                 }
402             }
403             return r;
404         },
405
406         /**
407          * Escapes the passed string for use in a regular expression
408          * @param {String} str
409          * @return {String}
410          */
411         escapeRe : function(s) {
412             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
413         },
414
415         // internal
416         callback : function(cb, scope, args, delay){
417             if(typeof cb == "function"){
418                 if(delay){
419                     cb.defer(delay, scope, args || []);
420                 }else{
421                     cb.apply(scope, args || []);
422                 }
423             }
424         },
425
426         /**
427          * Return the dom node for the passed string (id), dom node, or Roo.Element
428          * @param {String/HTMLElement/Roo.Element} el
429          * @return HTMLElement
430          */
431         getDom : function(el){
432             if(!el){
433                 return null;
434             }
435             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
436         },
437
438         /**
439         * Shorthand for {@link Roo.ComponentMgr#get}
440         * @param {String} id
441         * @return Roo.Component
442         */
443         getCmp : function(id){
444             return Roo.ComponentMgr.get(id);
445         },
446          
447         num : function(v, defaultValue){
448             if(typeof v != 'number'){
449                 return defaultValue;
450             }
451             return v;
452         },
453
454         destroy : function(){
455             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
456                 var as = a[i];
457                 if(as){
458                     if(as.dom){
459                         as.removeAllListeners();
460                         as.remove();
461                         continue;
462                     }
463                     if(typeof as.purgeListeners == 'function'){
464                         as.purgeListeners();
465                     }
466                     if(typeof as.destroy == 'function'){
467                         as.destroy();
468                     }
469                 }
470             }
471         },
472
473         // inpired by a similar function in mootools library
474         /**
475          * Returns the type of object that is passed in. If the object passed in is null or undefined it
476          * return false otherwise it returns one of the following values:<ul>
477          * <li><b>string</b>: If the object passed is a string</li>
478          * <li><b>number</b>: If the object passed is a number</li>
479          * <li><b>boolean</b>: If the object passed is a boolean value</li>
480          * <li><b>function</b>: If the object passed is a function reference</li>
481          * <li><b>object</b>: If the object passed is an object</li>
482          * <li><b>array</b>: If the object passed is an array</li>
483          * <li><b>regexp</b>: If the object passed is a regular expression</li>
484          * <li><b>element</b>: If the object passed is a DOM Element</li>
485          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488          * @param {Mixed} object
489          * @return {String}
490          */
491         type : function(o){
492             if(o === undefined || o === null){
493                 return false;
494             }
495             if(o.htmlElement){
496                 return 'element';
497             }
498             var t = typeof o;
499             if(t == 'object' && o.nodeName) {
500                 switch(o.nodeType) {
501                     case 1: return 'element';
502                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
503                 }
504             }
505             if(t == 'object' || t == 'function') {
506                 switch(o.constructor) {
507                     case Array: return 'array';
508                     case RegExp: return 'regexp';
509                 }
510                 if(typeof o.length == 'number' && typeof o.item == 'function') {
511                     return 'nodelist';
512                 }
513             }
514             return t;
515         },
516
517         /**
518          * Returns true if the passed value is null, undefined or an empty string (optional).
519          * @param {Mixed} value The value to test
520          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
521          * @return {Boolean}
522          */
523         isEmpty : function(v, allowBlank){
524             return v === null || v === undefined || (!allowBlank ? v === '' : false);
525         },
526         
527         /** @type Boolean */
528         isOpera : isOpera,
529         /** @type Boolean */
530         isSafari : isSafari,
531         /** @type Boolean */
532         isIE : isIE,
533         /** @type Boolean */
534         isIE7 : isIE7,
535         /** @type Boolean */
536         isGecko : isGecko,
537         /** @type Boolean */
538         isBorderBox : isBorderBox,
539         /** @type Boolean */
540         isWindows : isWindows,
541         /** @type Boolean */
542         isLinux : isLinux,
543         /** @type Boolean */
544         isMac : isMac,
545
546         /**
547          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548          * you may want to set this to true.
549          * @type Boolean
550          */
551         useShims : ((isIE && !isIE7) || (isGecko && isMac))
552     });
553
554
555 })();
556
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
559 /*
560  * Based on:
561  * Ext JS Library 1.1.1
562  * Copyright(c) 2006-2007, Ext JS, LLC.
563  *
564  * Originally Released Under LGPL - original licence link has changed is not relivant.
565  *
566  * Fork - LGPL
567  * <script type="text/javascript">
568  */
569
570 (function() {    
571     // wrappedn so fnCleanup is not in global scope...
572     if(Roo.isIE) {
573         function fnCleanUp() {
574             var p = Function.prototype;
575             delete p.createSequence;
576             delete p.defer;
577             delete p.createDelegate;
578             delete p.createCallback;
579             delete p.createInterceptor;
580
581             window.detachEvent("onunload", fnCleanUp);
582         }
583         window.attachEvent("onunload", fnCleanUp);
584     }
585 })();
586
587
588 /**
589  * @class Function
590  * These functions are available on every Function object (any JavaScript function).
591  */
592 Roo.apply(Function.prototype, {
593      /**
594      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596      * Will create a function that is bound to those 2 args.
597      * @return {Function} The new function
598     */
599     createCallback : function(/*args...*/){
600         // make args available, in function below
601         var args = arguments;
602         var method = this;
603         return function() {
604             return method.apply(window, args);
605         };
606     },
607
608     /**
609      * Creates a delegate (callback) that sets the scope to obj.
610      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611      * Will create a function that is automatically scoped to this.
612      * @param {Object} obj (optional) The object for which the scope is set
613      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615      *                                             if a number the args are inserted at the specified position
616      * @return {Function} The new function
617      */
618     createDelegate : function(obj, args, appendArgs){
619         var method = this;
620         return function() {
621             var callArgs = args || arguments;
622             if(appendArgs === true){
623                 callArgs = Array.prototype.slice.call(arguments, 0);
624                 callArgs = callArgs.concat(args);
625             }else if(typeof appendArgs == "number"){
626                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
629             }
630             return method.apply(obj || window, callArgs);
631         };
632     },
633
634     /**
635      * Calls this function after the number of millseconds specified.
636      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637      * @param {Object} obj (optional) The object for which the scope is set
638      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640      *                                             if a number the args are inserted at the specified position
641      * @return {Number} The timeout id that can be used with clearTimeout
642      */
643     defer : function(millis, obj, args, appendArgs){
644         var fn = this.createDelegate(obj, args, appendArgs);
645         if(millis){
646             return setTimeout(fn, millis);
647         }
648         fn();
649         return 0;
650     },
651     /**
652      * Create a combined function call sequence of the original function + the passed function.
653      * The resulting function returns the results of the original function.
654      * The passed fcn is called with the parameters of the original function
655      * @param {Function} fcn The function to sequence
656      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657      * @return {Function} The new function
658      */
659     createSequence : function(fcn, scope){
660         if(typeof fcn != "function"){
661             return this;
662         }
663         var method = this;
664         return function() {
665             var retval = method.apply(this || window, arguments);
666             fcn.apply(scope || this || window, arguments);
667             return retval;
668         };
669     },
670
671     /**
672      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673      * The resulting function returns the results of the original function.
674      * The passed fcn is called with the parameters of the original function.
675      * @addon
676      * @param {Function} fcn The function to call before the original
677      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678      * @return {Function} The new function
679      */
680     createInterceptor : function(fcn, scope){
681         if(typeof fcn != "function"){
682             return this;
683         }
684         var method = this;
685         return function() {
686             fcn.target = this;
687             fcn.method = method;
688             if(fcn.apply(scope || this || window, arguments) === false){
689                 return;
690             }
691             return method.apply(this || window, arguments);
692         };
693     }
694 });
695 /*
696  * Based on:
697  * Ext JS Library 1.1.1
698  * Copyright(c) 2006-2007, Ext JS, LLC.
699  *
700  * Originally Released Under LGPL - original licence link has changed is not relivant.
701  *
702  * Fork - LGPL
703  * <script type="text/javascript">
704  */
705
706 Roo.applyIf(String, {
707     
708     /** @scope String */
709     
710     /**
711      * Escapes the passed string for ' and \
712      * @param {String} string The string to escape
713      * @return {String} The escaped string
714      * @static
715      */
716     escape : function(string) {
717         return string.replace(/('|\\)/g, "\\$1");
718     },
719
720     /**
721      * Pads the left side of a string with a specified character.  This is especially useful
722      * for normalizing number and date strings.  Example usage:
723      * <pre><code>
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
726 </code></pre>
727      * @param {String} string The original string
728      * @param {Number} size The total length of the output string
729      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730      * @return {String} The padded string
731      * @static
732      */
733     leftPad : function (val, size, ch) {
734         var result = new String(val);
735         if(ch === null || ch === undefined || ch === '') {
736             ch = " ";
737         }
738         while (result.length < size) {
739             result = ch + result;
740         }
741         return result;
742     },
743
744     /**
745      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
746      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
747      * <pre><code>
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
751 </code></pre>
752      * @param {String} string The tokenized string to be formatted
753      * @param {String} value1 The value to replace token {0}
754      * @param {String} value2 Etc...
755      * @return {String} The formatted string
756      * @static
757      */
758     format : function(format){
759         var args = Array.prototype.slice.call(arguments, 1);
760         return format.replace(/\{(\d+)\}/g, function(m, i){
761             return Roo.util.Format.htmlEncode(args[i]);
762         });
763     }
764 });
765
766 /**
767  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
768  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
769  * they are already different, the first value passed in is returned.  Note that this method returns the new value
770  * but does not change the current string.
771  * <pre><code>
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
774
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
777 </code></pre>
778  * @param {String} value The value to compare to the current string
779  * @param {String} other The new value to use if the string already equals the first value passed in
780  * @return {String} The new value
781  */
782  
783 String.prototype.toggle = function(value, other){
784     return this == value ? other : value;
785 };/*
786  * Based on:
787  * Ext JS Library 1.1.1
788  * Copyright(c) 2006-2007, Ext JS, LLC.
789  *
790  * Originally Released Under LGPL - original licence link has changed is not relivant.
791  *
792  * Fork - LGPL
793  * <script type="text/javascript">
794  */
795
796  /**
797  * @class Number
798  */
799 Roo.applyIf(Number.prototype, {
800     /**
801      * Checks whether or not the current number is within a desired range.  If the number is already within the
802      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803      * exceeded.  Note that this method returns the constrained value but does not change the current number.
804      * @param {Number} min The minimum number in the range
805      * @param {Number} max The maximum number in the range
806      * @return {Number} The constrained value if outside the range, otherwise the current value
807      */
808     constrain : function(min, max){
809         return Math.min(Math.max(this, min), max);
810     }
811 });/*
812  * Based on:
813  * Ext JS Library 1.1.1
814  * Copyright(c) 2006-2007, Ext JS, LLC.
815  *
816  * Originally Released Under LGPL - original licence link has changed is not relivant.
817  *
818  * Fork - LGPL
819  * <script type="text/javascript">
820  */
821  /**
822  * @class Array
823  */
824 Roo.applyIf(Array.prototype, {
825     /**
826      * Checks whether or not the specified object exists in the array.
827      * @param {Object} o The object to check for
828      * @return {Number} The index of o in the array (or -1 if it is not found)
829      */
830     indexOf : function(o){
831        for (var i = 0, len = this.length; i < len; i++){
832               if(this[i] == o) return i;
833        }
834            return -1;
835     },
836
837     /**
838      * Removes the specified object from the array.  If the object is not found nothing happens.
839      * @param {Object} o The object to remove
840      */
841     remove : function(o){
842        var index = this.indexOf(o);
843        if(index != -1){
844            this.splice(index, 1);
845        }
846     }
847 });/*
848  * Based on:
849  * Ext JS Library 1.1.1
850  * Copyright(c) 2006-2007, Ext JS, LLC.
851  *
852  * Originally Released Under LGPL - original licence link has changed is not relivant.
853  *
854  * Fork - LGPL
855  * <script type="text/javascript">
856  */
857
858 /**
859  * @class Date
860  *
861  * The date parsing and format syntax is a subset of
862  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
863  * supported will provide results equivalent to their PHP versions.
864  *
865  * Following is the list of all currently supported formats:
866  *<pre>
867 Sample date:
868 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
869
870 Format  Output      Description
871 ------  ----------  --------------------------------------------------------------
872   d      10         Day of the month, 2 digits with leading zeros
873   D      Wed        A textual representation of a day, three letters
874   j      10         Day of the month without leading zeros
875   l      Wednesday  A full textual representation of the day of the week
876   S      th         English ordinal day of month suffix, 2 chars (use with j)
877   w      3          Numeric representation of the day of the week
878   z      9          The julian date, or day of the year (0-365)
879   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
880   F      January    A full textual representation of the month
881   m      01         Numeric representation of a month, with leading zeros
882   M      Jan        Month name abbreviation, three letters
883   n      1          Numeric representation of a month, without leading zeros
884   t      31         Number of days in the given month
885   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
886   Y      2007       A full numeric representation of a year, 4 digits
887   y      07         A two digit representation of a year
888   a      pm         Lowercase Ante meridiem and Post meridiem
889   A      PM         Uppercase Ante meridiem and Post meridiem
890   g      3          12-hour format of an hour without leading zeros
891   G      15         24-hour format of an hour without leading zeros
892   h      03         12-hour format of an hour with leading zeros
893   H      15         24-hour format of an hour with leading zeros
894   i      05         Minutes with leading zeros
895   s      01         Seconds, with leading zeros
896   O      -0600      Difference to Greenwich time (GMT) in hours
897   T      CST        Timezone setting of the machine running the code
898   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
899 </pre>
900  *
901  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
902  * <pre><code>
903 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
904 document.write(dt.format('Y-m-d'));                         //2007-01-10
905 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
906 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
907  </code></pre>
908  *
909  * Here are some standard date/time patterns that you might find helpful.  They
910  * are not part of the source of Date.js, but to use them you can simply copy this
911  * block of code into any script that is included after Date.js and they will also become
912  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
913  * <pre><code>
914 Date.patterns = {
915     ISO8601Long:"Y-m-d H:i:s",
916     ISO8601Short:"Y-m-d",
917     ShortDate: "n/j/Y",
918     LongDate: "l, F d, Y",
919     FullDateTime: "l, F d, Y g:i:s A",
920     MonthDay: "F d",
921     ShortTime: "g:i A",
922     LongTime: "g:i:s A",
923     SortableDateTime: "Y-m-d\\TH:i:s",
924     UniversalSortableDateTime: "Y-m-d H:i:sO",
925     YearMonth: "F, Y"
926 };
927 </code></pre>
928  *
929  * Example usage:
930  * <pre><code>
931 var dt = new Date();
932 document.write(dt.format(Date.patterns.ShortDate));
933  </code></pre>
934  */
935
936 /*
937  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
938  * They generate precompiled functions from date formats instead of parsing and
939  * processing the pattern every time you format a date.  These functions are available
940  * on every Date object (any javascript function).
941  *
942  * The original article and download are here:
943  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
944  *
945  */
946  
947  
948  // was in core
949 /**
950  Returns the number of milliseconds between this date and date
951  @param {Date} date (optional) Defaults to now
952  @return {Number} The diff in milliseconds
953  @member Date getElapsed
954  */
955 Date.prototype.getElapsed = function(date) {
956         return Math.abs((date || new Date()).getTime()-this.getTime());
957 };
958 // was in date file..
959
960
961 // private
962 Date.parseFunctions = {count:0};
963 // private
964 Date.parseRegexes = [];
965 // private
966 Date.formatFunctions = {count:0};
967
968 // private
969 Date.prototype.dateFormat = function(format) {
970     if (Date.formatFunctions[format] == null) {
971         Date.createNewFormat(format);
972     }
973     var func = Date.formatFunctions[format];
974     return this[func]();
975 };
976
977
978 /**
979  * Formats a date given the supplied format string
980  * @param {String} format The format string
981  * @return {String} The formatted date
982  * @method
983  */
984 Date.prototype.format = Date.prototype.dateFormat;
985
986 // private
987 Date.createNewFormat = function(format) {
988     var funcName = "format" + Date.formatFunctions.count++;
989     Date.formatFunctions[format] = funcName;
990     var code = "Date.prototype." + funcName + " = function(){return ";
991     var special = false;
992     var ch = '';
993     for (var i = 0; i < format.length; ++i) {
994         ch = format.charAt(i);
995         if (!special && ch == "\\") {
996             special = true;
997         }
998         else if (special) {
999             special = false;
1000             code += "'" + String.escape(ch) + "' + ";
1001         }
1002         else {
1003             code += Date.getFormatCode(ch);
1004         }
1005     }
1006     /** eval:var:zzzzzzzzzzzzz */
1007     eval(code.substring(0, code.length - 3) + ";}");
1008 };
1009
1010 // private
1011 Date.getFormatCode = function(character) {
1012     switch (character) {
1013     case "d":
1014         return "String.leftPad(this.getDate(), 2, '0') + ";
1015     case "D":
1016         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1017     case "j":
1018         return "this.getDate() + ";
1019     case "l":
1020         return "Date.dayNames[this.getDay()] + ";
1021     case "S":
1022         return "this.getSuffix() + ";
1023     case "w":
1024         return "this.getDay() + ";
1025     case "z":
1026         return "this.getDayOfYear() + ";
1027     case "W":
1028         return "this.getWeekOfYear() + ";
1029     case "F":
1030         return "Date.monthNames[this.getMonth()] + ";
1031     case "m":
1032         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1033     case "M":
1034         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1035     case "n":
1036         return "(this.getMonth() + 1) + ";
1037     case "t":
1038         return "this.getDaysInMonth() + ";
1039     case "L":
1040         return "(this.isLeapYear() ? 1 : 0) + ";
1041     case "Y":
1042         return "this.getFullYear() + ";
1043     case "y":
1044         return "('' + this.getFullYear()).substring(2, 4) + ";
1045     case "a":
1046         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1047     case "A":
1048         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1049     case "g":
1050         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1051     case "G":
1052         return "this.getHours() + ";
1053     case "h":
1054         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1055     case "H":
1056         return "String.leftPad(this.getHours(), 2, '0') + ";
1057     case "i":
1058         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1059     case "s":
1060         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1061     case "O":
1062         return "this.getGMTOffset() + ";
1063     case "T":
1064         return "this.getTimezone() + ";
1065     case "Z":
1066         return "(this.getTimezoneOffset() * -60) + ";
1067     default:
1068         return "'" + String.escape(character) + "' + ";
1069     }
1070 };
1071
1072 /**
1073  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1074  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1075  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1076  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1077  * string or the parse operation will fail.
1078  * Example Usage:
1079 <pre><code>
1080 //dt = Fri May 25 2007 (current date)
1081 var dt = new Date();
1082
1083 //dt = Thu May 25 2006 (today's month/day in 2006)
1084 dt = Date.parseDate("2006", "Y");
1085
1086 //dt = Sun Jan 15 2006 (all date parts specified)
1087 dt = Date.parseDate("2006-1-15", "Y-m-d");
1088
1089 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1090 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1091 </code></pre>
1092  * @param {String} input The unparsed date as a string
1093  * @param {String} format The format the date is in
1094  * @return {Date} The parsed date
1095  * @static
1096  */
1097 Date.parseDate = function(input, format) {
1098     if (Date.parseFunctions[format] == null) {
1099         Date.createParser(format);
1100     }
1101     var func = Date.parseFunctions[format];
1102     return Date[func](input);
1103 };
1104 /**
1105  * @private
1106  */
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;