Merge branch 'master' of https://github.com/roojs/roojs1 into github
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * 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.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358
359         /**
360          * 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]}.
361          * @param {String} string
362          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
363          * @return {Object} A literal with members
364          */
365         urlDecode : function(string, overwrite){
366             if(!string || !string.length){
367                 return {};
368             }
369             var obj = {};
370             var pairs = string.split('&');
371             var pair, name, value;
372             for(var i = 0, len = pairs.length; i < len; i++){
373                 pair = pairs[i].split('=');
374                 name = decodeURIComponent(pair[0]);
375                 value = decodeURIComponent(pair[1]);
376                 if(overwrite !== true){
377                     if(typeof obj[name] == "undefined"){
378                         obj[name] = value;
379                     }else if(typeof obj[name] == "string"){
380                         obj[name] = [obj[name]];
381                         obj[name].push(value);
382                     }else{
383                         obj[name].push(value);
384                     }
385                 }else{
386                     obj[name] = value;
387                 }
388             }
389             return obj;
390         },
391
392         /**
393          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
394          * passed array is not really an array, your function is called once with it.
395          * The supplied function is called with (Object item, Number index, Array allItems).
396          * @param {Array/NodeList/Mixed} array
397          * @param {Function} fn
398          * @param {Object} scope
399          */
400         each : function(array, fn, scope){
401             if(typeof array.length == "undefined" || typeof array == "string"){
402                 array = [array];
403             }
404             for(var i = 0, len = array.length; i < len; i++){
405                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
406             }
407         },
408
409         // deprecated
410         combine : function(){
411             var as = arguments, l = as.length, r = [];
412             for(var i = 0; i < l; i++){
413                 var a = as[i];
414                 if(a instanceof Array){
415                     r = r.concat(a);
416                 }else if(a.length !== undefined && !a.substr){
417                     r = r.concat(Array.prototype.slice.call(a, 0));
418                 }else{
419                     r.push(a);
420                 }
421             }
422             return r;
423         },
424
425         /**
426          * Escapes the passed string for use in a regular expression
427          * @param {String} str
428          * @return {String}
429          */
430         escapeRe : function(s) {
431             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
432         },
433
434         // internal
435         callback : function(cb, scope, args, delay){
436             if(typeof cb == "function"){
437                 if(delay){
438                     cb.defer(delay, scope, args || []);
439                 }else{
440                     cb.apply(scope, args || []);
441                 }
442             }
443         },
444
445         /**
446          * Return the dom node for the passed string (id), dom node, or Roo.Element
447          * @param {String/HTMLElement/Roo.Element} el
448          * @return HTMLElement
449          */
450         getDom : function(el){
451             if(!el){
452                 return null;
453             }
454             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
455         },
456
457         /**
458         * Shorthand for {@link Roo.ComponentMgr#get}
459         * @param {String} id
460         * @return Roo.Component
461         */
462         getCmp : function(id){
463             return Roo.ComponentMgr.get(id);
464         },
465          
466         num : function(v, defaultValue){
467             if(typeof v != 'number'){
468                 return defaultValue;
469             }
470             return v;
471         },
472
473         destroy : function(){
474             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
475                 var as = a[i];
476                 if(as){
477                     if(as.dom){
478                         as.removeAllListeners();
479                         as.remove();
480                         continue;
481                     }
482                     if(typeof as.purgeListeners == 'function'){
483                         as.purgeListeners();
484                     }
485                     if(typeof as.destroy == 'function'){
486                         as.destroy();
487                     }
488                 }
489             }
490         },
491
492         // inpired by a similar function in mootools library
493         /**
494          * Returns the type of object that is passed in. If the object passed in is null or undefined it
495          * return false otherwise it returns one of the following values:<ul>
496          * <li><b>string</b>: If the object passed is a string</li>
497          * <li><b>number</b>: If the object passed is a number</li>
498          * <li><b>boolean</b>: If the object passed is a boolean value</li>
499          * <li><b>function</b>: If the object passed is a function reference</li>
500          * <li><b>object</b>: If the object passed is an object</li>
501          * <li><b>array</b>: If the object passed is an array</li>
502          * <li><b>regexp</b>: If the object passed is a regular expression</li>
503          * <li><b>element</b>: If the object passed is a DOM Element</li>
504          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
505          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
506          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
507          * @param {Mixed} object
508          * @return {String}
509          */
510         type : function(o){
511             if(o === undefined || o === null){
512                 return false;
513             }
514             if(o.htmlElement){
515                 return 'element';
516             }
517             var t = typeof o;
518             if(t == 'object' && o.nodeName) {
519                 switch(o.nodeType) {
520                     case 1: return 'element';
521                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
522                 }
523             }
524             if(t == 'object' || t == 'function') {
525                 switch(o.constructor) {
526                     case Array: return 'array';
527                     case RegExp: return 'regexp';
528                 }
529                 if(typeof o.length == 'number' && typeof o.item == 'function') {
530                     return 'nodelist';
531                 }
532             }
533             return t;
534         },
535
536         /**
537          * Returns true if the passed value is null, undefined or an empty string (optional).
538          * @param {Mixed} value The value to test
539          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
540          * @return {Boolean}
541          */
542         isEmpty : function(v, allowBlank){
543             return v === null || v === undefined || (!allowBlank ? v === '' : false);
544         },
545         
546         /** @type Boolean */
547         isOpera : isOpera,
548         /** @type Boolean */
549         isSafari : isSafari,
550         /** @type Boolean */
551         isIE : isIE,
552         /** @type Boolean */
553         isIE7 : isIE7,
554         /** @type Boolean */
555         isGecko : isGecko,
556         /** @type Boolean */
557         isBorderBox : isBorderBox,
558         /** @type Boolean */
559         isWindows : isWindows,
560         /** @type Boolean */
561         isLinux : isLinux,
562         /** @type Boolean */
563         isMac : isMac,
564
565         /**
566          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
567          * you may want to set this to true.
568          * @type Boolean
569          */
570         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
571         
572         
573                 
574         /**
575          * Selects a single element as a Roo Element
576          * This is about as close as you can get to jQuery's $('do crazy stuff')
577          * @param {String} selector The selector/xpath query
578          * @param {Node} root (optional) The start of the query (defaults to document).
579          * @return {Roo.Element}
580          */
581         selectNode : function(selector, root) 
582         {
583             var node = Roo.DomQuery.selectNode(selector,root);
584             return node ? Roo.get(node) : new Roo.Element(false);
585         }
586         
587     });
588
589
590 })();
591
592 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
593                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
594 /*
595  * Based on:
596  * Ext JS Library 1.1.1
597  * Copyright(c) 2006-2007, Ext JS, LLC.
598  *
599  * Originally Released Under LGPL - original licence link has changed is not relivant.
600  *
601  * Fork - LGPL
602  * <script type="text/javascript">
603  */
604
605 (function() {    
606     // wrappedn so fnCleanup is not in global scope...
607     if(Roo.isIE) {
608         function fnCleanUp() {
609             var p = Function.prototype;
610             delete p.createSequence;
611             delete p.defer;
612             delete p.createDelegate;
613             delete p.createCallback;
614             delete p.createInterceptor;
615
616             window.detachEvent("onunload", fnCleanUp);
617         }
618         window.attachEvent("onunload", fnCleanUp);
619     }
620 })();
621
622
623 /**
624  * @class Function
625  * These functions are available on every Function object (any JavaScript function).
626  */
627 Roo.apply(Function.prototype, {
628      /**
629      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
630      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
631      * Will create a function that is bound to those 2 args.
632      * @return {Function} The new function
633     */
634     createCallback : function(/*args...*/){
635         // make args available, in function below
636         var args = arguments;
637         var method = this;
638         return function() {
639             return method.apply(window, args);
640         };
641     },
642
643     /**
644      * Creates a delegate (callback) that sets the scope to obj.
645      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
646      * Will create a function that is automatically scoped to this.
647      * @param {Object} obj (optional) The object for which the scope is set
648      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
649      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
650      *                                             if a number the args are inserted at the specified position
651      * @return {Function} The new function
652      */
653     createDelegate : function(obj, args, appendArgs){
654         var method = this;
655         return function() {
656             var callArgs = args || arguments;
657             if(appendArgs === true){
658                 callArgs = Array.prototype.slice.call(arguments, 0);
659                 callArgs = callArgs.concat(args);
660             }else if(typeof appendArgs == "number"){
661                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
662                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
663                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
664             }
665             return method.apply(obj || window, callArgs);
666         };
667     },
668
669     /**
670      * Calls this function after the number of millseconds specified.
671      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
672      * @param {Object} obj (optional) The object for which the scope is set
673      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
674      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
675      *                                             if a number the args are inserted at the specified position
676      * @return {Number} The timeout id that can be used with clearTimeout
677      */
678     defer : function(millis, obj, args, appendArgs){
679         var fn = this.createDelegate(obj, args, appendArgs);
680         if(millis){
681             return setTimeout(fn, millis);
682         }
683         fn();
684         return 0;
685     },
686     /**
687      * Create a combined function call sequence of the original function + the passed function.
688      * The resulting function returns the results of the original function.
689      * The passed fcn is called with the parameters of the original function
690      * @param {Function} fcn The function to sequence
691      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
692      * @return {Function} The new function
693      */
694     createSequence : function(fcn, scope){
695         if(typeof fcn != "function"){
696             return this;
697         }
698         var method = this;
699         return function() {
700             var retval = method.apply(this || window, arguments);
701             fcn.apply(scope || this || window, arguments);
702             return retval;
703         };
704     },
705
706     /**
707      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
708      * The resulting function returns the results of the original function.
709      * The passed fcn is called with the parameters of the original function.
710      * @addon
711      * @param {Function} fcn The function to call before the original
712      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
713      * @return {Function} The new function
714      */
715     createInterceptor : function(fcn, scope){
716         if(typeof fcn != "function"){
717             return this;
718         }
719         var method = this;
720         return function() {
721             fcn.target = this;
722             fcn.method = method;
723             if(fcn.apply(scope || this || window, arguments) === false){
724                 return;
725             }
726             return method.apply(this || window, arguments);
727         };
728     }
729 });
730 /*
731  * Based on:
732  * Ext JS Library 1.1.1
733  * Copyright(c) 2006-2007, Ext JS, LLC.
734  *
735  * Originally Released Under LGPL - original licence link has changed is not relivant.
736  *
737  * Fork - LGPL
738  * <script type="text/javascript">
739  */
740
741 Roo.applyIf(String, {
742     
743     /** @scope String */
744     
745     /**
746      * Escapes the passed string for ' and \
747      * @param {String} string The string to escape
748      * @return {String} The escaped string
749      * @static
750      */
751     escape : function(string) {
752         return string.replace(/('|\\)/g, "\\$1");
753     },
754
755     /**
756      * Pads the left side of a string with a specified character.  This is especially useful
757      * for normalizing number and date strings.  Example usage:
758      * <pre><code>
759 var s = String.leftPad('123', 5, '0');
760 // s now contains the string: '00123'
761 </code></pre>
762      * @param {String} string The original string
763      * @param {Number} size The total length of the output string
764      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
765      * @return {String} The padded string
766      * @static
767      */
768     leftPad : function (val, size, ch) {
769         var result = new String(val);
770         if(ch === null || ch === undefined || ch === '') {
771             ch = " ";
772         }
773         while (result.length < size) {
774             result = ch + result;
775         }
776         return result;
777     },
778
779     /**
780      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
781      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
782      * <pre><code>
783 var cls = 'my-class', text = 'Some text';
784 var s = String.format('<div class="{0}">{1}</div>', cls, text);
785 // s now contains the string: '<div class="my-class">Some text</div>'
786 </code></pre>
787      * @param {String} string The tokenized string to be formatted
788      * @param {String} value1 The value to replace token {0}
789      * @param {String} value2 Etc...
790      * @return {String} The formatted string
791      * @static
792      */
793     format : function(format){
794         var args = Array.prototype.slice.call(arguments, 1);
795         return format.replace(/\{(\d+)\}/g, function(m, i){
796             return Roo.util.Format.htmlEncode(args[i]);
797         });
798     }
799 });
800
801 /**
802  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
803  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
804  * they are already different, the first value passed in is returned.  Note that this method returns the new value
805  * but does not change the current string.
806  * <pre><code>
807 // alternate sort directions
808 sort = sort.toggle('ASC', 'DESC');
809
810 // instead of conditional logic:
811 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
812 </code></pre>
813  * @param {String} value The value to compare to the current string
814  * @param {String} other The new value to use if the string already equals the first value passed in
815  * @return {String} The new value
816  */
817  
818 String.prototype.toggle = function(value, other){
819     return this == value ? other : value;
820 };/*
821  * Based on:
822  * Ext JS Library 1.1.1
823  * Copyright(c) 2006-2007, Ext JS, LLC.
824  *
825  * Originally Released Under LGPL - original licence link has changed is not relivant.
826  *
827  * Fork - LGPL
828  * <script type="text/javascript">
829  */
830
831  /**
832  * @class Number
833  */
834 Roo.applyIf(Number.prototype, {
835     /**
836      * Checks whether or not the current number is within a desired range.  If the number is already within the
837      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
838      * exceeded.  Note that this method returns the constrained value but does not change the current number.
839      * @param {Number} min The minimum number in the range
840      * @param {Number} max The maximum number in the range
841      * @return {Number} The constrained value if outside the range, otherwise the current value
842      */
843     constrain : function(min, max){
844         return Math.min(Math.max(this, min), max);
845     }
846 });/*
847  * Based on:
848  * Ext JS Library 1.1.1
849  * Copyright(c) 2006-2007, Ext JS, LLC.
850  *
851  * Originally Released Under LGPL - original licence link has changed is not relivant.
852  *
853  * Fork - LGPL
854  * <script type="text/javascript">
855  */
856  /**
857  * @class Array
858  */
859 Roo.applyIf(Array.prototype, {
860     /**
861      * Checks whether or not the specified object exists in the array.
862      * @param {Object} o The object to check for
863      * @return {Number} The index of o in the array (or -1 if it is not found)
864      */
865     indexOf : function(o){
866        for (var i = 0, len = this.length; i < len; i++){
867               if(this[i] == o) return i;
868        }
869            return -1;
870     },
871
872     /**
873      * Removes the specified object from the array.  If the object is not found nothing happens.
874      * @param {Object} o The object to remove
875      */
876     remove : function(o){
877        var index = this.indexOf(o);
878        if(index != -1){
879            this.splice(index, 1);
880        }
881     },
882     /**
883      * Map (JS 1.6 compatibility)
884      * @param {Function} function  to call
885      */
886     map : function(fun )
887     {
888         var len = this.length >>> 0;
889         if (typeof fun != "function")
890             throw new TypeError();
891
892         var res = new Array(len);
893         var thisp = arguments[1];
894         for (var i = 0; i < len; i++)
895         {
896             if (i in this)
897                 res[i] = fun.call(thisp, this[i], i, this);
898         }
899
900         return res;
901     }
902     
903 });
904
905
906  /*
907  * Based on:
908  * Ext JS Library 1.1.1
909  * Copyright(c) 2006-2007, Ext JS, LLC.
910  *
911  * Originally Released Under LGPL - original licence link has changed is not relivant.
912  *
913  * Fork - LGPL
914  * <script type="text/javascript">
915  */
916
917 /**
918  * @class Date
919  *
920  * The date parsing and format syntax is a subset of
921  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
922  * supported will provide results equivalent to their PHP versions.
923  *
924  * Following is the list of all currently supported formats:
925  *<pre>
926 Sample date:
927 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
928
929 Format  Output      Description
930 ------  ----------  --------------------------------------------------------------
931   d      10         Day of the month, 2 digits with leading zeros
932   D      Wed        A textual representation of a day, three letters
933   j      10         Day of the month without leading zeros
934   l      Wednesday  A full textual representation of the day of the week
935   S      th         English ordinal day of month suffix, 2 chars (use with j)
936   w      3          Numeric representation of the day of the week
937   z      9          The julian date, or day of the year (0-365)
938   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
939   F      January    A full textual representation of the month
940   m      01         Numeric representation of a month, with leading zeros
941   M      Jan        Month name abbreviation, three letters
942   n      1          Numeric representation of a month, without leading zeros
943   t      31         Number of days in the given month
944   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
945   Y      2007       A full numeric representation of a year, 4 digits
946   y      07         A two digit representation of a year
947   a      pm         Lowercase Ante meridiem and Post meridiem
948   A      PM         Uppercase Ante meridiem and Post meridiem
949   g      3          12-hour format of an hour without leading zeros
950   G      15         24-hour format of an hour without leading zeros
951   h      03         12-hour format of an hour with leading zeros
952   H      15         24-hour format of an hour with leading zeros
953   i      05         Minutes with leading zeros
954   s      01         Seconds, with leading zeros
955   O      -0600      Difference to Greenwich time (GMT) in hours
956   T      CST        Timezone setting of the machine running the code
957   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
958 </pre>
959  *
960  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
961  * <pre><code>
962 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
963 document.write(dt.format('Y-m-d'));                         //2007-01-10
964 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
965 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
966  </code></pre>
967  *
968  * Here are some standard date/time patterns that you might find helpful.  They
969  * are not part of the source of Date.js, but to use them you can simply copy this
970  * block of code into any script that is included after Date.js and they will also become
971  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
972  * <pre><code>
973 Date.patterns = {
974     ISO8601Long:"Y-m-d H:i:s",
975     ISO8601Short:"Y-m-d",
976     ShortDate: "n/j/Y",
977     LongDate: "l, F d, Y",
978     FullDateTime: "l, F d, Y g:i:s A",
979     MonthDay: "F d",
980     ShortTime: "g:i A",
981     LongTime: "g:i:s A",
982     SortableDateTime: "Y-m-d\\TH:i:s",
983     UniversalSortableDateTime: "Y-m-d H:i:sO",
984     YearMonth: "F, Y"
985 };
986 </code></pre>
987  *
988  * Example usage:
989  * <pre><code>
990 var dt = new Date();
991 document.write(dt.format(Date.patterns.ShortDate));
992  </code></pre>
993  */
994
995 /*
996  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
997  * They generate precompiled functions from date formats instead of parsing and
998  * processing the pattern every time you format a date.  These functions are available
999  * on every Date object (any javascript function).
1000  *
1001  * The original article and download are here:
1002  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1003  *
1004  */
1005  
1006  
1007  // was in core
1008 /**
1009  Returns the number of milliseconds between this date and date
1010  @param {Date} date (optional) Defaults to now
1011  @return {Number} The diff in milliseconds
1012  @member Date getElapsed
1013  */
1014 Date.prototype.getElapsed = function(date) {
1015         return Math.abs((date || new Date()).getTime()-this.getTime());
1016 };
1017 // was in date file..
1018
1019
1020 // private
1021 Date.parseFunctions = {count:0};
1022 // private
1023 Date.parseRegexes = [];
1024 // private
1025 Date.formatFunctions = {count:0};
1026
1027 // private
1028 Date.prototype.dateFormat = function(format) {
1029     if (Date.formatFunctions[format] == null) {
1030         Date.createNewFormat(format);
1031     }
1032     var func = Date.formatFunctions[format];
1033     return this[func]();
1034 };
1035
1036
1037 /**
1038  * Formats a date given the supplied format string
1039  * @param {String} format The format string
1040  * @return {String} The formatted date
1041  * @method
1042  */
1043 Date.prototype.format = Date.prototype.dateFormat;
1044
1045 // private
1046 Date.createNewFormat = function(format) {
1047     var funcName = "format" + Date.formatFunctions.count++;
1048     Date.formatFunctions[format] = funcName;
1049     var code = "Date.prototype." + funcName + " = function(){return ";
1050     var special = false;
1051     var ch = '';
1052     for (var i = 0; i < format.length; ++i) {
1053         ch = format.charAt(i);
1054         if (!special && ch == "\\") {
1055             special = true;
1056         }
1057         else if (special) {
1058             special = false;
1059             code += "'" + String.escape(ch) + "' + ";
1060         }
1061         else {
1062             code += Date.getFormatCode(ch);
1063         }
1064     }
1065     /** eval:var:zzzzzzzzzzzzz */
1066     eval(code.substring(0, code.length - 3) + ";}");
1067 };
1068
1069 // private
1070 Date.getFormatCode = function(character) {
1071     switch (character) {
1072     case "d":
1073         return "String.leftPad(this.getDate(), 2, '0') + ";
1074     case "D":
1075         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1076     case "j":
1077         return "this.getDate() + ";
1078     case "l":
1079         return "Date.dayNames[this.getDay()] + ";
1080     case "S":
1081         return "this.getSuffix() + ";
1082     case "w":
1083         return "this.getDay() + ";
1084     case "z":
1085         return "this.getDayOfYear() + ";
1086     case "W":
1087         return "this.getWeekOfYear() + ";
1088     case "F":
1089         return "Date.monthNames[this.getMonth()] + ";
1090     case "m":
1091         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1092     case "M":
1093         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1094     case "n":
1095         return "(this.getMonth() + 1) + ";
1096     case "t":
1097         return "this.getDaysInMonth() + ";
1098     case "L":
1099         return "(this.isLeapYear() ? 1 : 0) + ";
1100     case "Y":
1101         return "this.getFullYear() + ";
1102     case "y":
1103         return "('' + this.getFullYear()).substring(2, 4) + ";
1104     case "a":
1105         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1106     case "A":
1107         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1108     case "g":
1109         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1110     case "G":
1111         return "this.getHours() + ";
1112     case "h":
1113         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1114     case "H":
1115         return "String.leftPad(this.getHours(), 2, '0') + ";
1116     case "i":
1117         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1118     case "s":
1119         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1120     case "O":
1121         return "this.getGMTOffset() + ";
1122     case "T":
1123         return "this.getTimezone() + ";
1124     case "Z":
1125         return "(this.getTimezoneOffset() * -60) + ";
1126     default:
1127         return "'" + String.escape(character) + "' + ";
1128     }
1129 };
1130
1131 /**
1132  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1133  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1134  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1135  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1136  * string or the parse operation will fail.
1137  * Example Usage:
1138 <pre><code>
1139 //dt = Fri May 25 2007 (current date)
1140 var dt = new Date();
1141
1142 //dt = Thu May 25 2006 (today's month/day in 2006)
1143 dt = Date.parseDate("2006", "Y");
1144
1145 //dt = Sun Jan 15 2006 (all date parts specified)
1146 dt = Date.parseDate("2006-1-15", "Y-m-d");
1147
1148 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1149 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1150 </code></pre>
1151  * @param {String} input The unparsed date as a string
1152  * @param {String} format The format the date is in
1153  * @return {Date} The parsed date
1154  * @static
1155  */
1156 Date.parseDate = function(input, format) {
1157     if (Date.parseFunctions[format] == null) {
1158         Date.createParser(format);
1159     }
1160     var func = Date.parseFunctions[format];
1161     return Date[func](input);
1162 };
1163 /**
1164  * @private
1165  */
1166 Date.createParser = function(format) {
1167     var funcName = "parse" + Date.parseFunctions.count++;
1168     var regexNum = Date.parseRegexes.length;
1169     var currentGroup = 1;
1170     Date.parseFunctions[format] = funcName;
1171
1172     var code = "Date." + funcName + " = function(input){\n"
1173         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1174         + "var d = new Date();\n"
1175         + "y = d.getFullYear();\n"
1176         + "m = d.getMonth();\n"
1177         + "d = d.getDate();\n"
1178         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1179         + "if (results && results.length > 0) {";
1180     var regex = "";
1181
1182     var special = false;
1183     var ch = '';
1184     for (var i = 0; i < format.length; ++i) {
1185         ch = format.charAt(i);
1186         if (!special && ch == "\\") {
1187             special = true;
1188         }
1189         else if (special) {
1190             special = false;
1191             regex += String.escape(ch);
1192         }
1193         else {
1194             var obj = Date.formatCodeToRegex(ch, currentGroup);
1195             currentGroup += obj.g;
1196             regex += obj.s;
1197             if (obj.g && obj.c) {
1198                 code += obj.c;
1199             }
1200         }
1201     }
1202
1203     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1204         + "{v = new Date(y, m, d, h, i, s);}\n"
1205         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1206         + "{v = new Date(y, m, d, h, i);}\n"
1207         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1208         + "{v = new Date(y, m, d, h);}\n"
1209         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1210         + "{v = new Date(y, m, d);}\n"
1211         + "else if (y >= 0 && m >= 0)\n"
1212         + "{v = new Date(y, m);}\n"
1213         + "else if (y >= 0)\n"
1214         + "{v = new Date(y);}\n"
1215         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1216         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1217         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1218         + ";}";
1219
1220     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1221     /** eval:var:zzzzzzzzzzzzz */
1222     eval(code);
1223 };
1224
1225 // private
1226 Date.formatCodeToRegex = function(character, currentGroup) {
1227     switch (character) {
1228     case "D":
1229         return {g:0,
1230         c:null,
1231         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1232     case "j":
1233         return {g:1,
1234             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1235             s:"(\\d{1,2})"}; // day of month without leading zeroes
1236     case "d":
1237         return {g:1,
1238             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1239             s:"(\\d{2})"}; // day of month with leading zeroes
1240     case "l":
1241         return {g:0,
1242             c:null,
1243             s:"(?:" + Date.dayNames.join("|") + ")"};
1244     case "S":
1245         return {g:0,
1246             c:null,
1247             s:"(?:st|nd|rd|th)"};
1248     case "w":
1249         return {g:0,
1250             c:null,
1251             s:"\\d"};
1252     case "z":
1253         return {g:0,
1254             c:null,
1255             s:"(?:\\d{1,3})"};
1256     case "W":
1257         return {g:0,
1258             c:null,
1259             s:"(?:\\d{2})"};
1260     case "F":
1261         return {g:1,
1262             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1263             s:"(" + Date.monthNames.join("|") + ")"};
1264     case "M":
1265         return {g:1,
1266             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1267             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1268     case "n":
1269         return {g:1,
1270             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1271             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1272     case "m":
1273         return {g:1,
1274             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1275             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1276     case "t":
1277         return {g:0,
1278             c:null,
1279             s:"\\d{1,2}"};
1280     case "L":
1281         return {g:0,
1282             c:null,
1283             s:"(?:1|0)"};
1284     case "Y":
1285         return {g:1,
1286             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1287             s:"(\\d{4})"};
1288     case "y":
1289         return {g:1,
1290             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1291                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1292             s:"(\\d{1,2})"};
1293     case "a":
1294         return {g:1,
1295             c:"if (results[" + currentGroup + "] == 'am') {\n"
1296                 + "if (h == 12) { h = 0; }\n"
1297                 + "} else { if (h < 12) { h += 12; }}",
1298             s:"(am|pm)"};
1299     case "A":
1300         return {g:1,
1301             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1302                 + "if (h == 12) { h = 0; }\n"
1303                 + "} else { if (h < 12) { h += 12; }}",
1304             s:"(AM|PM)"};
1305     case "g":
1306     case "G":
1307         return {g:1,
1308             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1309             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1310     case "h":
1311     case "H":
1312         return {g:1,
1313             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1314             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1315     case "i":
1316         return {g:1,
1317             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1318             s:"(\\d{2})"};
1319     case "s":
1320         return {g:1,
1321             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1322             s:"(\\d{2})"};
1323     case "O":
1324         return {g:1,
1325             c:[
1326                 "o = results[", currentGroup, "];\n",
1327                 "var sn = o.substring(0,1);\n", // get + / - sign
1328                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1329                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1330                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1331                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1332             ].join(""),
1333             s:"([+\-]\\d{4})"};
1334     case "T":
1335         return {g:0,
1336             c:null,
1337             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1338     case "Z":
1339         return {g:1,
1340             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1341                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1342             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1343     default:
1344         return {g:0,
1345             c:null,
1346             s:String.escape(character)};
1347     }
1348 };
1349
1350 /**
1351  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1352  * @return {String} The abbreviated timezone name (e.g. 'CST')
1353  */
1354 Date.prototype.getTimezone = function() {
1355     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1356 };
1357
1358 /**
1359  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1360  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1361  */
1362 Date.prototype.getGMTOffset = function() {
1363     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1364         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1365         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1366 };
1367
1368 /**
1369  * Get the numeric day number of the year, adjusted for leap year.
1370  * @return {Number} 0 through 364 (365 in leap years)
1371  */
1372 Date.prototype.getDayOfYear = function() {
1373     var num = 0;
1374     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1375     for (var i = 0; i < this.getMonth(); ++i) {
1376         num += Date.daysInMonth[i];
1377     }
1378     return num + this.getDate() - 1;
1379 };
1380
1381 /**
1382  * Get the string representation of the numeric week number of the year
1383  * (equivalent to the format specifier 'W').
1384  * @return {String} '00' through '52'
1385  */
1386 Date.prototype.getWeekOfYear = function() {
1387     // Skip to Thursday of this week
1388     var now = this.getDayOfYear() + (4 - this.getDay());
1389     // Find the first Thursday of the year
1390     var jan1 = new Date(this.getFullYear(), 0, 1);
1391     var then = (7 - jan1.getDay() + 4);
1392     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1393 };
1394
1395 /**
1396  * Whether or not the current date is in a leap year.
1397  * @return {Boolean} True if the current date is in a leap year, else false
1398  */
1399 Date.prototype.isLeapYear = function() {
1400     var year = this.getFullYear();
1401     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1402 };
1403
1404 /**
1405  * Get the first day of the current month, adjusted for leap year.  The returned value
1406  * is the numeric day index within the week (0-6) which can be used in conjunction with
1407  * the {@link #monthNames} array to retrieve the textual day name.
1408  * Example:
1409  *<pre><code>
1410 var dt = new Date('1/10/2007');
1411 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1412 </code></pre>
1413  * @return {Number} The day number (0-6)
1414  */
1415 Date.prototype.getFirstDayOfMonth = function() {
1416     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1417     return (day < 0) ? (day + 7) : day;
1418 };
1419
1420 /**
1421  * Get the last day of the current month, adjusted for leap year.  The returned value
1422  * is the numeric day index within the week (0-6) which can be used in conjunction with
1423  * the {@link #monthNames} array to retrieve the textual day name.
1424  * Example:
1425  *<pre><code>
1426 var dt = new Date('1/10/2007');
1427 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1428 </code></pre>
1429  * @return {Number} The day number (0-6)
1430  */
1431 Date.prototype.getLastDayOfMonth = function() {
1432     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1433     return (day < 0) ? (day + 7) : day;
1434 };
1435
1436
1437 /**
1438  * Get the first date of this date's month
1439  * @return {Date}
1440  */
1441 Date.prototype.getFirstDateOfMonth = function() {
1442     return new Date(this.getFullYear(), this.getMonth(), 1);
1443 };
1444
1445 /**
1446  * Get the last date of this date's month
1447  * @return {Date}
1448  */
1449 Date.prototype.getLastDateOfMonth = function() {
1450     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1451 };
1452 /**
1453  * Get the number of days in the current month, adjusted for leap year.
1454  * @return {Number} The number of days in the month
1455  */
1456 Date.prototype.getDaysInMonth = function() {
1457     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1458     return Date.daysInMonth[this.getMonth()];
1459 };
1460
1461 /**
1462  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1463  * @return {String} 'st, 'nd', 'rd' or 'th'
1464  */
1465 Date.prototype.getSuffix = function() {
1466     switch (this.getDate()) {
1467         case 1:
1468         case 21:
1469         case 31:
1470             return "st";
1471         case 2:
1472         case 22:
1473             return "nd";
1474         case 3:
1475         case 23:
1476             return "rd";
1477         default:
1478             return "th";
1479     }
1480 };
1481
1482 // private
1483 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1484
1485 /**
1486  * An array of textual month names.
1487  * Override these values for international dates, for example...
1488  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1489  * @type Array
1490  * @static
1491  */
1492 Date.monthNames =
1493    ["January",
1494     "February",
1495     "March",
1496     "April",
1497     "May",
1498     "June",
1499     "July",
1500     "August",
1501     "September",
1502     "October",
1503     "November",
1504     "December"];
1505
1506 /**
1507  * An array of textual day names.
1508  * Override these values for international dates, for example...
1509  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1510  * @type Array
1511  * @static
1512  */
1513 Date.dayNames =
1514    ["Sunday",
1515     "Monday",
1516     "Tuesday",
1517     "Wednesday",
1518     "Thursday",
1519     "Friday",
1520     "Saturday"];
1521
1522 // private
1523 Date.y2kYear = 50;
1524 // private
1525 Date.monthNumbers = {
1526     Jan:0,
1527     Feb:1,
1528     Mar:2,
1529     Apr:3,
1530     May:4,
1531     Jun:5,
1532     Jul:6,
1533     Aug:7,
1534     Sep:8,
1535     Oct:9,
1536     Nov:10,
1537     Dec:11};
1538
1539 /**
1540  * Creates and returns a new Date instance with the exact same date value as the called instance.
1541  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1542  * variable will also be changed.  When the intention is to create a new variable that will not
1543  * modify the original instance, you should create a clone.
1544  *
1545  * Example of correctly cloning a date:
1546  * <pre><code>
1547 //wrong way:
1548 var orig = new Date('10/1/2006');
1549 var copy = orig;
1550 copy.setDate(5);
1551 document.write(orig);  //returns 'Thu Oct 05 2006'!
1552
1553 //correct way:
1554 var orig = new Date('10/1/2006');
1555 var copy = orig.clone();
1556 copy.setDate(5);
1557 document.write(orig);  //returns 'Thu Oct 01 2006'
1558 </code></pre>
1559  * @return {Date} The new Date instance
1560  */
1561 Date.prototype.clone = function() {
1562         return new Date(this.getTime());
1563 };
1564
1565 /**
1566  * Clears any time information from this date
1567  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1568  @return {Date} this or the clone
1569  */
1570 Date.prototype.clearTime = function(clone){
1571     if(clone){
1572         return this.clone().clearTime();
1573     }
1574     this.setHours(0);
1575     this.setMinutes(0);
1576     this.setSeconds(0);
1577     this.setMilliseconds(0);
1578     return this;
1579 };
1580
1581 // private
1582 // safari setMonth is broken
1583 if(Roo.isSafari){
1584     Date.brokenSetMonth = Date.prototype.setMonth;
1585         Date.prototype.setMonth = function(num){
1586                 if(num <= -1){
1587                         var n = Math.ceil(-num);
1588                         var back_year = Math.ceil(n/12);
1589                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1590                         this.setFullYear(this.getFullYear() - back_year);
1591                         return Date.brokenSetMonth.call(this, month);
1592                 } else {
1593                         return Date.brokenSetMonth.apply(this, arguments);
1594                 }
1595         };
1596 }
1597
1598 /** Date interval constant 
1599 * @static 
1600 * @type String */
1601 Date.MILLI = "ms";
1602 /** Date interval constant 
1603 * @static 
1604 * @type String */
1605 Date.SECOND = "s";
1606 /** Date interval constant 
1607 * @static 
1608 * @type String */
1609 Date.MINUTE = "mi";
1610 /** Date interval constant 
1611 * @static 
1612 * @type String */
1613 Date.HOUR = "h";
1614 /** Date interval constant 
1615 * @static 
1616 * @type String */
1617 Date.DAY = "d";
1618 /** Date interval constant 
1619 * @static 
1620 * @type String */
1621 Date.MONTH = "mo";
1622 /** Date interval constant 
1623 * @static 
1624 * @type String */
1625 Date.YEAR = "y";
1626
1627 /**
1628  * Provides a convenient method of performing basic date arithmetic.  This method
1629  * does not modify the Date instance being called - it creates and returns
1630  * a new Date instance containing the resulting date value.
1631  *
1632  * Examples:
1633  * <pre><code>
1634 //Basic usage:
1635 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1636 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1637
1638 //Negative values will subtract correctly:
1639 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1640 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1641
1642 //You can even chain several calls together in one line!
1643 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1644 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1645  </code></pre>
1646  *
1647  * @param {String} interval   A valid date interval enum value
1648  * @param {Number} value      The amount to add to the current date
1649  * @return {Date} The new Date instance
1650  */
1651 Date.prototype.add = function(interval, value){
1652   var d = this.clone();
1653   if (!interval || value === 0) return d;
1654   switch(interval.toLowerCase()){
1655     case Date.MILLI:
1656       d.setMilliseconds(this.getMilliseconds() + value);
1657       break;
1658     case Date.SECOND:
1659       d.setSeconds(this.getSeconds() + value);
1660       break;
1661     case Date.MINUTE:
1662       d.setMinutes(this.getMinutes() + value);
1663       break;
1664     case Date.HOUR:
1665       d.setHours(this.getHours() + value);
1666       break;
1667     case Date.DAY:
1668       d.setDate(this.getDate() + value);
1669       break;
1670     case Date.MONTH:
1671       var day = this.getDate();
1672       if(day > 28){
1673           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1674       }
1675       d.setDate(day);
1676       d.setMonth(this.getMonth() + value);
1677       break;
1678     case Date.YEAR:
1679       d.setFullYear(this.getFullYear() + value);
1680       break;
1681   }
1682   return d;
1683 };/*
1684  * Based on:
1685  * Ext JS Library 1.1.1
1686  * Copyright(c) 2006-2007, Ext JS, LLC.
1687  *
1688  * Originally Released Under LGPL - original licence link has changed is not relivant.
1689  *
1690  * Fork - LGPL
1691  * <script type="text/javascript">
1692  */
1693
1694 Roo.lib.Dom = {
1695     getViewWidth : function(full) {
1696         return full ? this.getDocumentWidth() : this.getViewportWidth();
1697     },
1698
1699     getViewHeight : function(full) {
1700         return full ? this.getDocumentHeight() : this.getViewportHeight();
1701     },
1702
1703     getDocumentHeight: function() {
1704         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1705         return Math.max(scrollHeight, this.getViewportHeight());
1706     },
1707
1708     getDocumentWidth: function() {
1709         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1710         return Math.max(scrollWidth, this.getViewportWidth());
1711     },
1712
1713     getViewportHeight: function() {
1714         var height = self.innerHeight;
1715         var mode = document.compatMode;
1716
1717         if ((mode || Roo.isIE) && !Roo.isOpera) {
1718             height = (mode == "CSS1Compat") ?
1719                      document.documentElement.clientHeight :
1720                      document.body.clientHeight;
1721         }
1722
1723         return height;
1724     },
1725
1726     getViewportWidth: function() {
1727         var width = self.innerWidth;
1728         var mode = document.compatMode;
1729
1730         if (mode || Roo.isIE) {
1731             width = (mode == "CSS1Compat") ?
1732                     document.documentElement.clientWidth :
1733                     document.body.clientWidth;
1734         }
1735         return width;
1736     },
1737
1738     isAncestor : function(p, c) {
1739         p = Roo.getDom(p);
1740         c = Roo.getDom(c);
1741         if (!p || !c) {
1742             return false;
1743         }
1744
1745         if (p.contains && !Roo.isSafari) {
1746             return p.contains(c);
1747         } else if (p.compareDocumentPosition) {
1748             return !!(p.compareDocumentPosition(c) & 16);
1749         } else {
1750             var parent = c.parentNode;
1751             while (parent) {
1752                 if (parent == p) {
1753                     return true;
1754                 }
1755                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1756                     return false;
1757                 }
1758                 parent = parent.parentNode;
1759             }
1760             return false;
1761         }
1762     },
1763
1764     getRegion : function(el) {
1765         return Roo.lib.Region.getRegion(el);
1766     },
1767
1768     getY : function(el) {
1769         return this.getXY(el)[1];
1770     },
1771
1772     getX : function(el) {
1773         return this.getXY(el)[0];
1774     },
1775
1776     getXY : function(el) {
1777         var p, pe, b, scroll, bd = document.body;
1778         el = Roo.getDom(el);
1779         var fly = Roo.lib.AnimBase.fly;
1780         if (el.getBoundingClientRect) {
1781             b = el.getBoundingClientRect();
1782             scroll = fly(document).getScroll();
1783             return [b.left + scroll.left, b.top + scroll.top];
1784         }
1785         var x = 0, y = 0;
1786
1787         p = el;
1788
1789         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1790
1791         while (p) {
1792
1793             x += p.offsetLeft;
1794             y += p.offsetTop;
1795
1796             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1797                 hasAbsolute = true;
1798             }
1799
1800             if (Roo.isGecko) {
1801                 pe = fly(p);
1802
1803                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1804                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1805
1806
1807                 x += bl;
1808                 y += bt;
1809
1810
1811                 if (p != el && pe.getStyle('overflow') != 'visible') {
1812                     x += bl;
1813                     y += bt;
1814                 }
1815             }
1816             p = p.offsetParent;
1817         }
1818
1819         if (Roo.isSafari && hasAbsolute) {
1820             x -= bd.offsetLeft;
1821             y -= bd.offsetTop;
1822         }
1823
1824         if (Roo.isGecko && !hasAbsolute) {
1825             var dbd = fly(bd);
1826             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1827             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1828         }
1829
1830         p = el.parentNode;
1831         while (p && p != bd) {
1832             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1833                 x -= p.scrollLeft;
1834                 y -= p.scrollTop;
1835             }
1836             p = p.parentNode;
1837         }
1838         return [x, y];
1839     },
1840  
1841   
1842
1843
1844     setXY : function(el, xy) {
1845         el = Roo.fly(el, '_setXY');
1846         el.position();
1847         var pts = el.translatePoints(xy);
1848         if (xy[0] !== false) {
1849             el.dom.style.left = pts.left + "px";
1850         }
1851         if (xy[1] !== false) {
1852             el.dom.style.top = pts.top + "px";
1853         }
1854     },
1855
1856     setX : function(el, x) {
1857         this.setXY(el, [x, false]);
1858     },
1859
1860     setY : function(el, y) {
1861         this.setXY(el, [false, y]);
1862     }
1863 };
1864 /*
1865  * Portions of this file are based on pieces of Yahoo User Interface Library
1866  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1867  * YUI licensed under the BSD License:
1868  * http://developer.yahoo.net/yui/license.txt
1869  * <script type="text/javascript">
1870  *
1871  */
1872
1873 Roo.lib.Event = function() {
1874     var loadComplete = false;
1875     var listeners = [];
1876     var unloadListeners = [];
1877     var retryCount = 0;
1878     var onAvailStack = [];
1879     var counter = 0;
1880     var lastError = null;
1881
1882     return {
1883         POLL_RETRYS: 200,
1884         POLL_INTERVAL: 20,
1885         EL: 0,
1886         TYPE: 1,
1887         FN: 2,
1888         WFN: 3,
1889         OBJ: 3,
1890         ADJ_SCOPE: 4,
1891         _interval: null,
1892
1893         startInterval: function() {
1894             if (!this._interval) {
1895                 var self = this;
1896                 var callback = function() {
1897                     self._tryPreloadAttach();
1898                 };
1899                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1900
1901             }
1902         },
1903
1904         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1905             onAvailStack.push({ id:         p_id,
1906                 fn:         p_fn,
1907                 obj:        p_obj,
1908                 override:   p_override,
1909                 checkReady: false    });
1910
1911             retryCount = this.POLL_RETRYS;
1912             this.startInterval();
1913         },
1914
1915
1916         addListener: function(el, eventName, fn) {
1917             el = Roo.getDom(el);
1918             if (!el || !fn) {
1919                 return false;
1920             }
1921
1922             if ("unload" == eventName) {
1923                 unloadListeners[unloadListeners.length] =
1924                 [el, eventName, fn];
1925                 return true;
1926             }
1927
1928             var wrappedFn = function(e) {
1929                 return fn(Roo.lib.Event.getEvent(e));
1930             };
1931
1932             var li = [el, eventName, fn, wrappedFn];
1933
1934             var index = listeners.length;
1935             listeners[index] = li;
1936
1937             this.doAdd(el, eventName, wrappedFn, false);
1938             return true;
1939
1940         },
1941
1942
1943         removeListener: function(el, eventName, fn) {
1944             var i, len;
1945
1946             el = Roo.getDom(el);
1947
1948             if(!fn) {
1949                 return this.purgeElement(el, false, eventName);
1950             }
1951
1952
1953             if ("unload" == eventName) {
1954
1955                 for (i = 0,len = unloadListeners.length; i < len; i++) {
1956                     var li = unloadListeners[i];
1957                     if (li &&
1958                         li[0] == el &&
1959                         li[1] == eventName &&
1960                         li[2] == fn) {
1961                         unloadListeners.splice(i, 1);
1962                         return true;
1963                     }
1964                 }
1965
1966                 return false;
1967             }
1968
1969             var cacheItem = null;
1970
1971
1972             var index = arguments[3];
1973
1974             if ("undefined" == typeof index) {
1975                 index = this._getCacheIndex(el, eventName, fn);
1976             }
1977
1978             if (index >= 0) {
1979                 cacheItem = listeners[index];
1980             }
1981
1982             if (!el || !cacheItem) {
1983                 return false;
1984             }
1985
1986             this.doRemove(el, eventName, cacheItem[this.WFN], false);
1987
1988             delete listeners[index][this.WFN];
1989             delete listeners[index][this.FN];
1990             listeners.splice(index, 1);
1991
1992             return true;
1993
1994         },
1995
1996
1997         getTarget: function(ev, resolveTextNode) {
1998             ev = ev.browserEvent || ev;
1999             var t = ev.target || ev.srcElement;
2000             return this.resolveTextNode(t);
2001         },
2002
2003
2004         resolveTextNode: function(node) {
2005             if (Roo.isSafari && node && 3 == node.nodeType) {
2006                 return node.parentNode;
2007             } else {
2008                 return node;
2009             }
2010         },
2011
2012
2013         getPageX: function(ev) {
2014             ev = ev.browserEvent || ev;
2015             var x = ev.pageX;
2016             if (!x && 0 !== x) {
2017                 x = ev.clientX || 0;
2018
2019                 if (Roo.isIE) {
2020                     x += this.getScroll()[1];
2021                 }
2022             }
2023
2024             return x;
2025         },
2026
2027
2028         getPageY: function(ev) {
2029             ev = ev.browserEvent || ev;
2030             var y = ev.pageY;
2031             if (!y && 0 !== y) {
2032                 y = ev.clientY || 0;
2033
2034                 if (Roo.isIE) {
2035                     y += this.getScroll()[0];
2036                 }
2037             }
2038
2039
2040             return y;
2041         },
2042
2043
2044         getXY: function(ev) {
2045             ev = ev.browserEvent || ev;
2046             return [this.getPageX(ev), this.getPageY(ev)];
2047         },
2048
2049
2050         getRelatedTarget: function(ev) {
2051             ev = ev.browserEvent || ev;
2052             var t = ev.relatedTarget;
2053             if (!t) {
2054                 if (ev.type == "mouseout") {
2055                     t = ev.toElement;
2056                 } else if (ev.type == "mouseover") {
2057                     t = ev.fromElement;
2058                 }
2059             }
2060
2061             return this.resolveTextNode(t);
2062         },
2063
2064
2065         getTime: function(ev) {
2066             ev = ev.browserEvent || ev;
2067             if (!ev.time) {
2068                 var t = new Date().getTime();
2069                 try {
2070                     ev.time = t;
2071                 } catch(ex) {
2072                     this.lastError = ex;
2073                     return t;
2074                 }
2075             }
2076
2077             return ev.time;
2078         },
2079
2080
2081         stopEvent: function(ev) {
2082             this.stopPropagation(ev);
2083             this.preventDefault(ev);
2084         },
2085
2086
2087         stopPropagation: function(ev) {
2088             ev = ev.browserEvent || ev;
2089             if (ev.stopPropagation) {
2090                 ev.stopPropagation();
2091             } else {
2092                 ev.cancelBubble = true;
2093             }
2094         },
2095
2096
2097         preventDefault: function(ev) {
2098             ev = ev.browserEvent || ev;
2099             if(ev.preventDefault) {
2100                 ev.preventDefault();
2101             } else {
2102                 ev.returnValue = false;
2103             }
2104         },
2105
2106
2107         getEvent: function(e) {
2108             var ev = e || window.event;
2109             if (!ev) {
2110                 var c = this.getEvent.caller;
2111                 while (c) {
2112                     ev = c.arguments[0];
2113                     if (ev && Event == ev.constructor) {
2114                         break;
2115                     }
2116                     c = c.caller;
2117                 }
2118             }
2119             return ev;
2120         },
2121
2122
2123         getCharCode: function(ev) {
2124             ev = ev.browserEvent || ev;
2125             return ev.charCode || ev.keyCode || 0;
2126         },
2127
2128
2129         _getCacheIndex: function(el, eventName, fn) {
2130             for (var i = 0,len = listeners.length; i < len; ++i) {
2131                 var li = listeners[i];
2132                 if (li &&
2133                     li[this.FN] == fn &&
2134                     li[this.EL] == el &&
2135                     li[this.TYPE] == eventName) {
2136                     return i;
2137                 }
2138             }
2139
2140             return -1;
2141         },
2142
2143
2144         elCache: {},
2145
2146
2147         getEl: function(id) {
2148             return document.getElementById(id);
2149         },
2150
2151
2152         clearCache: function() {
2153         },
2154
2155
2156         _load: function(e) {
2157             loadComplete = true;
2158             var EU = Roo.lib.Event;
2159
2160
2161             if (Roo.isIE) {
2162                 EU.doRemove(window, "load", EU._load);
2163             }
2164         },
2165
2166
2167         _tryPreloadAttach: function() {
2168
2169             if (this.locked) {
2170                 return false;
2171             }
2172
2173             this.locked = true;
2174
2175
2176             var tryAgain = !loadComplete;
2177             if (!tryAgain) {
2178                 tryAgain = (retryCount > 0);
2179             }
2180
2181
2182             var notAvail = [];
2183             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2184                 var item = onAvailStack[i];
2185                 if (item) {
2186                     var el = this.getEl(item.id);
2187
2188                     if (el) {
2189                         if (!item.checkReady ||
2190                             loadComplete ||
2191                             el.nextSibling ||
2192                             (document && document.body)) {
2193
2194                             var scope = el;
2195                             if (item.override) {
2196                                 if (item.override === true) {
2197                                     scope = item.obj;
2198                                 } else {
2199                                     scope = item.override;
2200                                 }
2201                             }
2202                             item.fn.call(scope, item.obj);
2203                             onAvailStack[i] = null;
2204                         }
2205                     } else {
2206                         notAvail.push(item);
2207                     }
2208                 }
2209             }
2210
2211             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2212
2213             if (tryAgain) {
2214
2215                 this.startInterval();
2216             } else {
2217                 clearInterval(this._interval);
2218                 this._interval = null;
2219             }
2220
2221             this.locked = false;
2222
2223             return true;
2224
2225         },
2226
2227
2228         purgeElement: function(el, recurse, eventName) {
2229             var elListeners = this.getListeners(el, eventName);
2230             if (elListeners) {
2231                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2232                     var l = elListeners[i];
2233                     this.removeListener(el, l.type, l.fn);
2234                 }
2235             }
2236
2237             if (recurse && el && el.childNodes) {
2238                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2239                     this.purgeElement(el.childNodes[i], recurse, eventName);
2240                 }
2241             }
2242         },
2243
2244
2245         getListeners: function(el, eventName) {
2246             var results = [], searchLists;
2247             if (!eventName) {
2248                 searchLists = [listeners, unloadListeners];
2249             } else if (eventName == "unload") {
2250                 searchLists = [unloadListeners];
2251             } else {
2252                 searchLists = [listeners];
2253             }
2254
2255             for (var j = 0; j < searchLists.length; ++j) {
2256                 var searchList = searchLists[j];
2257                 if (searchList && searchList.length > 0) {
2258                     for (var i = 0,len = searchList.length; i < len; ++i) {
2259                         var l = searchList[i];
2260                         if (l && l[this.EL] === el &&
2261                             (!eventName || eventName === l[this.TYPE])) {
2262                             results.push({
2263                                 type:   l[this.TYPE],
2264                                 fn:     l[this.FN],
2265                                 obj:    l[this.OBJ],
2266                                 adjust: l[this.ADJ_SCOPE],
2267                                 index:  i
2268                             });
2269                         }
2270                     }
2271                 }
2272             }
2273
2274             return (results.length) ? results : null;
2275         },
2276
2277
2278         _unload: function(e) {
2279
2280             var EU = Roo.lib.Event, i, j, l, len, index;
2281
2282             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2283                 l = unloadListeners[i];
2284                 if (l) {
2285                     var scope = window;
2286                     if (l[EU.ADJ_SCOPE]) {
2287                         if (l[EU.ADJ_SCOPE] === true) {
2288                             scope = l[EU.OBJ];
2289                         } else {
2290                             scope = l[EU.ADJ_SCOPE];
2291                         }
2292                     }
2293                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2294                     unloadListeners[i] = null;
2295                     l = null;
2296                     scope = null;
2297                 }
2298             }
2299
2300             unloadListeners = null;
2301
2302             if (listeners && listeners.length > 0) {
2303                 j = listeners.length;
2304                 while (j) {
2305                     index = j - 1;
2306                     l = listeners[index];
2307                     if (l) {
2308                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2309                                 l[EU.FN], index);
2310                     }
2311                     j = j - 1;
2312                 }
2313                 l = null;
2314
2315                 EU.clearCache();
2316             }
2317
2318             EU.doRemove(window, "unload", EU._unload);
2319
2320         },
2321
2322
2323         getScroll: function() {
2324             var dd = document.documentElement, db = document.body;
2325             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2326                 return [dd.scrollTop, dd.scrollLeft];
2327             } else if (db) {
2328                 return [db.scrollTop, db.scrollLeft];
2329             } else {
2330                 return [0, 0];
2331             }
2332         },
2333
2334
2335         doAdd: function () {
2336             if (window.addEventListener) {
2337                 return function(el, eventName, fn, capture) {
2338                     el.addEventListener(eventName, fn, (capture));
2339                 };
2340             } else if (window.attachEvent) {
2341                 return function(el, eventName, fn, capture) {
2342                     el.attachEvent("on" + eventName, fn);
2343                 };
2344             } else {
2345                 return function() {
2346                 };
2347             }
2348         }(),
2349
2350
2351         doRemove: function() {
2352             if (window.removeEventListener) {
2353                 return function (el, eventName, fn, capture) {
2354                     el.removeEventListener(eventName, fn, (capture));
2355                 };
2356             } else if (window.detachEvent) {
2357                 return function (el, eventName, fn) {
2358                     el.detachEvent("on" + eventName, fn);
2359                 };
2360             } else {
2361                 return function() {
2362                 };
2363             }
2364         }()
2365     };
2366     
2367 }();
2368 (function() {     
2369    
2370     var E = Roo.lib.Event;
2371     E.on = E.addListener;
2372     E.un = E.removeListener;
2373
2374     if (document && document.body) {
2375         E._load();
2376     } else {
2377         E.doAdd(window, "load", E._load);
2378     }
2379     E.doAdd(window, "unload", E._unload);
2380     E._tryPreloadAttach();
2381 })();
2382
2383 /*
2384  * Portions of this file are based on pieces of Yahoo User Interface Library
2385  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2386  * YUI licensed under the BSD License:
2387  * http://developer.yahoo.net/yui/license.txt
2388  * <script type="text/javascript">
2389  *
2390  */
2391
2392 (function() {
2393     
2394     Roo.lib.Ajax = {
2395         request : function(method, uri, cb, data, options) {
2396             if(options){
2397                 var hs = options.headers;
2398                 if(hs){
2399                     for(var h in hs){
2400                         if(hs.hasOwnProperty(h)){
2401                             this.initHeader(h, hs[h], false);
2402                         }
2403                     }
2404                 }
2405                 if(options.xmlData){
2406                     this.initHeader('Content-Type', 'text/xml', false);
2407                     method = 'POST';
2408                     data = options.xmlData;
2409                 }
2410             }
2411
2412             return this.asyncRequest(method, uri, cb, data);
2413         },
2414
2415         serializeForm : function(form) {
2416             if(typeof form == 'string') {
2417                 form = (document.getElementById(form) || document.forms[form]);
2418             }
2419
2420             var el, name, val, disabled, data = '', hasSubmit = false;
2421             for (var i = 0; i < form.elements.length; i++) {
2422                 el = form.elements[i];
2423                 disabled = form.elements[i].disabled;
2424                 name = form.elements[i].name;
2425                 val = form.elements[i].value;
2426
2427                 if (!disabled && name){
2428                     switch (el.type)
2429                             {
2430                         case 'select-one':
2431                         case 'select-multiple':
2432                             for (var j = 0; j < el.options.length; j++) {
2433                                 if (el.options[j].selected) {
2434                                     if (Roo.isIE) {
2435                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2436                                     }
2437                                     else {
2438                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2439                                     }
2440                                 }
2441                             }
2442                             break;
2443                         case 'radio':
2444                         case 'checkbox':
2445                             if (el.checked) {
2446                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2447                             }
2448                             break;
2449                         case 'file':
2450
2451                         case undefined:
2452
2453                         case 'reset':
2454
2455                         case 'button':
2456
2457                             break;
2458                         case 'submit':
2459                             if(hasSubmit == false) {
2460                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2461                                 hasSubmit = true;
2462                             }
2463                             break;
2464                         default:
2465                             data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2466                             break;
2467                     }
2468                 }
2469             }
2470             data = data.substr(0, data.length - 1);
2471             return data;
2472         },
2473
2474         headers:{},
2475
2476         hasHeaders:false,
2477
2478         useDefaultHeader:true,
2479
2480         defaultPostHeader:'application/x-www-form-urlencoded',
2481
2482         useDefaultXhrHeader:true,
2483
2484         defaultXhrHeader:'XMLHttpRequest',
2485
2486         hasDefaultHeaders:true,
2487
2488         defaultHeaders:{},
2489
2490         poll:{},
2491
2492         timeout:{},
2493
2494         pollInterval:50,
2495
2496         transactionId:0,
2497
2498         setProgId:function(id)
2499         {
2500             this.activeX.unshift(id);
2501         },
2502
2503         setDefaultPostHeader:function(b)
2504         {
2505             this.useDefaultHeader = b;
2506         },
2507
2508         setDefaultXhrHeader:function(b)
2509         {
2510             this.useDefaultXhrHeader = b;
2511         },
2512
2513         setPollingInterval:function(i)
2514         {
2515             if (typeof i == 'number' && isFinite(i)) {
2516                 this.pollInterval = i;
2517             }
2518         },
2519
2520         createXhrObject:function(transactionId)
2521         {
2522             var obj,http;
2523             try
2524             {
2525
2526                 http = new XMLHttpRequest();
2527
2528                 obj = { conn:http, tId:transactionId };
2529             }
2530             catch(e)
2531             {
2532                 for (var i = 0; i < this.activeX.length; ++i) {
2533                     try
2534                     {
2535
2536                         http = new ActiveXObject(this.activeX[i]);
2537
2538                         obj = { conn:http, tId:transactionId };
2539                         break;
2540                     }
2541                     catch(e) {
2542                     }
2543                 }
2544             }
2545             finally
2546             {
2547                 return obj;
2548             }
2549         },
2550
2551         getConnectionObject:function()
2552         {
2553             var o;
2554             var tId = this.transactionId;
2555
2556             try
2557             {
2558                 o = this.createXhrObject(tId);
2559                 if (o) {
2560                     this.transactionId++;
2561                 }
2562             }
2563             catch(e) {
2564             }
2565             finally
2566             {
2567                 return o;
2568             }
2569         },
2570
2571         asyncRequest:function(method, uri, callback, postData)
2572         {
2573             var o = this.getConnectionObject();
2574
2575             if (!o) {
2576                 return null;
2577             }
2578             else {
2579                 o.conn.open(method, uri, true);
2580
2581                 if (this.useDefaultXhrHeader) {
2582                     if (!this.defaultHeaders['X-Requested-With']) {
2583                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2584                     }
2585                 }
2586
2587                 if(postData && this.useDefaultHeader){
2588                     this.initHeader('Content-Type', this.defaultPostHeader);
2589                 }
2590
2591                  if (this.hasDefaultHeaders || this.hasHeaders) {
2592                     this.setHeader(o);
2593                 }
2594
2595                 this.handleReadyState(o, callback);
2596                 o.conn.send(postData || null);
2597
2598                 return o;
2599             }
2600         },
2601
2602         handleReadyState:function(o, callback)
2603         {
2604             var oConn = this;
2605
2606             if (callback && callback.timeout) {
2607                 this.timeout[o.tId] = window.setTimeout(function() {
2608                     oConn.abort(o, callback, true);
2609                 }, callback.timeout);
2610             }
2611
2612             this.poll[o.tId] = window.setInterval(
2613                     function() {
2614                         if (o.conn && o.conn.readyState == 4) {
2615                             window.clearInterval(oConn.poll[o.tId]);
2616                             delete oConn.poll[o.tId];
2617
2618                             if(callback && callback.timeout) {
2619                                 window.clearTimeout(oConn.timeout[o.tId]);
2620                                 delete oConn.timeout[o.tId];
2621                             }
2622
2623                             oConn.handleTransactionResponse(o, callback);
2624                         }
2625                     }
2626                     , this.pollInterval);
2627         },
2628
2629         handleTransactionResponse:function(o, callback, isAbort)
2630         {
2631
2632             if (!callback) {
2633                 this.releaseObject(o);
2634                 return;
2635             }
2636
2637             var httpStatus, responseObject;
2638
2639             try
2640             {
2641                 if (o.conn.status !== undefined && o.conn.status != 0) {
2642                     httpStatus = o.conn.status;
2643                 }
2644                 else {
2645                     httpStatus = 13030;
2646                 }
2647             }
2648             catch(e) {
2649
2650
2651                 httpStatus = 13030;
2652             }
2653
2654             if (httpStatus >= 200 && httpStatus < 300) {
2655                 responseObject = this.createResponseObject(o, callback.argument);
2656                 if (callback.success) {
2657                     if (!callback.scope) {
2658                         callback.success(responseObject);
2659                     }
2660                     else {
2661
2662
2663                         callback.success.apply(callback.scope, [responseObject]);
2664                     }
2665                 }
2666             }
2667             else {
2668                 switch (httpStatus) {
2669
2670                     case 12002:
2671                     case 12029:
2672                     case 12030:
2673                     case 12031:
2674                     case 12152:
2675                     case 13030:
2676                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2677                         if (callback.failure) {
2678                             if (!callback.scope) {
2679                                 callback.failure(responseObject);
2680                             }
2681                             else {
2682                                 callback.failure.apply(callback.scope, [responseObject]);
2683                             }
2684                         }
2685                         break;
2686                     default:
2687                         responseObject = this.createResponseObject(o, callback.argument);
2688                         if (callback.failure) {
2689                             if (!callback.scope) {
2690                                 callback.failure(responseObject);
2691                             }
2692                             else {
2693                                 callback.failure.apply(callback.scope, [responseObject]);
2694                             }
2695                         }
2696                 }
2697             }
2698
2699             this.releaseObject(o);
2700             responseObject = null;
2701         },
2702
2703         createResponseObject:function(o, callbackArg)
2704         {
2705             var obj = {};
2706             var headerObj = {};
2707
2708             try
2709             {
2710                 var headerStr = o.conn.getAllResponseHeaders();
2711                 var header = headerStr.split('\n');
2712                 for (var i = 0; i < header.length; i++) {
2713                     var delimitPos = header[i].indexOf(':');
2714                     if (delimitPos != -1) {
2715                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2716                     }
2717                 }
2718             }
2719             catch(e) {
2720             }
2721
2722             obj.tId = o.tId;
2723             obj.status = o.conn.status;
2724             obj.statusText = o.conn.statusText;
2725             obj.getResponseHeader = headerObj;
2726             obj.getAllResponseHeaders = headerStr;
2727             obj.responseText = o.conn.responseText;
2728             obj.responseXML = o.conn.responseXML;
2729
2730             if (typeof callbackArg !== undefined) {
2731                 obj.argument = callbackArg;
2732             }
2733
2734             return obj;
2735         },
2736
2737         createExceptionObject:function(tId, callbackArg, isAbort)
2738         {
2739             var COMM_CODE = 0;
2740             var COMM_ERROR = 'communication failure';
2741             var ABORT_CODE = -1;
2742             var ABORT_ERROR = 'transaction aborted';
2743
2744             var obj = {};
2745
2746             obj.tId = tId;
2747             if (isAbort) {
2748                 obj.status = ABORT_CODE;
2749                 obj.statusText = ABORT_ERROR;
2750             }
2751             else {
2752                 obj.status = COMM_CODE;
2753                 obj.statusText = COMM_ERROR;
2754             }
2755
2756             if (callbackArg) {
2757                 obj.argument = callbackArg;
2758             }
2759
2760             return obj;
2761         },
2762
2763         initHeader:function(label, value, isDefault)
2764         {
2765             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2766
2767             if (headerObj[label] === undefined) {
2768                 headerObj[label] = value;
2769             }
2770             else {
2771
2772
2773                 headerObj[label] = value + "," + headerObj[label];
2774             }
2775
2776             if (isDefault) {
2777                 this.hasDefaultHeaders = true;
2778             }
2779             else {
2780                 this.hasHeaders = true;
2781             }
2782         },
2783
2784
2785         setHeader:function(o)
2786         {
2787             if (this.hasDefaultHeaders) {
2788                 for (var prop in this.defaultHeaders) {
2789                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2790                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2791                     }
2792                 }
2793             }
2794
2795             if (this.hasHeaders) {
2796                 for (var prop in this.headers) {
2797                     if (this.headers.hasOwnProperty(prop)) {
2798                         o.conn.setRequestHeader(prop, this.headers[prop]);
2799                     }
2800                 }
2801                 this.headers = {};
2802                 this.hasHeaders = false;
2803             }
2804         },
2805
2806         resetDefaultHeaders:function() {
2807             delete this.defaultHeaders;
2808             this.defaultHeaders = {};
2809             this.hasDefaultHeaders = false;
2810         },
2811
2812         abort:function(o, callback, isTimeout)
2813         {
2814             if(this.isCallInProgress(o)) {
2815                 o.conn.abort();
2816                 window.clearInterval(this.poll[o.tId]);
2817                 delete this.poll[o.tId];
2818                 if (isTimeout) {
2819                     delete this.timeout[o.tId];
2820                 }
2821
2822                 this.handleTransactionResponse(o, callback, true);
2823
2824                 return true;
2825             }
2826             else {
2827                 return false;
2828             }
2829         },
2830
2831
2832         isCallInProgress:function(o)
2833         {
2834             if (o && o.conn) {
2835                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2836             }
2837             else {
2838
2839                 return false;
2840             }
2841         },
2842
2843
2844         releaseObject:function(o)
2845         {
2846
2847             o.conn = null;
2848
2849             o = null;
2850         },
2851
2852         activeX:[
2853         'MSXML2.XMLHTTP.3.0',
2854         'MSXML2.XMLHTTP',
2855         'Microsoft.XMLHTTP'
2856         ]
2857
2858
2859     };
2860 })();/*
2861  * Portions of this file are based on pieces of Yahoo User Interface Library
2862  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2863  * YUI licensed under the BSD License:
2864  * http://developer.yahoo.net/yui/license.txt
2865  * <script type="text/javascript">
2866  *
2867  */
2868
2869 Roo.lib.Region = function(t, r, b, l) {
2870     this.top = t;
2871     this[1] = t;
2872     this.right = r;
2873     this.bottom = b;
2874     this.left = l;
2875     this[0] = l;
2876 };
2877
2878
2879 Roo.lib.Region.prototype = {
2880     contains : function(region) {
2881         return ( region.left >= this.left &&
2882                  region.right <= this.right &&
2883                  region.top >= this.top &&
2884                  region.bottom <= this.bottom    );
2885
2886     },
2887
2888     getArea : function() {
2889         return ( (this.bottom - this.top) * (this.right - this.left) );
2890     },
2891
2892     intersect : function(region) {
2893         var t = Math.max(this.top, region.top);
2894         var r = Math.min(this.right, region.right);
2895         var b = Math.min(this.bottom, region.bottom);
2896         var l = Math.max(this.left, region.left);
2897
2898         if (b >= t && r >= l) {
2899             return new Roo.lib.Region(t, r, b, l);
2900         } else {
2901             return null;
2902         }
2903     },
2904     union : function(region) {
2905         var t = Math.min(this.top, region.top);
2906         var r = Math.max(this.right, region.right);
2907         var b = Math.max(this.bottom, region.bottom);
2908         var l = Math.min(this.left, region.left);
2909
2910         return new Roo.lib.Region(t, r, b, l);
2911     },
2912
2913     adjust : function(t, l, b, r) {
2914         this.top += t;
2915         this.left += l;
2916         this.right += r;
2917         this.bottom += b;
2918         return this;
2919     }
2920 };
2921
2922 Roo.lib.Region.getRegion = function(el) {
2923     var p = Roo.lib.Dom.getXY(el);
2924
2925     var t = p[1];
2926     var r = p[0] + el.offsetWidth;
2927     var b = p[1] + el.offsetHeight;
2928     var l = p[0];
2929
2930     return new Roo.lib.Region(t, r, b, l);
2931 };
2932 /*
2933  * Portions of this file are based on pieces of Yahoo User Interface Library
2934  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2935  * YUI licensed under the BSD License:
2936  * http://developer.yahoo.net/yui/license.txt
2937  * <script type="text/javascript">
2938  *
2939  */
2940 //@@dep Roo.lib.Region
2941
2942
2943 Roo.lib.Point = function(x, y) {
2944     if (x instanceof Array) {
2945         y = x[1];
2946         x = x[0];
2947     }
2948     this.x = this.right = this.left = this[0] = x;
2949     this.y = this.top = this.bottom = this[1] = y;
2950 };
2951
2952 Roo.lib.Point.prototype = new Roo.lib.Region();
2953 /*
2954  * Portions of this file are based on pieces of Yahoo User Interface Library
2955  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2956  * YUI licensed under the BSD License:
2957  * http://developer.yahoo.net/yui/license.txt
2958  * <script type="text/javascript">
2959  *
2960  */
2961  
2962 (function() {   
2963
2964     Roo.lib.Anim = {
2965         scroll : function(el, args, duration, easing, cb, scope) {
2966             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2967         },
2968
2969         motion : function(el, args, duration, easing, cb, scope) {
2970             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2971         },
2972
2973         color : function(el, args, duration, easing, cb, scope) {
2974             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2975         },
2976
2977         run : function(el, args, duration, easing, cb, scope, type) {
2978             type = type || Roo.lib.AnimBase;
2979             if (typeof easing == "string") {
2980                 easing = Roo.lib.Easing[easing];
2981             }
2982             var anim = new type(el, args, duration, easing);
2983             anim.animateX(function() {
2984                 Roo.callback(cb, scope);
2985             });
2986             return anim;
2987         }
2988     };
2989 })();/*
2990  * Portions of this file are based on pieces of Yahoo User Interface Library
2991  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2992  * YUI licensed under the BSD License:
2993  * http://developer.yahoo.net/yui/license.txt
2994  * <script type="text/javascript">
2995  *
2996  */
2997
2998 (function() {    
2999     var libFlyweight;
3000     
3001     function fly(el) {
3002         if (!libFlyweight) {
3003             libFlyweight = new Roo.Element.Flyweight();
3004         }
3005         libFlyweight.dom = el;
3006         return libFlyweight;
3007     }
3008
3009     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3010     
3011    
3012     
3013     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3014         if (el) {
3015             this.init(el, attributes, duration, method);
3016         }
3017     };
3018
3019     Roo.lib.AnimBase.fly = fly;
3020     
3021     
3022     
3023     Roo.lib.AnimBase.prototype = {
3024
3025         toString: function() {
3026             var el = this.getEl();
3027             var id = el.id || el.tagName;
3028             return ("Anim " + id);
3029         },
3030
3031         patterns: {
3032             noNegatives:        /width|height|opacity|padding/i,
3033             offsetAttribute:  /^((width|height)|(top|left))$/,
3034             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3035             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3036         },
3037
3038
3039         doMethod: function(attr, start, end) {
3040             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3041         },
3042
3043
3044         setAttribute: function(attr, val, unit) {
3045             if (this.patterns.noNegatives.test(attr)) {
3046                 val = (val > 0) ? val : 0;
3047             }
3048
3049             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3050         },
3051
3052
3053         getAttribute: function(attr) {
3054             var el = this.getEl();
3055             var val = fly(el).getStyle(attr);
3056
3057             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3058                 return parseFloat(val);
3059             }
3060
3061             var a = this.patterns.offsetAttribute.exec(attr) || [];
3062             var pos = !!( a[3] );
3063             var box = !!( a[2] );
3064
3065
3066             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3067                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3068             } else {
3069                 val = 0;
3070             }
3071
3072             return val;
3073         },
3074
3075
3076         getDefaultUnit: function(attr) {
3077             if (this.patterns.defaultUnit.test(attr)) {
3078                 return 'px';
3079             }
3080
3081             return '';
3082         },
3083
3084         animateX : function(callback, scope) {
3085             var f = function() {
3086                 this.onComplete.removeListener(f);
3087                 if (typeof callback == "function") {
3088                     callback.call(scope || this, this);
3089                 }
3090             };
3091             this.onComplete.addListener(f, this);
3092             this.animate();
3093         },
3094
3095
3096         setRuntimeAttribute: function(attr) {
3097             var start;
3098             var end;
3099             var attributes = this.attributes;
3100
3101             this.runtimeAttributes[attr] = {};
3102
3103             var isset = function(prop) {
3104                 return (typeof prop !== 'undefined');
3105             };
3106
3107             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3108                 return false;
3109             }
3110
3111             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3112
3113
3114             if (isset(attributes[attr]['to'])) {
3115                 end = attributes[attr]['to'];
3116             } else if (isset(attributes[attr]['by'])) {
3117                 if (start.constructor == Array) {
3118                     end = [];
3119                     for (var i = 0, len = start.length; i < len; ++i) {
3120                         end[i] = start[i] + attributes[attr]['by'][i];
3121                     }
3122                 } else {
3123                     end = start + attributes[attr]['by'];
3124                 }
3125             }
3126
3127             this.runtimeAttributes[attr].start = start;
3128             this.runtimeAttributes[attr].end = end;
3129
3130
3131             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3132         },
3133
3134
3135         init: function(el, attributes, duration, method) {
3136
3137             var isAnimated = false;
3138
3139
3140             var startTime = null;
3141
3142
3143             var actualFrames = 0;
3144
3145
3146             el = Roo.getDom(el);
3147
3148
3149             this.attributes = attributes || {};
3150
3151
3152             this.duration = duration || 1;
3153
3154
3155             this.method = method || Roo.lib.Easing.easeNone;
3156
3157
3158             this.useSeconds = true;
3159
3160
3161             this.currentFrame = 0;
3162
3163
3164             this.totalFrames = Roo.lib.AnimMgr.fps;
3165
3166
3167             this.getEl = function() {
3168                 return el;
3169             };
3170
3171
3172             this.isAnimated = function() {
3173                 return isAnimated;
3174             };
3175
3176
3177             this.getStartTime = function() {
3178                 return startTime;
3179             };
3180
3181             this.runtimeAttributes = {};
3182
3183
3184             this.animate = function() {
3185                 if (this.isAnimated()) {
3186                     return false;
3187                 }
3188
3189                 this.currentFrame = 0;
3190
3191                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3192
3193                 Roo.lib.AnimMgr.registerElement(this);
3194             };
3195
3196
3197             this.stop = function(finish) {
3198                 if (finish) {
3199                     this.currentFrame = this.totalFrames;
3200                     this._onTween.fire();
3201                 }
3202                 Roo.lib.AnimMgr.stop(this);
3203             };
3204
3205             var onStart = function() {
3206                 this.onStart.fire();
3207
3208                 this.runtimeAttributes = {};
3209                 for (var attr in this.attributes) {
3210                     this.setRuntimeAttribute(attr);
3211                 }
3212
3213                 isAnimated = true;
3214                 actualFrames = 0;
3215                 startTime = new Date();
3216             };
3217
3218
3219             var onTween = function() {
3220                 var data = {
3221                     duration: new Date() - this.getStartTime(),
3222                     currentFrame: this.currentFrame
3223                 };
3224
3225                 data.toString = function() {
3226                     return (
3227                             'duration: ' + data.duration +
3228                             ', currentFrame: ' + data.currentFrame
3229                             );
3230                 };
3231
3232                 this.onTween.fire(data);
3233
3234                 var runtimeAttributes = this.runtimeAttributes;
3235
3236                 for (var attr in runtimeAttributes) {
3237                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3238                 }
3239
3240                 actualFrames += 1;
3241             };
3242
3243             var onComplete = function() {
3244                 var actual_duration = (new Date() - startTime) / 1000 ;
3245
3246                 var data = {
3247                     duration: actual_duration,
3248                     frames: actualFrames,
3249                     fps: actualFrames / actual_duration
3250                 };
3251
3252                 data.toString = function() {
3253                     return (
3254                             'duration: ' + data.duration +
3255                             ', frames: ' + data.frames +
3256                             ', fps: ' + data.fps
3257                             );
3258                 };
3259
3260                 isAnimated = false;
3261                 actualFrames = 0;
3262                 this.onComplete.fire(data);
3263             };
3264
3265
3266             this._onStart = new Roo.util.Event(this);
3267             this.onStart = new Roo.util.Event(this);
3268             this.onTween = new Roo.util.Event(this);
3269             this._onTween = new Roo.util.Event(this);
3270             this.onComplete = new Roo.util.Event(this);
3271             this._onComplete = new Roo.util.Event(this);
3272             this._onStart.addListener(onStart);
3273             this._onTween.addListener(onTween);
3274             this._onComplete.addListener(onComplete);
3275         }
3276     };
3277 })();
3278 /*
3279  * Portions of this file are based on pieces of Yahoo User Interface Library
3280  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3281  * YUI licensed under the BSD License:
3282  * http://developer.yahoo.net/yui/license.txt
3283  * <script type="text/javascript">
3284  *
3285  */
3286
3287 Roo.lib.AnimMgr = new function() {
3288
3289         var thread = null;
3290
3291
3292         var queue = [];
3293
3294
3295         var tweenCount = 0;
3296
3297
3298         this.fps = 1000;
3299
3300
3301         this.delay = 1;
3302
3303
3304         this.registerElement = function(tween) {
3305             queue[queue.length] = tween;
3306             tweenCount += 1;
3307             tween._onStart.fire();
3308             this.start();
3309         };
3310
3311
3312         this.unRegister = function(tween, index) {
3313             tween._onComplete.fire();
3314             index = index || getIndex(tween);
3315             if (index != -1) {
3316                 queue.splice(index, 1);
3317             }
3318
3319             tweenCount -= 1;
3320             if (tweenCount <= 0) {
3321                 this.stop();
3322             }
3323         };
3324
3325
3326         this.start = function() {
3327             if (thread === null) {
3328                 thread = setInterval(this.run, this.delay);
3329             }
3330         };
3331
3332
3333         this.stop = function(tween) {
3334             if (!tween) {
3335                 clearInterval(thread);
3336
3337                 for (var i = 0, len = queue.length; i < len; ++i) {
3338                     if (queue[0].isAnimated()) {
3339                         this.unRegister(queue[0], 0);
3340                     }
3341                 }
3342
3343                 queue = [];
3344                 thread = null;
3345                 tweenCount = 0;
3346             }
3347             else {
3348                 this.unRegister(tween);
3349             }
3350         };
3351
3352
3353         this.run = function() {
3354             for (var i = 0, len = queue.length; i < len; ++i) {
3355                 var tween = queue[i];
3356                 if (!tween || !tween.isAnimated()) {
3357                     continue;
3358                 }
3359
3360                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3361                 {
3362                     tween.currentFrame += 1;
3363
3364                     if (tween.useSeconds) {
3365                         correctFrame(tween);
3366                     }
3367                     tween._onTween.fire();
3368                 }
3369                 else {
3370                     Roo.lib.AnimMgr.stop(tween, i);
3371                 }
3372             }
3373         };
3374
3375         var getIndex = function(anim) {
3376             for (var i = 0, len = queue.length; i < len; ++i) {
3377                 if (queue[i] == anim) {
3378                     return i;
3379                 }
3380             }
3381             return -1;
3382         };
3383
3384
3385         var correctFrame = function(tween) {
3386             var frames = tween.totalFrames;
3387             var frame = tween.currentFrame;
3388             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3389             var elapsed = (new Date() - tween.getStartTime());
3390             var tweak = 0;
3391
3392             if (elapsed < tween.duration * 1000) {
3393                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3394             } else {
3395                 tweak = frames - (frame + 1);
3396             }
3397             if (tweak > 0 && isFinite(tweak)) {
3398                 if (tween.currentFrame + tweak >= frames) {
3399                     tweak = frames - (frame + 1);
3400                 }
3401
3402                 tween.currentFrame += tweak;
3403             }
3404         };
3405     };/*
3406  * Portions of this file are based on pieces of Yahoo User Interface Library
3407  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3408  * YUI licensed under the BSD License:
3409  * http://developer.yahoo.net/yui/license.txt
3410  * <script type="text/javascript">
3411  *
3412  */
3413 Roo.lib.Bezier = new function() {
3414
3415         this.getPosition = function(points, t) {
3416             var n = points.length;
3417             var tmp = [];
3418
3419             for (var i = 0; i < n; ++i) {
3420                 tmp[i] = [points[i][0], points[i][1]];
3421             }
3422
3423             for (var j = 1; j < n; ++j) {
3424                 for (i = 0; i < n - j; ++i) {
3425                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3426                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3427                 }
3428             }
3429
3430             return [ tmp[0][0], tmp[0][1] ];
3431
3432         };
3433     };/*
3434  * Portions of this file are based on pieces of Yahoo User Interface Library
3435  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3436  * YUI licensed under the BSD License:
3437  * http://developer.yahoo.net/yui/license.txt
3438  * <script type="text/javascript">
3439  *
3440  */
3441 (function() {
3442
3443     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3444         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3445     };
3446
3447     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3448
3449     var fly = Roo.lib.AnimBase.fly;
3450     var Y = Roo.lib;
3451     var superclass = Y.ColorAnim.superclass;
3452     var proto = Y.ColorAnim.prototype;
3453
3454     proto.toString = function() {
3455         var el = this.getEl();
3456         var id = el.id || el.tagName;
3457         return ("ColorAnim " + id);
3458     };
3459
3460     proto.patterns.color = /color$/i;
3461     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3462     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3463     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3464     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3465
3466
3467     proto.parseColor = function(s) {
3468         if (s.length == 3) {
3469             return s;
3470         }
3471
3472         var c = this.patterns.hex.exec(s);
3473         if (c && c.length == 4) {
3474             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3475         }
3476
3477         c = this.patterns.rgb.exec(s);
3478         if (c && c.length == 4) {
3479             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3480         }
3481
3482         c = this.patterns.hex3.exec(s);
3483         if (c && c.length == 4) {
3484             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3485         }
3486
3487         return null;
3488     };
3489     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3490     proto.getAttribute = function(attr) {
3491         var el = this.getEl();
3492         if (this.patterns.color.test(attr)) {
3493             var val = fly(el).getStyle(attr);
3494
3495             if (this.patterns.transparent.test(val)) {
3496                 var parent = el.parentNode;
3497                 val = fly(parent).getStyle(attr);
3498
3499                 while (parent && this.patterns.transparent.test(val)) {
3500                     parent = parent.parentNode;
3501                     val = fly(parent).getStyle(attr);
3502                     if (parent.tagName.toUpperCase() == 'HTML') {
3503                         val = '#fff';
3504                     }
3505                 }
3506             }
3507         } else {
3508             val = superclass.getAttribute.call(this, attr);
3509         }
3510
3511         return val;
3512     };
3513     proto.getAttribute = function(attr) {
3514         var el = this.getEl();
3515         if (this.patterns.color.test(attr)) {
3516             var val = fly(el).getStyle(attr);
3517
3518             if (this.patterns.transparent.test(val)) {
3519                 var parent = el.parentNode;
3520                 val = fly(parent).getStyle(attr);
3521
3522                 while (parent && this.patterns.transparent.test(val)) {
3523                     parent = parent.parentNode;
3524                     val = fly(parent).getStyle(attr);
3525                     if (parent.tagName.toUpperCase() == 'HTML') {
3526                         val = '#fff';
3527                     }
3528                 }
3529             }
3530         } else {
3531             val = superclass.getAttribute.call(this, attr);
3532         }
3533
3534         return val;
3535     };
3536
3537     proto.doMethod = function(attr, start, end) {
3538         var val;
3539
3540         if (this.patterns.color.test(attr)) {
3541             val = [];
3542             for (var i = 0, len = start.length; i < len; ++i) {
3543                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3544             }
3545
3546             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3547         }
3548         else {
3549             val = superclass.doMethod.call(this, attr, start, end);
3550         }
3551
3552         return val;
3553     };
3554
3555     proto.setRuntimeAttribute = function(attr) {
3556         superclass.setRuntimeAttribute.call(this, attr);
3557
3558         if (this.patterns.color.test(attr)) {
3559             var attributes = this.attributes;
3560             var start = this.parseColor(this.runtimeAttributes[attr].start);
3561             var end = this.parseColor(this.runtimeAttributes[attr].end);
3562
3563             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3564                 end = this.parseColor(attributes[attr].by);
3565
3566                 for (var i = 0, len = start.length; i < len; ++i) {
3567                     end[i] = start[i] + end[i];
3568                 }
3569             }
3570
3571             this.runtimeAttributes[attr].start = start;
3572             this.runtimeAttributes[attr].end = end;
3573         }
3574     };
3575 })();
3576
3577 /*
3578  * Portions of this file are based on pieces of Yahoo User Interface Library
3579  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3580  * YUI licensed under the BSD License:
3581  * http://developer.yahoo.net/yui/license.txt
3582  * <script type="text/javascript">
3583  *
3584  */
3585 Roo.lib.Easing = {
3586
3587
3588     easeNone: function (t, b, c, d) {
3589         return c * t / d + b;
3590     },
3591
3592
3593     easeIn: function (t, b, c, d) {
3594         return c * (t /= d) * t + b;
3595     },
3596
3597
3598     easeOut: function (t, b, c, d) {
3599         return -c * (t /= d) * (t - 2) + b;
3600     },
3601
3602
3603     easeBoth: function (t, b, c, d) {
3604         if ((t /= d / 2) < 1) {
3605             return c / 2 * t * t + b;
3606         }
3607
3608         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3609     },
3610
3611
3612     easeInStrong: function (t, b, c, d) {
3613         return c * (t /= d) * t * t * t + b;
3614     },
3615
3616
3617     easeOutStrong: function (t, b, c, d) {
3618         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3619     },
3620
3621
3622     easeBothStrong: function (t, b, c, d) {
3623         if ((t /= d / 2) < 1) {
3624             return c / 2 * t * t * t * t + b;
3625         }
3626
3627         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3628     },
3629
3630
3631
3632     elasticIn: function (t, b, c, d, a, p) {
3633         if (t == 0) {
3634             return b;
3635         }
3636         if ((t /= d) == 1) {
3637             return b + c;
3638         }
3639         if (!p) {
3640             p = d * .3;
3641         }
3642
3643         if (!a || a < Math.abs(c)) {
3644             a = c;
3645             var s = p / 4;
3646         }
3647         else {
3648             var s = p / (2 * Math.PI) * Math.asin(c / a);
3649         }
3650
3651         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3652     },
3653
3654
3655     elasticOut: function (t, b, c, d, a, p) {
3656         if (t == 0) {
3657             return b;
3658         }
3659         if ((t /= d) == 1) {
3660             return b + c;
3661         }
3662         if (!p) {
3663             p = d * .3;
3664         }
3665
3666         if (!a || a < Math.abs(c)) {
3667             a = c;
3668             var s = p / 4;
3669         }
3670         else {
3671             var s = p / (2 * Math.PI) * Math.asin(c / a);
3672         }
3673
3674         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3675     },
3676
3677
3678     elasticBoth: function (t, b, c, d, a, p) {
3679         if (t == 0) {
3680             return b;
3681         }
3682
3683         if ((t /= d / 2) == 2) {
3684             return b + c;
3685         }
3686
3687         if (!p) {
3688             p = d * (.3 * 1.5);
3689         }
3690
3691         if (!a || a < Math.abs(c)) {
3692             a = c;
3693             var s = p / 4;
3694         }
3695         else {
3696             var s = p / (2 * Math.PI) * Math.asin(c / a);
3697         }
3698
3699         if (t < 1) {
3700             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3701                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3702         }
3703         return a * Math.pow(2, -10 * (t -= 1)) *
3704                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3705     },
3706
3707
3708
3709     backIn: function (t, b, c, d, s) {
3710         if (typeof s == 'undefined') {
3711             s = 1.70158;
3712         }
3713         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3714     },
3715
3716
3717     backOut: function (t, b, c, d, s) {
3718         if (typeof s == 'undefined') {
3719             s = 1.70158;
3720         }
3721         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3722     },
3723
3724
3725     backBoth: function (t, b, c, d, s) {
3726         if (typeof s == 'undefined') {
3727             s = 1.70158;
3728         }
3729
3730         if ((t /= d / 2 ) < 1) {
3731             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3732         }
3733         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3734     },
3735
3736
3737     bounceIn: function (t, b, c, d) {
3738         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3739     },
3740
3741
3742     bounceOut: function (t, b, c, d) {
3743         if ((t /= d) < (1 / 2.75)) {
3744             return c * (7.5625 * t * t) + b;
3745         } else if (t < (2 / 2.75)) {
3746             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3747         } else if (t < (2.5 / 2.75)) {
3748             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3749         }
3750         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3751     },
3752
3753
3754     bounceBoth: function (t, b, c, d) {
3755         if (t < d / 2) {
3756             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3757         }
3758         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3759     }
3760 };/*
3761  * Portions of this file are based on pieces of Yahoo User Interface Library
3762  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3763  * YUI licensed under the BSD License:
3764  * http://developer.yahoo.net/yui/license.txt
3765  * <script type="text/javascript">
3766  *
3767  */
3768     (function() {
3769         Roo.lib.Motion = function(el, attributes, duration, method) {
3770             if (el) {
3771                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3772             }
3773         };
3774
3775         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3776
3777
3778         var Y = Roo.lib;
3779         var superclass = Y.Motion.superclass;
3780         var proto = Y.Motion.prototype;
3781
3782         proto.toString = function() {
3783             var el = this.getEl();
3784             var id = el.id || el.tagName;
3785             return ("Motion " + id);
3786         };
3787
3788         proto.patterns.points = /^points$/i;
3789
3790         proto.setAttribute = function(attr, val, unit) {
3791             if (this.patterns.points.test(attr)) {
3792                 unit = unit || 'px';
3793                 superclass.setAttribute.call(this, 'left', val[0], unit);
3794                 superclass.setAttribute.call(this, 'top', val[1], unit);
3795             } else {
3796                 superclass.setAttribute.call(this, attr, val, unit);
3797             }
3798         };
3799
3800         proto.getAttribute = function(attr) {
3801             if (this.patterns.points.test(attr)) {
3802                 var val = [
3803                         superclass.getAttribute.call(this, 'left'),
3804                         superclass.getAttribute.call(this, 'top')
3805                         ];
3806             } else {
3807                 val = superclass.getAttribute.call(this, attr);
3808             }
3809
3810             return val;
3811         };
3812
3813         proto.doMethod = function(attr, start, end) {
3814             var val = null;
3815
3816             if (this.patterns.points.test(attr)) {
3817                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3818                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3819             } else {
3820                 val = superclass.doMethod.call(this, attr, start, end);
3821             }
3822             return val;
3823         };
3824
3825         proto.setRuntimeAttribute = function(attr) {
3826             if (this.patterns.points.test(attr)) {
3827                 var el = this.getEl();
3828                 var attributes = this.attributes;
3829                 var start;
3830                 var control = attributes['points']['control'] || [];
3831                 var end;
3832                 var i, len;
3833
3834                 if (control.length > 0 && !(control[0] instanceof Array)) {
3835                     control = [control];
3836                 } else {
3837                     var tmp = [];
3838                     for (i = 0,len = control.length; i < len; ++i) {
3839                         tmp[i] = control[i];
3840                     }
3841                     control = tmp;
3842                 }
3843
3844                 Roo.fly(el).position();
3845
3846                 if (isset(attributes['points']['from'])) {
3847                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3848                 }
3849                 else {
3850                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3851                 }
3852
3853                 start = this.getAttribute('points');
3854
3855
3856                 if (isset(attributes['points']['to'])) {
3857                     end = translateValues.call(this, attributes['points']['to'], start);
3858
3859                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3860                     for (i = 0,len = control.length; i < len; ++i) {
3861                         control[i] = translateValues.call(this, control[i], start);
3862                     }
3863
3864
3865                 } else if (isset(attributes['points']['by'])) {
3866                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3867
3868                     for (i = 0,len = control.length; i < len; ++i) {
3869                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3870                     }
3871                 }
3872
3873                 this.runtimeAttributes[attr] = [start];
3874
3875                 if (control.length > 0) {
3876                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3877                 }
3878
3879                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3880             }
3881             else {
3882                 superclass.setRuntimeAttribute.call(this, attr);
3883             }
3884         };
3885
3886         var translateValues = function(val, start) {
3887             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3888             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3889
3890             return val;
3891         };
3892
3893         var isset = function(prop) {
3894             return (typeof prop !== 'undefined');
3895         };
3896     })();
3897 /*
3898  * Portions of this file are based on pieces of Yahoo User Interface Library
3899  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3900  * YUI licensed under the BSD License:
3901  * http://developer.yahoo.net/yui/license.txt
3902  * <script type="text/javascript">
3903  *
3904  */
3905     (function() {
3906         Roo.lib.Scroll = function(el, attributes, duration, method) {
3907             if (el) {
3908                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3909             }
3910         };
3911
3912         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3913
3914
3915         var Y = Roo.lib;
3916         var superclass = Y.Scroll.superclass;
3917         var proto = Y.Scroll.prototype;
3918
3919         proto.toString = function() {
3920             var el = this.getEl();
3921             var id = el.id || el.tagName;
3922             return ("Scroll " + id);
3923         };
3924
3925         proto.doMethod = function(attr, start, end) {
3926             var val = null;
3927
3928             if (attr == 'scroll') {
3929                 val = [
3930                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3931                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3932                         ];
3933
3934             } else {
3935                 val = superclass.doMethod.call(this, attr, start, end);
3936             }
3937             return val;
3938         };
3939
3940         proto.getAttribute = function(attr) {
3941             var val = null;
3942             var el = this.getEl();
3943
3944             if (attr == 'scroll') {
3945                 val = [ el.scrollLeft, el.scrollTop ];
3946             } else {
3947                 val = superclass.getAttribute.call(this, attr);
3948             }
3949
3950             return val;
3951         };
3952
3953         proto.setAttribute = function(attr, val, unit) {
3954             var el = this.getEl();
3955
3956             if (attr == 'scroll') {
3957                 el.scrollLeft = val[0];
3958                 el.scrollTop = val[1];
3959             } else {
3960                 superclass.setAttribute.call(this, attr, val, unit);
3961             }
3962         };
3963     })();
3964 /*
3965  * Based on:
3966  * Ext JS Library 1.1.1
3967  * Copyright(c) 2006-2007, Ext JS, LLC.
3968  *
3969  * Originally Released Under LGPL - original licence link has changed is not relivant.
3970  *
3971  * Fork - LGPL
3972  * <script type="text/javascript">
3973  */
3974  
3975
3976 /**
3977  * @class Roo.DomHelper
3978  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3979  * 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>.
3980  * @singleton
3981  */
3982 Roo.DomHelper = function(){
3983     var tempTableEl = null;
3984     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3985     var tableRe = /^table|tbody|tr|td$/i;
3986     var xmlns = {};
3987     // build as innerHTML where available
3988     /** @ignore */
3989     var createHtml = function(o){
3990         if(typeof o == 'string'){
3991             return o;
3992         }
3993         var b = "";
3994         if(!o.tag){
3995             o.tag = "div";
3996         }
3997         b += "<" + o.tag;
3998         for(var attr in o){
3999             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4000             if(attr == "style"){
4001                 var s = o["style"];
4002                 if(typeof s == "function"){
4003                     s = s.call();
4004                 }
4005                 if(typeof s == "string"){
4006                     b += ' style="' + s + '"';
4007                 }else if(typeof s == "object"){
4008                     b += ' style="';
4009                     for(var key in s){
4010                         if(typeof s[key] != "function"){
4011                             b += key + ":" + s[key] + ";";
4012                         }
4013                     }
4014                     b += '"';
4015                 }
4016             }else{
4017                 if(attr == "cls"){
4018                     b += ' class="' + o["cls"] + '"';
4019                 }else if(attr == "htmlFor"){
4020                     b += ' for="' + o["htmlFor"] + '"';
4021                 }else{
4022                     b += " " + attr + '="' + o[attr] + '"';
4023                 }
4024             }
4025         }
4026         if(emptyTags.test(o.tag)){
4027             b += "/>";
4028         }else{
4029             b += ">";
4030             var cn = o.children || o.cn;
4031             if(cn){
4032                 //http://bugs.kde.org/show_bug.cgi?id=71506
4033                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4034                     for(var i = 0, len = cn.length; i < len; i++) {
4035                         b += createHtml(cn[i], b);
4036                     }
4037                 }else{
4038                     b += createHtml(cn, b);
4039                 }
4040             }
4041             if(o.html){
4042                 b += o.html;
4043             }
4044             b += "</" + o.tag + ">";
4045         }
4046         return b;
4047     };
4048
4049     // build as dom
4050     /** @ignore */
4051     var createDom = function(o, parentNode){
4052          
4053         // defininition craeted..
4054         var ns = false;
4055         if (o.ns && o.ns != 'html') {
4056                
4057             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4058                 xmlns[o.ns] = o.xmlns;
4059                 ns = o.xmlns;
4060             }
4061             if (typeof(xmlns[o.ns]) == 'undefined') {
4062                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4063             }
4064             ns = xmlns[o.ns];
4065         }
4066         
4067         
4068         if (typeof(o) == 'string') {
4069             return parentNode.appendChild(document.createTextNode(o));
4070         }
4071         o.tag = o.tag || div;
4072         if (o.ns && Roo.isIE) {
4073             ns = false;
4074             o.tag = o.ns + ':' + o.tag;
4075             
4076         }
4077         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4078         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4079         for(var attr in o){
4080             
4081             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4082                     attr == "style" || typeof o[attr] == "function") continue;
4083                     
4084             if(attr=="cls" && Roo.isIE){
4085                 el.className = o["cls"];
4086             }else{
4087                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4088                 else el[attr] = o[attr];
4089             }
4090         }
4091         Roo.DomHelper.applyStyles(el, o.style);
4092         var cn = o.children || o.cn;
4093         if(cn){
4094             //http://bugs.kde.org/show_bug.cgi?id=71506
4095              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4096                 for(var i = 0, len = cn.length; i < len; i++) {
4097                     createDom(cn[i], el);
4098                 }
4099             }else{
4100                 createDom(cn, el);
4101             }
4102         }
4103         if(o.html){
4104             el.innerHTML = o.html;
4105         }
4106         if(parentNode){
4107            parentNode.appendChild(el);
4108         }
4109         return el;
4110     };
4111
4112     var ieTable = function(depth, s, h, e){
4113         tempTableEl.innerHTML = [s, h, e].join('');
4114         var i = -1, el = tempTableEl;
4115         while(++i < depth){
4116             el = el.firstChild;
4117         }
4118         return el;
4119     };
4120
4121     // kill repeat to save bytes
4122     var ts = '<table>',
4123         te = '</table>',
4124         tbs = ts+'<tbody>',
4125         tbe = '</tbody>'+te,
4126         trs = tbs + '<tr>',
4127         tre = '</tr>'+tbe;
4128
4129     /**
4130      * @ignore
4131      * Nasty code for IE's broken table implementation
4132      */
4133     var insertIntoTable = function(tag, where, el, html){
4134         if(!tempTableEl){
4135             tempTableEl = document.createElement('div');
4136         }
4137         var node;
4138         var before = null;
4139         if(tag == 'td'){
4140             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4141                 return;
4142             }
4143             if(where == 'beforebegin'){
4144                 before = el;
4145                 el = el.parentNode;
4146             } else{
4147                 before = el.nextSibling;
4148                 el = el.parentNode;
4149             }
4150             node = ieTable(4, trs, html, tre);
4151         }
4152         else if(tag == 'tr'){
4153             if(where == 'beforebegin'){
4154                 before = el;
4155                 el = el.parentNode;
4156                 node = ieTable(3, tbs, html, tbe);
4157             } else if(where == 'afterend'){
4158                 before = el.nextSibling;
4159                 el = el.parentNode;
4160                 node = ieTable(3, tbs, html, tbe);
4161             } else{ // INTO a TR
4162                 if(where == 'afterbegin'){
4163                     before = el.firstChild;
4164                 }
4165                 node = ieTable(4, trs, html, tre);
4166             }
4167         } else if(tag == 'tbody'){
4168             if(where == 'beforebegin'){
4169                 before = el;
4170                 el = el.parentNode;
4171                 node = ieTable(2, ts, html, te);
4172             } else if(where == 'afterend'){
4173                 before = el.nextSibling;
4174                 el = el.parentNode;
4175                 node = ieTable(2, ts, html, te);
4176             } else{
4177                 if(where == 'afterbegin'){
4178                     before = el.firstChild;
4179                 }
4180                 node = ieTable(3, tbs, html, tbe);
4181             }
4182         } else{ // TABLE
4183             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4184                 return;
4185             }
4186             if(where == 'afterbegin'){
4187                 before = el.firstChild;
4188             }
4189             node = ieTable(2, ts, html, te);
4190         }
4191         el.insertBefore(node, before);
4192         return node;
4193     };
4194
4195     return {
4196     /** True to force the use of DOM instead of html fragments @type Boolean */
4197     useDom : false,
4198
4199     /**
4200      * Returns the markup for the passed Element(s) config
4201      * @param {Object} o The Dom object spec (and children)
4202      * @return {String}
4203      */
4204     markup : function(o){
4205         return createHtml(o);
4206     },
4207
4208     /**
4209      * Applies a style specification to an element
4210      * @param {String/HTMLElement} el The element to apply styles to
4211      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4212      * a function which returns such a specification.
4213      */
4214     applyStyles : function(el, styles){
4215         if(styles){
4216            el = Roo.fly(el);
4217            if(typeof styles == "string"){
4218                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4219                var matches;
4220                while ((matches = re.exec(styles)) != null){
4221                    el.setStyle(matches[1], matches[2]);
4222                }
4223            }else if (typeof styles == "object"){
4224                for (var style in styles){
4225                   el.setStyle(style, styles[style]);
4226                }
4227            }else if (typeof styles == "function"){
4228                 Roo.DomHelper.applyStyles(el, styles.call());
4229            }
4230         }
4231     },
4232
4233     /**
4234      * Inserts an HTML fragment into the Dom
4235      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4236      * @param {HTMLElement} el The context element
4237      * @param {String} html The HTML fragmenet
4238      * @return {HTMLElement} The new node
4239      */
4240     insertHtml : function(where, el, html){
4241         where = where.toLowerCase();
4242         if(el.insertAdjacentHTML){
4243             if(tableRe.test(el.tagName)){
4244                 var rs;
4245                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4246                     return rs;
4247                 }
4248             }
4249             switch(where){
4250                 case "beforebegin":
4251                     el.insertAdjacentHTML('BeforeBegin', html);
4252                     return el.previousSibling;
4253                 case "afterbegin":
4254                     el.insertAdjacentHTML('AfterBegin', html);
4255                     return el.firstChild;
4256                 case "beforeend":
4257                     el.insertAdjacentHTML('BeforeEnd', html);
4258                     return el.lastChild;
4259                 case "afterend":
4260                     el.insertAdjacentHTML('AfterEnd', html);
4261                     return el.nextSibling;
4262             }
4263             throw 'Illegal insertion point -> "' + where + '"';
4264         }
4265         var range = el.ownerDocument.createRange();
4266         var frag;
4267         switch(where){
4268              case "beforebegin":
4269                 range.setStartBefore(el);
4270                 frag = range.createContextualFragment(html);
4271                 el.parentNode.insertBefore(frag, el);
4272                 return el.previousSibling;
4273              case "afterbegin":
4274                 if(el.firstChild){
4275                     range.setStartBefore(el.firstChild);
4276                     frag = range.createContextualFragment(html);
4277                     el.insertBefore(frag, el.firstChild);
4278                     return el.firstChild;
4279                 }else{
4280                     el.innerHTML = html;
4281                     return el.firstChild;
4282                 }
4283             case "beforeend":
4284                 if(el.lastChild){
4285                     range.setStartAfter(el.lastChild);
4286                     frag = range.createContextualFragment(html);
4287                     el.appendChild(frag);
4288                     return el.lastChild;
4289                 }else{
4290                     el.innerHTML = html;
4291                     return el.lastChild;
4292                 }
4293             case "afterend":
4294                 range.setStartAfter(el);
4295                 frag = range.createContextualFragment(html);
4296                 el.parentNode.insertBefore(frag, el.nextSibling);
4297                 return el.nextSibling;
4298             }
4299             throw 'Illegal insertion point -> "' + where + '"';
4300     },
4301
4302     /**
4303      * Creates new Dom element(s) and inserts them before el
4304      * @param {String/HTMLElement/Element} el The context element
4305      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4306      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4307      * @return {HTMLElement/Roo.Element} The new node
4308      */
4309     insertBefore : function(el, o, returnElement){
4310         return this.doInsert(el, o, returnElement, "beforeBegin");
4311     },
4312
4313     /**
4314      * Creates new Dom element(s) and inserts them after el
4315      * @param {String/HTMLElement/Element} el The context element
4316      * @param {Object} o The Dom object spec (and children)
4317      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4318      * @return {HTMLElement/Roo.Element} The new node
4319      */
4320     insertAfter : function(el, o, returnElement){
4321         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4322     },
4323
4324     /**
4325      * Creates new Dom element(s) and inserts them as the first child of el
4326      * @param {String/HTMLElement/Element} el The context element
4327      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4328      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4329      * @return {HTMLElement/Roo.Element} The new node
4330      */
4331     insertFirst : function(el, o, returnElement){
4332         return this.doInsert(el, o, returnElement, "afterBegin");
4333     },
4334
4335     // private
4336     doInsert : function(el, o, returnElement, pos, sibling){
4337         el = Roo.getDom(el);
4338         var newNode;
4339         if(this.useDom || o.ns){
4340             newNode = createDom(o, null);
4341             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4342         }else{
4343             var html = createHtml(o);
4344             newNode = this.insertHtml(pos, el, html);
4345         }
4346         return returnElement ? Roo.get(newNode, true) : newNode;
4347     },
4348
4349     /**
4350      * Creates new Dom element(s) and appends them to el
4351      * @param {String/HTMLElement/Element} el The context element
4352      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4353      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4354      * @return {HTMLElement/Roo.Element} The new node
4355      */
4356     append : function(el, o, returnElement){
4357         el = Roo.getDom(el);
4358         var newNode;
4359         if(this.useDom || o.ns){
4360             newNode = createDom(o, null);
4361             el.appendChild(newNode);
4362         }else{
4363             var html = createHtml(o);
4364             newNode = this.insertHtml("beforeEnd", el, html);
4365         }
4366         return returnElement ? Roo.get(newNode, true) : newNode;
4367     },
4368
4369     /**
4370      * Creates new Dom element(s) and overwrites the contents of el with them
4371      * @param {String/HTMLElement/Element} el The context element
4372      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4373      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4374      * @return {HTMLElement/Roo.Element} The new node
4375      */
4376     overwrite : function(el, o, returnElement){
4377         el = Roo.getDom(el);
4378         if (o.ns) {
4379           
4380             while (el.childNodes.length) {
4381                 el.removeChild(el.firstChild);
4382             }
4383             createDom(o, el);
4384         } else {
4385             el.innerHTML = createHtml(o);   
4386         }
4387         
4388         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4389     },
4390
4391     /**
4392      * Creates a new Roo.DomHelper.Template from the Dom object spec
4393      * @param {Object} o The Dom object spec (and children)
4394      * @return {Roo.DomHelper.Template} The new template
4395      */
4396     createTemplate : function(o){
4397         var html = createHtml(o);
4398         return new Roo.Template(html);
4399     }
4400     };
4401 }();
4402 /*
4403  * Based on:
4404  * Ext JS Library 1.1.1
4405  * Copyright(c) 2006-2007, Ext JS, LLC.
4406  *
4407  * Originally Released Under LGPL - original licence link has changed is not relivant.
4408  *
4409  * Fork - LGPL
4410  * <script type="text/javascript">
4411  */
4412  
4413 /**
4414 * @class Roo.Template
4415 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4416 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4417 * Usage:
4418 <pre><code>
4419 var t = new Roo.Template({
4420     html :  '&lt;div name="{id}"&gt;' + 
4421         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4422         '&lt;/div&gt;',
4423     myformat: function (value, allValues) {
4424         return 'XX' + value;
4425     }
4426 });
4427 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4428 </code></pre>
4429 * 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>. 
4430 * @constructor
4431 * @param {Object} cfg - Configuration object.
4432 */
4433 Roo.Template = function(cfg){
4434     // BC!
4435     if(cfg instanceof Array){
4436         cfg = cfg.join("");
4437     }else if(arguments.length > 1){
4438         cfg = Array.prototype.join.call(arguments, "");
4439     }
4440     
4441     
4442     if (typeof(cfg) == 'object') {
4443         Roo.apply(this,cfg)
4444     } else {
4445         // bc
4446         this.html = cfg;
4447     }
4448     
4449     
4450 };
4451 Roo.Template.prototype = {
4452     
4453     /**
4454      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4455      */
4456     html : '',
4457     /**
4458      * Returns an HTML fragment of this template with the specified values applied.
4459      * @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'})
4460      * @return {String} The HTML fragment
4461      */
4462     applyTemplate : function(values){
4463         try {
4464             
4465             if(this.compiled){
4466                 return this.compiled(values);
4467             }
4468             var useF = this.disableFormats !== true;
4469             var fm = Roo.util.Format, tpl = this;
4470             var fn = function(m, name, format, args){
4471                 if(format && useF){
4472                     if(format.substr(0, 5) == "this."){
4473                         return tpl.call(format.substr(5), values[name], values);
4474                     }else{
4475                         if(args){
4476                             // quoted values are required for strings in compiled templates, 
4477                             // but for non compiled we need to strip them
4478                             // quoted reversed for jsmin
4479                             var re = /^\s*['"](.*)["']\s*$/;
4480                             args = args.split(',');
4481                             for(var i = 0, len = args.length; i < len; i++){
4482                                 args[i] = args[i].replace(re, "$1");
4483                             }
4484                             args = [values[name]].concat(args);
4485                         }else{
4486                             args = [values[name]];
4487                         }
4488                         return fm[format].apply(fm, args);
4489                     }
4490                 }else{
4491                     return values[name] !== undefined ? values[name] : "";
4492                 }
4493             };
4494             return this.html.replace(this.re, fn);
4495         } catch (e) {
4496             Roo.log(e);
4497             throw e;
4498         }
4499          
4500     },
4501     
4502     /**
4503      * Sets the HTML used as the template and optionally compiles it.
4504      * @param {String} html
4505      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4506      * @return {Roo.Template} this
4507      */
4508     set : function(html, compile){
4509         this.html = html;
4510         this.compiled = null;
4511         if(compile){
4512             this.compile();
4513         }
4514         return this;
4515     },
4516     
4517     /**
4518      * True to disable format functions (defaults to false)
4519      * @type Boolean
4520      */
4521     disableFormats : false,
4522     
4523     /**
4524     * The regular expression used to match template variables 
4525     * @type RegExp
4526     * @property 
4527     */
4528     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4529     
4530     /**
4531      * Compiles the template into an internal function, eliminating the RegEx overhead.
4532      * @return {Roo.Template} this
4533      */
4534     compile : function(){
4535         var fm = Roo.util.Format;
4536         var useF = this.disableFormats !== true;
4537         var sep = Roo.isGecko ? "+" : ",";
4538         var fn = function(m, name, format, args){
4539             if(format && useF){
4540                 args = args ? ',' + args : "";
4541                 if(format.substr(0, 5) != "this."){
4542                     format = "fm." + format + '(';
4543                 }else{
4544                     format = 'this.call("'+ format.substr(5) + '", ';
4545                     args = ", values";
4546                 }
4547             }else{
4548                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4549             }
4550             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4551         };
4552         var body;
4553         // branched to use + in gecko and [].join() in others
4554         if(Roo.isGecko){
4555             body = "this.compiled = function(values){ return '" +
4556                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4557                     "';};";
4558         }else{
4559             body = ["this.compiled = function(values){ return ['"];
4560             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4561             body.push("'].join('');};");
4562             body = body.join('');
4563         }
4564         /**
4565          * eval:var:values
4566          * eval:var:fm
4567          */
4568         eval(body);
4569         return this;
4570     },
4571     
4572     // private function used to call members
4573     call : function(fnName, value, allValues){
4574         return this[fnName](value, allValues);
4575     },
4576     
4577     /**
4578      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4579      * @param {String/HTMLElement/Roo.Element} el The context element
4580      * @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'})
4581      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4582      * @return {HTMLElement/Roo.Element} The new node or Element
4583      */
4584     insertFirst: function(el, values, returnElement){
4585         return this.doInsert('afterBegin', el, values, returnElement);
4586     },
4587
4588     /**
4589      * Applies the supplied values to the template and inserts the new node(s) before el.
4590      * @param {String/HTMLElement/Roo.Element} el The context element
4591      * @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'})
4592      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4593      * @return {HTMLElement/Roo.Element} The new node or Element
4594      */
4595     insertBefore: function(el, values, returnElement){
4596         return this.doInsert('beforeBegin', el, values, returnElement);
4597     },
4598
4599     /**
4600      * Applies the supplied values to the template and inserts the new node(s) after el.
4601      * @param {String/HTMLElement/Roo.Element} el The context element
4602      * @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'})
4603      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4604      * @return {HTMLElement/Roo.Element} The new node or Element
4605      */
4606     insertAfter : function(el, values, returnElement){
4607         return this.doInsert('afterEnd', el, values, returnElement);
4608     },
4609     
4610     /**
4611      * Applies the supplied values to the template and appends the new node(s) to el.
4612      * @param {String/HTMLElement/Roo.Element} el The context element
4613      * @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'})
4614      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4615      * @return {HTMLElement/Roo.Element} The new node or Element
4616      */
4617     append : function(el, values, returnElement){
4618         return this.doInsert('beforeEnd', el, values, returnElement);
4619     },
4620
4621     doInsert : function(where, el, values, returnEl){
4622         el = Roo.getDom(el);
4623         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4624         return returnEl ? Roo.get(newNode, true) : newNode;
4625     },
4626
4627     /**
4628      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4629      * @param {String/HTMLElement/Roo.Element} el The context element
4630      * @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'})
4631      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4632      * @return {HTMLElement/Roo.Element} The new node or Element
4633      */
4634     overwrite : function(el, values, returnElement){
4635         el = Roo.getDom(el);
4636         el.innerHTML = this.applyTemplate(values);
4637         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4638     }
4639 };
4640 /**
4641  * Alias for {@link #applyTemplate}
4642  * @method
4643  */
4644 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4645
4646 // backwards compat
4647 Roo.DomHelper.Template = Roo.Template;
4648
4649 /**
4650  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4651  * @param {String/HTMLElement} el A DOM element or its id
4652  * @returns {Roo.Template} The created template
4653  * @static
4654  */
4655 Roo.Template.from = function(el){
4656     el = Roo.getDom(el);
4657     return new Roo.Template(el.value || el.innerHTML);
4658 };/*
4659  * Based on:
4660  * Ext JS Library 1.1.1
4661  * Copyright(c) 2006-2007, Ext JS, LLC.
4662  *
4663  * Originally Released Under LGPL - original licence link has changed is not relivant.
4664  *
4665  * Fork - LGPL
4666  * <script type="text/javascript">
4667  */
4668  
4669
4670 /*
4671  * This is code is also distributed under MIT license for use
4672  * with jQuery and prototype JavaScript libraries.
4673  */
4674 /**
4675  * @class Roo.DomQuery
4676 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).
4677 <p>
4678 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>
4679
4680 <p>
4681 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.
4682 </p>
4683 <h4>Element Selectors:</h4>
4684 <ul class="list">
4685     <li> <b>*</b> any element</li>
4686     <li> <b>E</b> an element with the tag E</li>
4687     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4688     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4689     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4690     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4691 </ul>
4692 <h4>Attribute Selectors:</h4>
4693 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4694 <ul class="list">
4695     <li> <b>E[foo]</b> has an attribute "foo"</li>
4696     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4697     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4698     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4699     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4700     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4701     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4702 </ul>
4703 <h4>Pseudo Classes:</h4>
4704 <ul class="list">
4705     <li> <b>E:first-child</b> E is the first child of its parent</li>
4706     <li> <b>E:last-child</b> E is the last child of its parent</li>
4707     <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>
4708     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4709     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4710     <li> <b>E:only-child</b> E is the only child of its parent</li>
4711     <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>
4712     <li> <b>E:first</b> the first E in the resultset</li>
4713     <li> <b>E:last</b> the last E in the resultset</li>
4714     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4715     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4716     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4717     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4718     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4719     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4720     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4721     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4722     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4723 </ul>
4724 <h4>CSS Value Selectors:</h4>
4725 <ul class="list">
4726     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4727     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4728     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4729     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4730     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4731     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4732 </ul>
4733  * @singleton
4734  */
4735 Roo.DomQuery = function(){
4736     var cache = {}, simpleCache = {}, valueCache = {};
4737     var nonSpace = /\S/;
4738     var trimRe = /^\s+|\s+$/g;
4739     var tplRe = /\{(\d+)\}/g;
4740     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4741     var tagTokenRe = /^(#)?([\w-\*]+)/;
4742     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4743
4744     function child(p, index){
4745         var i = 0;
4746         var n = p.firstChild;
4747         while(n){
4748             if(n.nodeType == 1){
4749                if(++i == index){
4750                    return n;
4751                }
4752             }
4753             n = n.nextSibling;
4754         }
4755         return null;
4756     };
4757
4758     function next(n){
4759         while((n = n.nextSibling) && n.nodeType != 1);
4760         return n;
4761     };
4762
4763     function prev(n){
4764         while((n = n.previousSibling) && n.nodeType != 1);
4765         return n;
4766     };
4767
4768     function children(d){
4769         var n = d.firstChild, ni = -1;
4770             while(n){
4771                 var nx = n.nextSibling;
4772                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4773                     d.removeChild(n);
4774                 }else{
4775                     n.nodeIndex = ++ni;
4776                 }
4777                 n = nx;
4778             }
4779             return this;
4780         };
4781
4782     function byClassName(c, a, v){
4783         if(!v){
4784             return c;
4785         }
4786         var r = [], ri = -1, cn;
4787         for(var i = 0, ci; ci = c[i]; i++){
4788             if((' '+ci.className+' ').indexOf(v) != -1){
4789                 r[++ri] = ci;
4790             }
4791         }
4792         return r;
4793     };
4794
4795     function attrValue(n, attr){
4796         if(!n.tagName && typeof n.length != "undefined"){
4797             n = n[0];
4798         }
4799         if(!n){
4800             return null;
4801         }
4802         if(attr == "for"){
4803             return n.htmlFor;
4804         }
4805         if(attr == "class" || attr == "className"){
4806             return n.className;
4807         }
4808         return n.getAttribute(attr) || n[attr];
4809
4810     };
4811
4812     function getNodes(ns, mode, tagName){
4813         var result = [], ri = -1, cs;
4814         if(!ns){
4815             return result;
4816         }
4817         tagName = tagName || "*";
4818         if(typeof ns.getElementsByTagName != "undefined"){
4819             ns = [ns];
4820         }
4821         if(!mode){
4822             for(var i = 0, ni; ni = ns[i]; i++){
4823                 cs = ni.getElementsByTagName(tagName);
4824                 for(var j = 0, ci; ci = cs[j]; j++){
4825                     result[++ri] = ci;
4826                 }
4827             }
4828         }else if(mode == "/" || mode == ">"){
4829             var utag = tagName.toUpperCase();
4830             for(var i = 0, ni, cn; ni = ns[i]; i++){
4831                 cn = ni.children || ni.childNodes;
4832                 for(var j = 0, cj; cj = cn[j]; j++){
4833                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4834                         result[++ri] = cj;
4835                     }
4836                 }
4837             }
4838         }else if(mode == "+"){
4839             var utag = tagName.toUpperCase();
4840             for(var i = 0, n; n = ns[i]; i++){
4841                 while((n = n.nextSibling) && n.nodeType != 1);
4842                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4843                     result[++ri] = n;
4844                 }
4845             }
4846         }else if(mode == "~"){
4847             for(var i = 0, n; n = ns[i]; i++){
4848                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4849                 if(n){
4850                     result[++ri] = n;
4851                 }
4852             }
4853         }
4854         return result;
4855     };
4856
4857     function concat(a, b){
4858         if(b.slice){
4859             return a.concat(b);
4860         }
4861         for(var i = 0, l = b.length; i < l; i++){
4862             a[a.length] = b[i];
4863         }
4864         return a;
4865     }
4866
4867     function byTag(cs, tagName){
4868         if(cs.tagName || cs == document){
4869             cs = [cs];
4870         }
4871         if(!tagName){
4872             return cs;
4873         }
4874         var r = [], ri = -1;
4875         tagName = tagName.toLowerCase();
4876         for(var i = 0, ci; ci = cs[i]; i++){
4877             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4878                 r[++ri] = ci;
4879             }
4880         }
4881         return r;
4882     };
4883
4884     function byId(cs, attr, id){
4885         if(cs.tagName || cs == document){
4886             cs = [cs];
4887         }
4888         if(!id){
4889             return cs;
4890         }
4891         var r = [], ri = -1;
4892         for(var i = 0,ci; ci = cs[i]; i++){
4893             if(ci && ci.id == id){
4894                 r[++ri] = ci;
4895                 return r;
4896             }
4897         }
4898         return r;
4899     };
4900
4901     function byAttribute(cs, attr, value, op, custom){
4902         var r = [], ri = -1, st = custom=="{";
4903         var f = Roo.DomQuery.operators[op];
4904         for(var i = 0, ci; ci = cs[i]; i++){
4905             var a;
4906             if(st){
4907                 a = Roo.DomQuery.getStyle(ci, attr);
4908             }
4909             else if(attr == "class" || attr == "className"){
4910                 a = ci.className;
4911             }else if(attr == "for"){
4912                 a = ci.htmlFor;
4913             }else if(attr == "href"){
4914                 a = ci.getAttribute("href", 2);
4915             }else{
4916                 a = ci.getAttribute(attr);
4917             }
4918             if((f && f(a, value)) || (!f && a)){
4919                 r[++ri] = ci;
4920             }
4921         }
4922         return r;
4923     };
4924
4925     function byPseudo(cs, name, value){
4926         return Roo.DomQuery.pseudos[name](cs, value);
4927     };
4928
4929     // This is for IE MSXML which does not support expandos.
4930     // IE runs the same speed using setAttribute, however FF slows way down
4931     // and Safari completely fails so they need to continue to use expandos.
4932     var isIE = window.ActiveXObject ? true : false;
4933
4934     // this eval is stop the compressor from
4935     // renaming the variable to something shorter
4936     
4937     /** eval:var:batch */
4938     var batch = 30803; 
4939
4940     var key = 30803;
4941
4942     function nodupIEXml(cs){
4943         var d = ++key;
4944         cs[0].setAttribute("_nodup", d);
4945         var r = [cs[0]];
4946         for(var i = 1, len = cs.length; i < len; i++){
4947             var c = cs[i];
4948             if(!c.getAttribute("_nodup") != d){
4949                 c.setAttribute("_nodup", d);
4950                 r[r.length] = c;
4951             }
4952         }
4953         for(var i = 0, len = cs.length; i < len; i++){
4954             cs[i].removeAttribute("_nodup");
4955         }
4956         return r;
4957     }
4958
4959     function nodup(cs){
4960         if(!cs){
4961             return [];
4962         }
4963         var len = cs.length, c, i, r = cs, cj, ri = -1;
4964         if(!len || typeof cs.nodeType != "undefined" || len == 1){
4965             return cs;
4966         }
4967         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4968             return nodupIEXml(cs);
4969         }
4970         var d = ++key;
4971         cs[0]._nodup = d;
4972         for(i = 1; c = cs[i]; i++){
4973             if(c._nodup != d){
4974                 c._nodup = d;
4975             }else{
4976                 r = [];
4977                 for(var j = 0; j < i; j++){
4978                     r[++ri] = cs[j];
4979                 }
4980                 for(j = i+1; cj = cs[j]; j++){
4981                     if(cj._nodup != d){
4982                         cj._nodup = d;
4983                         r[++ri] = cj;
4984                     }
4985                 }
4986                 return r;
4987             }
4988         }
4989         return r;
4990     }
4991
4992     function quickDiffIEXml(c1, c2){
4993         var d = ++key;
4994         for(var i = 0, len = c1.length; i < len; i++){
4995             c1[i].setAttribute("_qdiff", d);
4996         }
4997         var r = [];
4998         for(var i = 0, len = c2.length; i < len; i++){
4999             if(c2[i].getAttribute("_qdiff") != d){
5000                 r[r.length] = c2[i];
5001             }
5002         }
5003         for(var i = 0, len = c1.length; i < len; i++){
5004            c1[i].removeAttribute("_qdiff");
5005         }
5006         return r;
5007     }
5008
5009     function quickDiff(c1, c2){
5010         var len1 = c1.length;
5011         if(!len1){
5012             return c2;
5013         }
5014         if(isIE && c1[0].selectSingleNode){
5015             return quickDiffIEXml(c1, c2);
5016         }
5017         var d = ++key;
5018         for(var i = 0; i < len1; i++){
5019             c1[i]._qdiff = d;
5020         }
5021         var r = [];
5022         for(var i = 0, len = c2.length; i < len; i++){
5023             if(c2[i]._qdiff != d){
5024                 r[r.length] = c2[i];
5025             }
5026         }
5027         return r;
5028     }
5029
5030     function quickId(ns, mode, root, id){
5031         if(ns == root){
5032            var d = root.ownerDocument || root;
5033            return d.getElementById(id);
5034         }
5035         ns = getNodes(ns, mode, "*");
5036         return byId(ns, null, id);
5037     }
5038
5039     return {
5040         getStyle : function(el, name){
5041             return Roo.fly(el).getStyle(name);
5042         },
5043         /**
5044          * Compiles a selector/xpath query into a reusable function. The returned function
5045          * takes one parameter "root" (optional), which is the context node from where the query should start.
5046          * @param {String} selector The selector/xpath query
5047          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5048          * @return {Function}
5049          */
5050         compile : function(path, type){
5051             type = type || "select";
5052             
5053             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5054             var q = path, mode, lq;
5055             var tk = Roo.DomQuery.matchers;
5056             var tklen = tk.length;
5057             var mm;
5058
5059             // accept leading mode switch
5060             var lmode = q.match(modeRe);
5061             if(lmode && lmode[1]){
5062                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5063                 q = q.replace(lmode[1], "");
5064             }
5065             // strip leading slashes
5066             while(path.substr(0, 1)=="/"){
5067                 path = path.substr(1);
5068             }
5069
5070             while(q && lq != q){
5071                 lq = q;
5072                 var tm = q.match(tagTokenRe);
5073                 if(type == "select"){
5074                     if(tm){
5075                         if(tm[1] == "#"){
5076                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5077                         }else{
5078                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5079                         }
5080                         q = q.replace(tm[0], "");
5081                     }else if(q.substr(0, 1) != '@'){
5082                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5083                     }
5084                 }else{
5085                     if(tm){
5086                         if(tm[1] == "#"){
5087                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5088                         }else{
5089                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5090                         }
5091                         q = q.replace(tm[0], "");
5092                     }
5093                 }
5094                 while(!(mm = q.match(modeRe))){
5095                     var matched = false;
5096                     for(var j = 0; j < tklen; j++){
5097                         var t = tk[j];
5098                         var m = q.match(t.re);
5099                         if(m){
5100                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5101                                                     return m[i];
5102                                                 });
5103                             q = q.replace(m[0], "");
5104                             matched = true;
5105                             break;
5106                         }
5107                     }
5108                     // prevent infinite loop on bad selector
5109                     if(!matched){
5110                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5111                     }
5112                 }
5113                 if(mm[1]){
5114                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5115                     q = q.replace(mm[1], "");
5116                 }
5117             }
5118             fn[fn.length] = "return nodup(n);\n}";
5119             
5120              /** 
5121               * list of variables that need from compression as they are used by eval.
5122              *  eval:var:batch 
5123              *  eval:var:nodup
5124              *  eval:var:byTag
5125              *  eval:var:ById
5126              *  eval:var:getNodes
5127              *  eval:var:quickId
5128              *  eval:var:mode
5129              *  eval:var:root
5130              *  eval:var:n
5131              *  eval:var:byClassName
5132              *  eval:var:byPseudo
5133              *  eval:var:byAttribute
5134              *  eval:var:attrValue
5135              * 
5136              **/ 
5137             eval(fn.join(""));
5138             return f;
5139         },
5140
5141         /**
5142          * Selects a group of elements.
5143          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5144          * @param {Node} root (optional) The start of the query (defaults to document).
5145          * @return {Array}
5146          */
5147         select : function(path, root, type){
5148             if(!root || root == document){
5149                 root = document;
5150             }
5151             if(typeof root == "string"){
5152                 root = document.getElementById(root);
5153             }
5154             var paths = path.split(",");
5155             var results = [];
5156             for(var i = 0, len = paths.length; i < len; i++){
5157                 var p = paths[i].replace(trimRe, "");
5158                 if(!cache[p]){
5159                     cache[p] = Roo.DomQuery.compile(p);
5160                     if(!cache[p]){
5161                         throw p + " is not a valid selector";
5162                     }
5163                 }
5164                 var result = cache[p](root);
5165                 if(result && result != document){
5166                     results = results.concat(result);
5167                 }
5168             }
5169             if(paths.length > 1){
5170                 return nodup(results);
5171             }
5172             return results;
5173         },
5174
5175         /**
5176          * Selects a single element.
5177          * @param {String} selector The selector/xpath query
5178          * @param {Node} root (optional) The start of the query (defaults to document).
5179          * @return {Element}
5180          */
5181         selectNode : function(path, root){
5182             return Roo.DomQuery.select(path, root)[0];
5183         },
5184
5185         /**
5186          * Selects the value of a node, optionally replacing null with the defaultValue.
5187          * @param {String} selector The selector/xpath query
5188          * @param {Node} root (optional) The start of the query (defaults to document).
5189          * @param {String} defaultValue
5190          */
5191         selectValue : function(path, root, defaultValue){
5192             path = path.replace(trimRe, "");
5193             if(!valueCache[path]){
5194                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5195             }
5196             var n = valueCache[path](root);
5197             n = n[0] ? n[0] : n;
5198             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5199             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5200         },
5201
5202         /**
5203          * Selects the value of a node, parsing integers and floats.
5204          * @param {String} selector The selector/xpath query
5205          * @param {Node} root (optional) The start of the query (defaults to document).
5206          * @param {Number} defaultValue
5207          * @return {Number}
5208          */
5209         selectNumber : function(path, root, defaultValue){
5210             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5211             return parseFloat(v);
5212         },
5213
5214         /**
5215          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5216          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5217          * @param {String} selector The simple selector to test
5218          * @return {Boolean}
5219          */
5220         is : function(el, ss){
5221             if(typeof el == "string"){
5222                 el = document.getElementById(el);
5223             }
5224             var isArray = (el instanceof Array);
5225             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5226             return isArray ? (result.length == el.length) : (result.length > 0);
5227         },
5228
5229         /**
5230          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5231          * @param {Array} el An array of elements to filter
5232          * @param {String} selector The simple selector to test
5233          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5234          * the selector instead of the ones that match
5235          * @return {Array}
5236          */
5237         filter : function(els, ss, nonMatches){
5238             ss = ss.replace(trimRe, "");
5239             if(!simpleCache[ss]){
5240                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5241             }
5242             var result = simpleCache[ss](els);
5243             return nonMatches ? quickDiff(result, els) : result;
5244         },
5245
5246         /**
5247          * Collection of matching regular expressions and code snippets.
5248          */
5249         matchers : [{
5250                 re: /^\.([\w-]+)/,
5251                 select: 'n = byClassName(n, null, " {1} ");'
5252             }, {
5253                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5254                 select: 'n = byPseudo(n, "{1}", "{2}");'
5255             },{
5256                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5257                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5258             }, {
5259                 re: /^#([\w-]+)/,
5260                 select: 'n = byId(n, null, "{1}");'
5261             },{
5262                 re: /^@([\w-]+)/,
5263                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5264             }
5265         ],
5266
5267         /**
5268          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5269          * 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;.
5270          */
5271         operators : {
5272             "=" : function(a, v){
5273                 return a == v;
5274             },
5275             "!=" : function(a, v){
5276                 return a != v;
5277             },
5278             "^=" : function(a, v){
5279                 return a && a.substr(0, v.length) == v;
5280             },
5281             "$=" : function(a, v){
5282                 return a && a.substr(a.length-v.length) == v;
5283             },
5284             "*=" : function(a, v){
5285                 return a && a.indexOf(v) !== -1;
5286             },
5287             "%=" : function(a, v){
5288                 return (a % v) == 0;
5289             },
5290             "|=" : function(a, v){
5291                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5292             },
5293             "~=" : function(a, v){
5294                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5295             }
5296         },
5297
5298         /**
5299          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5300          * and the argument (if any) supplied in the selector.
5301          */
5302         pseudos : {
5303             "first-child" : function(c){
5304                 var r = [], ri = -1, n;
5305                 for(var i = 0, ci; ci = n = c[i]; i++){
5306                     while((n = n.previousSibling) && n.nodeType != 1);
5307                     if(!n){
5308                         r[++ri] = ci;
5309                     }
5310                 }
5311                 return r;
5312             },
5313
5314             "last-child" : function(c){
5315                 var r = [], ri = -1, n;
5316                 for(var i = 0, ci; ci = n = c[i]; i++){
5317                     while((n = n.nextSibling) && n.nodeType != 1);
5318                     if(!n){
5319                         r[++ri] = ci;
5320                     }
5321                 }
5322                 return r;
5323             },
5324
5325             "nth-child" : function(c, a) {
5326                 var r = [], ri = -1;
5327                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5328                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5329                 for(var i = 0, n; n = c[i]; i++){
5330                     var pn = n.parentNode;
5331                     if (batch != pn._batch) {
5332                         var j = 0;
5333                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5334                             if(cn.nodeType == 1){
5335                                cn.nodeIndex = ++j;
5336                             }
5337                         }
5338                         pn._batch = batch;
5339                     }
5340                     if (f == 1) {
5341                         if (l == 0 || n.nodeIndex == l){
5342                             r[++ri] = n;
5343                         }
5344                     } else if ((n.nodeIndex + l) % f == 0){
5345                         r[++ri] = n;
5346                     }
5347                 }
5348
5349                 return r;
5350             },
5351
5352             "only-child" : function(c){
5353                 var r = [], ri = -1;;
5354                 for(var i = 0, ci; ci = c[i]; i++){
5355                     if(!prev(ci) && !next(ci)){
5356                         r[++ri] = ci;
5357                     }
5358                 }
5359                 return r;
5360             },
5361
5362             "empty" : function(c){
5363                 var r = [], ri = -1;
5364                 for(var i = 0, ci; ci = c[i]; i++){
5365                     var cns = ci.childNodes, j = 0, cn, empty = true;
5366                     while(cn = cns[j]){
5367                         ++j;
5368                         if(cn.nodeType == 1 || cn.nodeType == 3){
5369                             empty = false;
5370                             break;
5371                         }
5372                     }
5373                     if(empty){
5374                         r[++ri] = ci;
5375                     }
5376                 }
5377                 return r;
5378             },
5379
5380             "contains" : function(c, v){
5381                 var r = [], ri = -1;
5382                 for(var i = 0, ci; ci = c[i]; i++){
5383                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5384                         r[++ri] = ci;
5385                     }
5386                 }
5387                 return r;
5388             },
5389
5390             "nodeValue" : function(c, v){
5391                 var r = [], ri = -1;
5392                 for(var i = 0, ci; ci = c[i]; i++){
5393                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5394                         r[++ri] = ci;
5395                     }
5396                 }
5397                 return r;
5398             },
5399
5400             "checked" : function(c){
5401                 var r = [], ri = -1;
5402                 for(var i = 0, ci; ci = c[i]; i++){
5403                     if(ci.checked == true){
5404                         r[++ri] = ci;
5405                     }
5406                 }
5407                 return r;
5408             },
5409
5410             "not" : function(c, ss){
5411                 return Roo.DomQuery.filter(c, ss, true);
5412             },
5413
5414             "odd" : function(c){
5415                 return this["nth-child"](c, "odd");
5416             },
5417
5418             "even" : function(c){
5419                 return this["nth-child"](c, "even");
5420             },
5421
5422             "nth" : function(c, a){
5423                 return c[a-1] || [];
5424             },
5425
5426             "first" : function(c){
5427                 return c[0] || [];
5428             },
5429
5430             "last" : function(c){
5431                 return c[c.length-1] || [];
5432             },
5433
5434             "has" : function(c, ss){
5435                 var s = Roo.DomQuery.select;
5436                 var r = [], ri = -1;
5437                 for(var i = 0, ci; ci = c[i]; i++){
5438                     if(s(ss, ci).length > 0){
5439                         r[++ri] = ci;
5440                     }
5441                 }
5442                 return r;
5443             },
5444
5445             "next" : function(c, ss){
5446                 var is = Roo.DomQuery.is;
5447                 var r = [], ri = -1;
5448                 for(var i = 0, ci; ci = c[i]; i++){
5449                     var n = next(ci);
5450                     if(n && is(n, ss)){
5451                         r[++ri] = ci;
5452                     }
5453                 }
5454                 return r;
5455             },
5456
5457             "prev" : function(c, ss){
5458                 var is = Roo.DomQuery.is;
5459                 var r = [], ri = -1;
5460                 for(var i = 0, ci; ci = c[i]; i++){
5461                     var n = prev(ci);
5462                     if(n && is(n, ss)){
5463                         r[++ri] = ci;
5464                     }
5465                 }
5466                 return r;
5467             }
5468         }
5469     };
5470 }();
5471
5472 /**
5473  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5474  * @param {String} path The selector/xpath query
5475  * @param {Node} root (optional) The start of the query (defaults to document).
5476  * @return {Array}
5477  * @member Roo
5478  * @method query
5479  */
5480 Roo.query = Roo.DomQuery.select;
5481 /*
5482  * Based on:
5483  * Ext JS Library 1.1.1
5484  * Copyright(c) 2006-2007, Ext JS, LLC.
5485  *
5486  * Originally Released Under LGPL - original licence link has changed is not relivant.
5487  *
5488  * Fork - LGPL
5489  * <script type="text/javascript">
5490  */
5491
5492 /**
5493  * @class Roo.util.Observable
5494  * Base class that provides a common interface for publishing events. Subclasses are expected to
5495  * to have a property "events" with all the events defined.<br>
5496  * For example:
5497  * <pre><code>
5498  Employee = function(name){
5499     this.name = name;
5500     this.addEvents({
5501         "fired" : true,
5502         "quit" : true
5503     });
5504  }
5505  Roo.extend(Employee, Roo.util.Observable);
5506 </code></pre>
5507  * @param {Object} config properties to use (incuding events / listeners)
5508  */
5509
5510 Roo.util.Observable = function(cfg){
5511     
5512     cfg = cfg|| {};
5513     this.addEvents(cfg.events || {});
5514     if (cfg.events) {
5515         delete cfg.events; // make sure
5516     }
5517      
5518     Roo.apply(this, cfg);
5519     
5520     if(this.listeners){
5521         this.on(this.listeners);
5522         delete this.listeners;
5523     }
5524 };
5525 Roo.util.Observable.prototype = {
5526     /** 
5527  * @cfg {Object} listeners  list of events and functions to call for this object, 
5528  * For example :
5529  * <pre><code>
5530     listeners :  { 
5531        'click' : function(e) {
5532            ..... 
5533         } ,
5534         .... 
5535     } 
5536   </code></pre>
5537  */
5538     
5539     
5540     /**
5541      * Fires the specified event with the passed parameters (minus the event name).
5542      * @param {String} eventName
5543      * @param {Object...} args Variable number of parameters are passed to handlers
5544      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5545      */
5546     fireEvent : function(){
5547         var ce = this.events[arguments[0].toLowerCase()];
5548         if(typeof ce == "object"){
5549             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5550         }else{
5551             return true;
5552         }
5553     },
5554
5555     // private
5556     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5557
5558     /**
5559      * Appends an event handler to this component
5560      * @param {String}   eventName The type of event to listen for
5561      * @param {Function} handler The method the event invokes
5562      * @param {Object}   scope (optional) The scope in which to execute the handler
5563      * function. The handler function's "this" context.
5564      * @param {Object}   options (optional) An object containing handler configuration
5565      * properties. This may contain any of the following properties:<ul>
5566      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5567      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5568      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5569      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5570      * by the specified number of milliseconds. If the event fires again within that time, the original
5571      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5572      * </ul><br>
5573      * <p>
5574      * <b>Combining Options</b><br>
5575      * Using the options argument, it is possible to combine different types of listeners:<br>
5576      * <br>
5577      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5578                 <pre><code>
5579                 el.on('click', this.onClick, this, {
5580                         single: true,
5581                 delay: 100,
5582                 forumId: 4
5583                 });
5584                 </code></pre>
5585      * <p>
5586      * <b>Attaching multiple handlers in 1 call</b><br>
5587      * The method also allows for a single argument to be passed which is a config object containing properties
5588      * which specify multiple handlers.
5589      * <pre><code>
5590                 el.on({
5591                         'click': {
5592                         fn: this.onClick,
5593                         scope: this,
5594                         delay: 100
5595                 }, 
5596                 'mouseover': {
5597                         fn: this.onMouseOver,
5598                         scope: this
5599                 },
5600                 'mouseout': {
5601                         fn: this.onMouseOut,
5602                         scope: this
5603                 }
5604                 });
5605                 </code></pre>
5606      * <p>
5607      * Or a shorthand syntax which passes the same scope object to all handlers:
5608         <pre><code>
5609                 el.on({
5610                         'click': this.onClick,
5611                 'mouseover': this.onMouseOver,
5612                 'mouseout': this.onMouseOut,
5613                 scope: this
5614                 });
5615                 </code></pre>
5616      */
5617     addListener : function(eventName, fn, scope, o){
5618         if(typeof eventName == "object"){
5619             o = eventName;
5620             for(var e in o){
5621                 if(this.filterOptRe.test(e)){
5622                     continue;
5623                 }
5624                 if(typeof o[e] == "function"){
5625                     // shared options
5626                     this.addListener(e, o[e], o.scope,  o);
5627                 }else{
5628                     // individual options
5629                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5630                 }
5631             }
5632             return;
5633         }
5634         o = (!o || typeof o == "boolean") ? {} : o;
5635         eventName = eventName.toLowerCase();
5636         var ce = this.events[eventName] || true;
5637         if(typeof ce == "boolean"){
5638             ce = new Roo.util.Event(this, eventName);
5639             this.events[eventName] = ce;
5640         }
5641         ce.addListener(fn, scope, o);
5642     },
5643
5644     /**
5645      * Removes a listener
5646      * @param {String}   eventName     The type of event to listen for
5647      * @param {Function} handler        The handler to remove
5648      * @param {Object}   scope  (optional) The scope (this object) for the handler
5649      */
5650     removeListener : function(eventName, fn, scope){
5651         var ce = this.events[eventName.toLowerCase()];
5652         if(typeof ce == "object"){
5653             ce.removeListener(fn, scope);
5654         }
5655     },
5656
5657     /**
5658      * Removes all listeners for this object
5659      */
5660     purgeListeners : function(){
5661         for(var evt in this.events){
5662             if(typeof this.events[evt] == "object"){
5663                  this.events[evt].clearListeners();
5664             }
5665         }
5666     },
5667
5668     relayEvents : function(o, events){
5669         var createHandler = function(ename){
5670             return function(){
5671                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5672             };
5673         };
5674         for(var i = 0, len = events.length; i < len; i++){
5675             var ename = events[i];
5676             if(!this.events[ename]){ this.events[ename] = true; };
5677             o.on(ename, createHandler(ename), this);
5678         }
5679     },
5680
5681     /**
5682      * Used to define events on this Observable
5683      * @param {Object} object The object with the events defined
5684      */
5685     addEvents : function(o){
5686         if(!this.events){
5687             this.events = {};
5688         }
5689         Roo.applyIf(this.events, o);
5690     },
5691
5692     /**
5693      * Checks to see if this object has any listeners for a specified event
5694      * @param {String} eventName The name of the event to check for
5695      * @return {Boolean} True if the event is being listened for, else false
5696      */
5697     hasListener : function(eventName){
5698         var e = this.events[eventName];
5699         return typeof e == "object" && e.listeners.length > 0;
5700     }
5701 };
5702 /**
5703  * Appends an event handler to this element (shorthand for addListener)
5704  * @param {String}   eventName     The type of event to listen for
5705  * @param {Function} handler        The method the event invokes
5706  * @param {Object}   scope (optional) The scope in which to execute the handler
5707  * function. The handler function's "this" context.
5708  * @param {Object}   options  (optional)
5709  * @method
5710  */
5711 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5712 /**
5713  * Removes a listener (shorthand for removeListener)
5714  * @param {String}   eventName     The type of event to listen for
5715  * @param {Function} handler        The handler to remove
5716  * @param {Object}   scope  (optional) The scope (this object) for the handler
5717  * @method
5718  */
5719 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5720
5721 /**
5722  * Starts capture on the specified Observable. All events will be passed
5723  * to the supplied function with the event name + standard signature of the event
5724  * <b>before</b> the event is fired. If the supplied function returns false,
5725  * the event will not fire.
5726  * @param {Observable} o The Observable to capture
5727  * @param {Function} fn The function to call
5728  * @param {Object} scope (optional) The scope (this object) for the fn
5729  * @static
5730  */
5731 Roo.util.Observable.capture = function(o, fn, scope){
5732     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5733 };
5734
5735 /**
5736  * Removes <b>all</b> added captures from the Observable.
5737  * @param {Observable} o The Observable to release
5738  * @static
5739  */
5740 Roo.util.Observable.releaseCapture = function(o){
5741     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5742 };
5743
5744 (function(){
5745
5746     var createBuffered = function(h, o, scope){
5747         var task = new Roo.util.DelayedTask();
5748         return function(){
5749             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5750         };
5751     };
5752
5753     var createSingle = function(h, e, fn, scope){
5754         return function(){
5755             e.removeListener(fn, scope);
5756             return h.apply(scope, arguments);
5757         };
5758     };
5759
5760     var createDelayed = function(h, o, scope){
5761         return function(){
5762             var args = Array.prototype.slice.call(arguments, 0);
5763             setTimeout(function(){
5764                 h.apply(scope, args);
5765             }, o.delay || 10);
5766         };
5767     };
5768
5769     Roo.util.Event = function(obj, name){
5770         this.name = name;
5771         this.obj = obj;
5772         this.listeners = [];
5773     };
5774
5775     Roo.util.Event.prototype = {
5776         addListener : function(fn, scope, options){
5777             var o = options || {};
5778             scope = scope || this.obj;
5779             if(!this.isListening(fn, scope)){
5780                 var l = {fn: fn, scope: scope, options: o};
5781                 var h = fn;
5782                 if(o.delay){
5783                     h = createDelayed(h, o, scope);
5784                 }
5785                 if(o.single){
5786                     h = createSingle(h, this, fn, scope);
5787                 }
5788                 if(o.buffer){
5789                     h = createBuffered(h, o, scope);
5790                 }
5791                 l.fireFn = h;
5792                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5793                     this.listeners.push(l);
5794                 }else{
5795                     this.listeners = this.listeners.slice(0);
5796                     this.listeners.push(l);
5797                 }
5798             }
5799         },
5800
5801         findListener : function(fn, scope){
5802             scope = scope || this.obj;
5803             var ls = this.listeners;
5804             for(var i = 0, len = ls.length; i < len; i++){
5805                 var l = ls[i];
5806                 if(l.fn == fn && l.scope == scope){
5807                     return i;
5808                 }
5809             }
5810             return -1;
5811         },
5812
5813         isListening : function(fn, scope){
5814             return this.findListener(fn, scope) != -1;
5815         },
5816
5817         removeListener : function(fn, scope){
5818             var index;
5819             if((index = this.findListener(fn, scope)) != -1){
5820                 if(!this.firing){
5821                     this.listeners.splice(index, 1);
5822                 }else{
5823                     this.listeners = this.listeners.slice(0);
5824                     this.listeners.splice(index, 1);
5825                 }
5826                 return true;
5827             }
5828             return false;
5829         },
5830
5831         clearListeners : function(){
5832             this.listeners = [];
5833         },
5834
5835         fire : function(){
5836             var ls = this.listeners, scope, len = ls.length;
5837             if(len > 0){
5838                 this.firing = true;
5839                 var args = Array.prototype.slice.call(arguments, 0);
5840                 for(var i = 0; i < len; i++){
5841                     var l = ls[i];
5842                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5843                         this.firing = false;
5844                         return false;
5845                     }
5846                 }
5847                 this.firing = false;
5848             }
5849             return true;
5850         }
5851     };
5852 })();/*
5853  * Based on:
5854  * Ext JS Library 1.1.1
5855  * Copyright(c) 2006-2007, Ext JS, LLC.
5856  *
5857  * Originally Released Under LGPL - original licence link has changed is not relivant.
5858  *
5859  * Fork - LGPL
5860  * <script type="text/javascript">
5861  */
5862
5863 /**
5864  * @class Roo.EventManager
5865  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5866  * several useful events directly.
5867  * See {@link Roo.EventObject} for more details on normalized event objects.
5868  * @singleton
5869  */
5870 Roo.EventManager = function(){
5871     var docReadyEvent, docReadyProcId, docReadyState = false;
5872     var resizeEvent, resizeTask, textEvent, textSize;
5873     var E = Roo.lib.Event;
5874     var D = Roo.lib.Dom;
5875
5876
5877     var fireDocReady = function(){
5878         if(!docReadyState){
5879             docReadyState = true;
5880             Roo.isReady = true;
5881             if(docReadyProcId){
5882                 clearInterval(docReadyProcId);
5883             }
5884             if(Roo.isGecko || Roo.isOpera) {
5885                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5886             }
5887             if(Roo.isIE){
5888                 var defer = document.getElementById("ie-deferred-loader");
5889                 if(defer){
5890                     defer.onreadystatechange = null;
5891                     defer.parentNode.removeChild(defer);
5892                 }
5893             }
5894             if(docReadyEvent){
5895                 docReadyEvent.fire();
5896                 docReadyEvent.clearListeners();
5897             }
5898         }
5899     };
5900     
5901     var initDocReady = function(){
5902         docReadyEvent = new Roo.util.Event();
5903         if(Roo.isGecko || Roo.isOpera) {
5904             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5905         }else if(Roo.isIE){
5906             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5907             var defer = document.getElementById("ie-deferred-loader");
5908             defer.onreadystatechange = function(){
5909                 if(this.readyState == "complete"){
5910                     fireDocReady();
5911                 }
5912             };
5913         }else if(Roo.isSafari){ 
5914             docReadyProcId = setInterval(function(){
5915                 var rs = document.readyState;
5916                 if(rs == "complete") {
5917                     fireDocReady();     
5918                  }
5919             }, 10);
5920         }
5921         // no matter what, make sure it fires on load
5922         E.on(window, "load", fireDocReady);
5923     };
5924
5925     var createBuffered = function(h, o){
5926         var task = new Roo.util.DelayedTask(h);
5927         return function(e){
5928             // create new event object impl so new events don't wipe out properties
5929             e = new Roo.EventObjectImpl(e);
5930             task.delay(o.buffer, h, null, [e]);
5931         };
5932     };
5933
5934     var createSingle = function(h, el, ename, fn){
5935         return function(e){
5936             Roo.EventManager.removeListener(el, ename, fn);
5937             h(e);
5938         };
5939     };
5940
5941     var createDelayed = function(h, o){
5942         return function(e){
5943             // create new event object impl so new events don't wipe out properties
5944             e = new Roo.EventObjectImpl(e);
5945             setTimeout(function(){
5946                 h(e);
5947             }, o.delay || 10);
5948         };
5949     };
5950
5951     var listen = function(element, ename, opt, fn, scope){
5952         var o = (!opt || typeof opt == "boolean") ? {} : opt;
5953         fn = fn || o.fn; scope = scope || o.scope;
5954         var el = Roo.getDom(element);
5955         if(!el){
5956             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5957         }
5958         var h = function(e){
5959             e = Roo.EventObject.setEvent(e);
5960             var t;
5961             if(o.delegate){
5962                 t = e.getTarget(o.delegate, el);
5963                 if(!t){
5964                     return;
5965                 }
5966             }else{
5967                 t = e.target;
5968             }
5969             if(o.stopEvent === true){
5970                 e.stopEvent();
5971             }
5972             if(o.preventDefault === true){
5973                e.preventDefault();
5974             }
5975             if(o.stopPropagation === true){
5976                 e.stopPropagation();
5977             }
5978
5979             if(o.normalized === false){
5980                 e = e.browserEvent;
5981             }
5982
5983             fn.call(scope || el, e, t, o);
5984         };
5985         if(o.delay){
5986             h = createDelayed(h, o);
5987         }
5988         if(o.single){
5989             h = createSingle(h, el, ename, fn);
5990         }
5991         if(o.buffer){
5992             h = createBuffered(h, o);
5993         }
5994         fn._handlers = fn._handlers || [];
5995         fn._handlers.push([Roo.id(el), ename, h]);
5996
5997         E.on(el, ename, h);
5998         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5999             el.addEventListener("DOMMouseScroll", h, false);
6000             E.on(window, 'unload', function(){
6001                 el.removeEventListener("DOMMouseScroll", h, false);
6002             });
6003         }
6004         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6005             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6006         }
6007         return h;
6008     };
6009
6010     var stopListening = function(el, ename, fn){
6011         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6012         if(hds){
6013             for(var i = 0, len = hds.length; i < len; i++){
6014                 var h = hds[i];
6015                 if(h[0] == id && h[1] == ename){
6016                     hd = h[2];
6017                     hds.splice(i, 1);
6018                     break;
6019                 }
6020             }
6021         }
6022         E.un(el, ename, hd);
6023         el = Roo.getDom(el);
6024         if(ename == "mousewheel" && el.addEventListener){
6025             el.removeEventListener("DOMMouseScroll", hd, false);
6026         }
6027         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6028             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6029         }
6030     };
6031
6032     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6033     
6034     var pub = {
6035         
6036         
6037         /** 
6038          * Fix for doc tools
6039          * @scope Roo.EventManager
6040          */
6041         
6042         
6043         /** 
6044          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6045          * object with a Roo.EventObject
6046          * @param {Function} fn        The method the event invokes
6047          * @param {Object}   scope    An object that becomes the scope of the handler
6048          * @param {boolean}  override If true, the obj passed in becomes
6049          *                             the execution scope of the listener
6050          * @return {Function} The wrapped function
6051          * @deprecated
6052          */
6053         wrap : function(fn, scope, override){
6054             return function(e){
6055                 Roo.EventObject.setEvent(e);
6056                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6057             };
6058         },
6059         
6060         /**
6061      * Appends an event handler to an element (shorthand for addListener)
6062      * @param {String/HTMLElement}   element        The html element or id to assign the
6063      * @param {String}   eventName The type of event to listen for
6064      * @param {Function} handler The method the event invokes
6065      * @param {Object}   scope (optional) The scope in which to execute the handler
6066      * function. The handler function's "this" context.
6067      * @param {Object}   options (optional) An object containing handler configuration
6068      * properties. This may contain any of the following properties:<ul>
6069      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6070      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6071      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6072      * <li>preventDefault {Boolean} True to prevent the default action</li>
6073      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6074      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6075      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6076      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6077      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6078      * by the specified number of milliseconds. If the event fires again within that time, the original
6079      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6080      * </ul><br>
6081      * <p>
6082      * <b>Combining Options</b><br>
6083      * Using the options argument, it is possible to combine different types of listeners:<br>
6084      * <br>
6085      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6086      * Code:<pre><code>
6087 el.on('click', this.onClick, this, {
6088     single: true,
6089     delay: 100,
6090     stopEvent : true,
6091     forumId: 4
6092 });</code></pre>
6093      * <p>
6094      * <b>Attaching multiple handlers in 1 call</b><br>
6095       * The method also allows for a single argument to be passed which is a config object containing properties
6096      * which specify multiple handlers.
6097      * <p>
6098      * Code:<pre><code>
6099 el.on({
6100     'click' : {
6101         fn: this.onClick
6102         scope: this,
6103         delay: 100
6104     },
6105     'mouseover' : {
6106         fn: this.onMouseOver
6107         scope: this
6108     },
6109     'mouseout' : {
6110         fn: this.onMouseOut
6111         scope: this
6112     }
6113 });</code></pre>
6114      * <p>
6115      * Or a shorthand syntax:<br>
6116      * Code:<pre><code>
6117 el.on({
6118     'click' : this.onClick,
6119     'mouseover' : this.onMouseOver,
6120     'mouseout' : this.onMouseOut
6121     scope: this
6122 });</code></pre>
6123      */
6124         addListener : function(element, eventName, fn, scope, options){
6125             if(typeof eventName == "object"){
6126                 var o = eventName;
6127                 for(var e in o){
6128                     if(propRe.test(e)){
6129                         continue;
6130                     }
6131                     if(typeof o[e] == "function"){
6132                         // shared options
6133                         listen(element, e, o, o[e], o.scope);
6134                     }else{
6135                         // individual options
6136                         listen(element, e, o[e]);
6137                     }
6138                 }
6139                 return;
6140             }
6141             return listen(element, eventName, options, fn, scope);
6142         },
6143         
6144         /**
6145          * Removes an event handler
6146          *
6147          * @param {String/HTMLElement}   element        The id or html element to remove the 
6148          *                             event from
6149          * @param {String}   eventName     The type of event
6150          * @param {Function} fn
6151          * @return {Boolean} True if a listener was actually removed
6152          */
6153         removeListener : function(element, eventName, fn){
6154             return stopListening(element, eventName, fn);
6155         },
6156         
6157         /**
6158          * Fires when the document is ready (before onload and before images are loaded). Can be 
6159          * accessed shorthanded Roo.onReady().
6160          * @param {Function} fn        The method the event invokes
6161          * @param {Object}   scope    An  object that becomes the scope of the handler
6162          * @param {boolean}  options
6163          */
6164         onDocumentReady : function(fn, scope, options){
6165             if(docReadyState){ // if it already fired
6166                 docReadyEvent.addListener(fn, scope, options);
6167                 docReadyEvent.fire();
6168                 docReadyEvent.clearListeners();
6169                 return;
6170             }
6171             if(!docReadyEvent){
6172                 initDocReady();
6173             }
6174             docReadyEvent.addListener(fn, scope, options);
6175         },
6176         
6177         /**
6178          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6179          * @param {Function} fn        The method the event invokes
6180          * @param {Object}   scope    An object that becomes the scope of the handler
6181          * @param {boolean}  options
6182          */
6183         onWindowResize : function(fn, scope, options){
6184             if(!resizeEvent){
6185                 resizeEvent = new Roo.util.Event();
6186                 resizeTask = new Roo.util.DelayedTask(function(){
6187                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6188                 });
6189                 E.on(window, "resize", function(){
6190                     if(Roo.isIE){
6191                         resizeTask.delay(50);
6192                     }else{
6193                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6194                     }
6195                 });
6196             }
6197             resizeEvent.addListener(fn, scope, options);
6198         },
6199
6200         /**
6201          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6202          * @param {Function} fn        The method the event invokes
6203          * @param {Object}   scope    An object that becomes the scope of the handler
6204          * @param {boolean}  options
6205          */
6206         onTextResize : function(fn, scope, options){
6207             if(!textEvent){
6208                 textEvent = new Roo.util.Event();
6209                 var textEl = new Roo.Element(document.createElement('div'));
6210                 textEl.dom.className = 'x-text-resize';
6211                 textEl.dom.innerHTML = 'X';
6212                 textEl.appendTo(document.body);
6213                 textSize = textEl.dom.offsetHeight;
6214                 setInterval(function(){
6215                     if(textEl.dom.offsetHeight != textSize){
6216                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6217                     }
6218                 }, this.textResizeInterval);
6219             }
6220             textEvent.addListener(fn, scope, options);
6221         },
6222
6223         /**
6224          * Removes the passed window resize listener.
6225          * @param {Function} fn        The method the event invokes
6226          * @param {Object}   scope    The scope of handler
6227          */
6228         removeResizeListener : function(fn, scope){
6229             if(resizeEvent){
6230                 resizeEvent.removeListener(fn, scope);
6231             }
6232         },
6233
6234         // private
6235         fireResize : function(){
6236             if(resizeEvent){
6237                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6238             }   
6239         },
6240         /**
6241          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6242          */
6243         ieDeferSrc : false,
6244         /**
6245          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6246          */
6247         textResizeInterval : 50
6248     };
6249     
6250     /**
6251      * Fix for doc tools
6252      * @scopeAlias pub=Roo.EventManager
6253      */
6254     
6255      /**
6256      * Appends an event handler to an element (shorthand for addListener)
6257      * @param {String/HTMLElement}   element        The html element or id to assign the
6258      * @param {String}   eventName The type of event to listen for
6259      * @param {Function} handler The method the event invokes
6260      * @param {Object}   scope (optional) The scope in which to execute the handler
6261      * function. The handler function's "this" context.
6262      * @param {Object}   options (optional) An object containing handler configuration
6263      * properties. This may contain any of the following properties:<ul>
6264      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6265      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6266      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6267      * <li>preventDefault {Boolean} True to prevent the default action</li>
6268      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6269      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6270      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6271      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6272      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6273      * by the specified number of milliseconds. If the event fires again within that time, the original
6274      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6275      * </ul><br>
6276      * <p>
6277      * <b>Combining Options</b><br>
6278      * Using the options argument, it is possible to combine different types of listeners:<br>
6279      * <br>
6280      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6281      * Code:<pre><code>
6282 el.on('click', this.onClick, this, {
6283     single: true,
6284     delay: 100,
6285     stopEvent : true,
6286     forumId: 4
6287 });</code></pre>
6288      * <p>
6289      * <b>Attaching multiple handlers in 1 call</b><br>
6290       * The method also allows for a single argument to be passed which is a config object containing properties
6291      * which specify multiple handlers.
6292      * <p>
6293      * Code:<pre><code>
6294 el.on({
6295     'click' : {
6296         fn: this.onClick
6297         scope: this,
6298         delay: 100
6299     },
6300     'mouseover' : {
6301         fn: this.onMouseOver
6302         scope: this
6303     },
6304     'mouseout' : {
6305         fn: this.onMouseOut
6306         scope: this
6307     }
6308 });</code></pre>
6309      * <p>
6310      * Or a shorthand syntax:<br>
6311      * Code:<pre><code>
6312 el.on({
6313     'click' : this.onClick,
6314     'mouseover' : this.onMouseOver,
6315     'mouseout' : this.onMouseOut
6316     scope: this
6317 });</code></pre>
6318      */
6319     pub.on = pub.addListener;
6320     pub.un = pub.removeListener;
6321
6322     pub.stoppedMouseDownEvent = new Roo.util.Event();
6323     return pub;
6324 }();
6325 /**
6326   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6327   * @param {Function} fn        The method the event invokes
6328   * @param {Object}   scope    An  object that becomes the scope of the handler
6329   * @param {boolean}  override If true, the obj passed in becomes
6330   *                             the execution scope of the listener
6331   * @member Roo
6332   * @method onReady
6333  */
6334 Roo.onReady = Roo.EventManager.onDocumentReady;
6335
6336 Roo.onReady(function(){
6337     var bd = Roo.get(document.body);
6338     if(!bd){ return; }
6339
6340     var cls = [
6341             Roo.isIE ? "roo-ie"
6342             : Roo.isGecko ? "roo-gecko"
6343             : Roo.isOpera ? "roo-opera"
6344             : Roo.isSafari ? "roo-safari" : ""];
6345
6346     if(Roo.isMac){
6347         cls.push("roo-mac");
6348     }
6349     if(Roo.isLinux){
6350         cls.push("roo-linux");
6351     }
6352     if(Roo.isBorderBox){
6353         cls.push('roo-border-box');
6354     }
6355     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6356         var p = bd.dom.parentNode;
6357         if(p){
6358             p.className += ' roo-strict';
6359         }
6360     }
6361     bd.addClass(cls.join(' '));
6362 });
6363
6364 /**
6365  * @class Roo.EventObject
6366  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6367  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6368  * Example:
6369  * <pre><code>
6370  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6371     e.preventDefault();
6372     var target = e.getTarget();
6373     ...
6374  }
6375  var myDiv = Roo.get("myDiv");
6376  myDiv.on("click", handleClick);
6377  //or
6378  Roo.EventManager.on("myDiv", 'click', handleClick);
6379  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6380  </code></pre>
6381  * @singleton
6382  */
6383 Roo.EventObject = function(){
6384     
6385     var E = Roo.lib.Event;
6386     
6387     // safari keypress events for special keys return bad keycodes
6388     var safariKeys = {
6389         63234 : 37, // left
6390         63235 : 39, // right
6391         63232 : 38, // up
6392         63233 : 40, // down
6393         63276 : 33, // page up
6394         63277 : 34, // page down
6395         63272 : 46, // delete
6396         63273 : 36, // home
6397         63275 : 35  // end
6398     };
6399
6400     // normalize button clicks
6401     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6402                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6403
6404     Roo.EventObjectImpl = function(e){
6405         if(e){
6406             this.setEvent(e.browserEvent || e);
6407         }
6408     };
6409     Roo.EventObjectImpl.prototype = {
6410         /**
6411          * Used to fix doc tools.
6412          * @scope Roo.EventObject.prototype
6413          */
6414             
6415
6416         
6417         
6418         /** The normal browser event */
6419         browserEvent : null,
6420         /** The button pressed in a mouse event */
6421         button : -1,
6422         /** True if the shift key was down during the event */
6423         shiftKey : false,
6424         /** True if the control key was down during the event */
6425         ctrlKey : false,
6426         /** True if the alt key was down during the event */
6427         altKey : false,
6428
6429         /** Key constant 
6430         * @type Number */
6431         BACKSPACE : 8,
6432         /** Key constant 
6433         * @type Number */
6434         TAB : 9,
6435         /** Key constant 
6436         * @type Number */
6437         RETURN : 13,
6438         /** Key constant 
6439         * @type Number */
6440         ENTER : 13,
6441         /** Key constant 
6442         * @type Number */
6443         SHIFT : 16,
6444         /** Key constant 
6445         * @type Number */
6446         CONTROL : 17,
6447         /** Key constant 
6448         * @type Number */
6449         ESC : 27,
6450         /** Key constant 
6451         * @type Number */
6452         SPACE : 32,
6453         /** Key constant 
6454         * @type Number */
6455         PAGEUP : 33,
6456         /** Key constant 
6457         * @type Number */
6458         PAGEDOWN : 34,
6459         /** Key constant 
6460         * @type Number */
6461         END : 35,
6462         /** Key constant 
6463         * @type Number */
6464         HOME : 36,
6465         /** Key constant 
6466         * @type Number */
6467         LEFT : 37,
6468         /** Key constant 
6469         * @type Number */
6470         UP : 38,
6471         /** Key constant 
6472         * @type Number */
6473         RIGHT : 39,
6474         /** Key constant 
6475         * @type Number */
6476         DOWN : 40,
6477         /** Key constant 
6478         * @type Number */
6479         DELETE : 46,
6480         /** Key constant 
6481         * @type Number */
6482         F5 : 116,
6483
6484            /** @private */
6485         setEvent : function(e){
6486             if(e == this || (e && e.browserEvent)){ // already wrapped
6487                 return e;
6488             }
6489             this.browserEvent = e;
6490             if(e){
6491                 // normalize buttons
6492                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6493                 if(e.type == 'click' && this.button == -1){
6494                     this.button = 0;
6495                 }
6496                 this.type = e.type;
6497                 this.shiftKey = e.shiftKey;
6498                 // mac metaKey behaves like ctrlKey
6499                 this.ctrlKey = e.ctrlKey || e.metaKey;
6500                 this.altKey = e.altKey;
6501                 // in getKey these will be normalized for the mac
6502                 this.keyCode = e.keyCode;
6503                 // keyup warnings on firefox.
6504                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6505                 // cache the target for the delayed and or buffered events
6506                 this.target = E.getTarget(e);
6507                 // same for XY
6508                 this.xy = E.getXY(e);
6509             }else{
6510                 this.button = -1;
6511                 this.shiftKey = false;
6512                 this.ctrlKey = false;
6513                 this.altKey = false;
6514                 this.keyCode = 0;
6515                 this.charCode =0;
6516                 this.target = null;
6517                 this.xy = [0, 0];
6518             }
6519             return this;
6520         },
6521
6522         /**
6523          * Stop the event (preventDefault and stopPropagation)
6524          */
6525         stopEvent : function(){
6526             if(this.browserEvent){
6527                 if(this.browserEvent.type == 'mousedown'){
6528                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6529                 }
6530                 E.stopEvent(this.browserEvent);
6531             }
6532         },
6533
6534         /**
6535          * Prevents the browsers default handling of the event.
6536          */
6537         preventDefault : function(){
6538             if(this.browserEvent){
6539                 E.preventDefault(this.browserEvent);
6540             }
6541         },
6542
6543         /** @private */
6544         isNavKeyPress : function(){
6545             var k = this.keyCode;
6546             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6547             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6548         },
6549
6550         isSpecialKey : function(){
6551             var k = this.keyCode;
6552             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6553             (k == 16) || (k == 17) ||
6554             (k >= 18 && k <= 20) ||
6555             (k >= 33 && k <= 35) ||
6556             (k >= 36 && k <= 39) ||
6557             (k >= 44 && k <= 45);
6558         },
6559         /**
6560          * Cancels bubbling of the event.
6561          */
6562         stopPropagation : function(){
6563             if(this.browserEvent){
6564                 if(this.type == 'mousedown'){
6565                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6566                 }
6567                 E.stopPropagation(this.browserEvent);
6568             }
6569         },
6570
6571         /**
6572          * Gets the key code for the event.
6573          * @return {Number}
6574          */
6575         getCharCode : function(){
6576             return this.charCode || this.keyCode;
6577         },
6578
6579         /**
6580          * Returns a normalized keyCode for the event.
6581          * @return {Number} The key code
6582          */
6583         getKey : function(){
6584             var k = this.keyCode || this.charCode;
6585             return Roo.isSafari ? (safariKeys[k] || k) : k;
6586         },
6587
6588         /**
6589          * Gets the x coordinate of the event.
6590          * @return {Number}
6591          */
6592         getPageX : function(){
6593             return this.xy[0];
6594         },
6595
6596         /**
6597          * Gets the y coordinate of the event.
6598          * @return {Number}
6599          */
6600         getPageY : function(){
6601             return this.xy[1];
6602         },
6603
6604         /**
6605          * Gets the time of the event.
6606          * @return {Number}
6607          */
6608         getTime : function(){
6609             if(this.browserEvent){
6610                 return E.getTime(this.browserEvent);
6611             }
6612             return null;
6613         },
6614
6615         /**
6616          * Gets the page coordinates of the event.
6617          * @return {Array} The xy values like [x, y]
6618          */
6619         getXY : function(){
6620             return this.xy;
6621         },
6622
6623         /**
6624          * Gets the target for the event.
6625          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6626          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6627                 search as a number or element (defaults to 10 || document.body)
6628          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6629          * @return {HTMLelement}
6630          */
6631         getTarget : function(selector, maxDepth, returnEl){
6632             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6633         },
6634         /**
6635          * Gets the related target.
6636          * @return {HTMLElement}
6637          */
6638         getRelatedTarget : function(){
6639             if(this.browserEvent){
6640                 return E.getRelatedTarget(this.browserEvent);
6641             }
6642             return null;
6643         },
6644
6645         /**
6646          * Normalizes mouse wheel delta across browsers
6647          * @return {Number} The delta
6648          */
6649         getWheelDelta : function(){
6650             var e = this.browserEvent;
6651             var delta = 0;
6652             if(e.wheelDelta){ /* IE/Opera. */
6653                 delta = e.wheelDelta/120;
6654             }else if(e.detail){ /* Mozilla case. */
6655                 delta = -e.detail/3;
6656             }
6657             return delta;
6658         },
6659
6660         /**
6661          * Returns true if the control, meta, shift or alt key was pressed during this event.
6662          * @return {Boolean}
6663          */
6664         hasModifier : function(){
6665             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6666         },
6667
6668         /**
6669          * Returns true if the target of this event equals el or is a child of el
6670          * @param {String/HTMLElement/Element} el
6671          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6672          * @return {Boolean}
6673          */
6674         within : function(el, related){
6675             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6676             return t && Roo.fly(el).contains(t);
6677         },
6678
6679         getPoint : function(){
6680             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6681         }
6682     };
6683
6684     return new Roo.EventObjectImpl();
6685 }();
6686             
6687     /*
6688  * Based on:
6689  * Ext JS Library 1.1.1
6690  * Copyright(c) 2006-2007, Ext JS, LLC.
6691  *
6692  * Originally Released Under LGPL - original licence link has changed is not relivant.
6693  *
6694  * Fork - LGPL
6695  * <script type="text/javascript">
6696  */
6697
6698  
6699 // was in Composite Element!??!?!
6700  
6701 (function(){
6702     var D = Roo.lib.Dom;
6703     var E = Roo.lib.Event;
6704     var A = Roo.lib.Anim;
6705
6706     // local style camelizing for speed
6707     var propCache = {};
6708     var camelRe = /(-[a-z])/gi;
6709     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6710     var view = document.defaultView;
6711
6712 /**
6713  * @class Roo.Element
6714  * Represents an Element in the DOM.<br><br>
6715  * Usage:<br>
6716 <pre><code>
6717 var el = Roo.get("my-div");
6718
6719 // or with getEl
6720 var el = getEl("my-div");
6721
6722 // or with a DOM element
6723 var el = Roo.get(myDivElement);
6724 </code></pre>
6725  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6726  * each call instead of constructing a new one.<br><br>
6727  * <b>Animations</b><br />
6728  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6729  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6730 <pre>
6731 Option    Default   Description
6732 --------- --------  ---------------------------------------------
6733 duration  .35       The duration of the animation in seconds
6734 easing    easeOut   The YUI easing method
6735 callback  none      A function to execute when the anim completes
6736 scope     this      The scope (this) of the callback function
6737 </pre>
6738 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6739 * manipulate the animation. Here's an example:
6740 <pre><code>
6741 var el = Roo.get("my-div");
6742
6743 // no animation
6744 el.setWidth(100);
6745
6746 // default animation
6747 el.setWidth(100, true);
6748
6749 // animation with some options set
6750 el.setWidth(100, {
6751     duration: 1,
6752     callback: this.foo,
6753     scope: this
6754 });
6755
6756 // using the "anim" property to get the Anim object
6757 var opt = {
6758     duration: 1,
6759     callback: this.foo,
6760     scope: this
6761 };
6762 el.setWidth(100, opt);
6763 ...
6764 if(opt.anim.isAnimated()){
6765     opt.anim.stop();
6766 }
6767 </code></pre>
6768 * <b> Composite (Collections of) Elements</b><br />
6769  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6770  * @constructor Create a new Element directly.
6771  * @param {String/HTMLElement} element
6772  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6773  */
6774     Roo.Element = function(element, forceNew){
6775         var dom = typeof element == "string" ?
6776                 document.getElementById(element) : element;
6777         if(!dom){ // invalid id/element
6778             return null;
6779         }
6780         var id = dom.id;
6781         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6782             return Roo.Element.cache[id];
6783         }
6784
6785         /**
6786          * The DOM element
6787          * @type HTMLElement
6788          */
6789         this.dom = dom;
6790
6791         /**
6792          * The DOM element ID
6793          * @type String
6794          */
6795         this.id = id || Roo.id(dom);
6796     };
6797
6798     var El = Roo.Element;
6799
6800     El.prototype = {
6801         /**
6802          * The element's default display mode  (defaults to "")
6803          * @type String
6804          */
6805         originalDisplay : "",
6806
6807         visibilityMode : 1,
6808         /**
6809          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6810          * @type String
6811          */
6812         defaultUnit : "px",
6813         /**
6814          * Sets the element's visibility mode. When setVisible() is called it
6815          * will use this to determine whether to set the visibility or the display property.
6816          * @param visMode Element.VISIBILITY or Element.DISPLAY
6817          * @return {Roo.Element} this
6818          */
6819         setVisibilityMode : function(visMode){
6820             this.visibilityMode = visMode;
6821             return this;
6822         },
6823         /**
6824          * Convenience method for setVisibilityMode(Element.DISPLAY)
6825          * @param {String} display (optional) What to set display to when visible
6826          * @return {Roo.Element} this
6827          */
6828         enableDisplayMode : function(display){
6829             this.setVisibilityMode(El.DISPLAY);
6830             if(typeof display != "undefined") this.originalDisplay = display;
6831             return this;
6832         },
6833
6834         /**
6835          * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6836          * @param {String} selector The simple selector to test
6837          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6838                 search as a number or element (defaults to 10 || document.body)
6839          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6840          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6841          */
6842         findParent : function(simpleSelector, maxDepth, returnEl){
6843             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6844             maxDepth = maxDepth || 50;
6845             if(typeof maxDepth != "number"){
6846                 stopEl = Roo.getDom(maxDepth);
6847                 maxDepth = 10;
6848             }
6849             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6850                 if(dq.is(p, simpleSelector)){
6851                     return returnEl ? Roo.get(p) : p;
6852                 }
6853                 depth++;
6854                 p = p.parentNode;
6855             }
6856             return null;
6857         },
6858
6859
6860         /**
6861          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6862          * @param {String} selector The simple selector to test
6863          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6864                 search as a number or element (defaults to 10 || document.body)
6865          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6866          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6867          */
6868         findParentNode : function(simpleSelector, maxDepth, returnEl){
6869             var p = Roo.fly(this.dom.parentNode, '_internal');
6870             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6871         },
6872
6873         /**
6874          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6875          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6876          * @param {String} selector The simple selector to test
6877          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6878                 search as a number or element (defaults to 10 || document.body)
6879          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6880          */
6881         up : function(simpleSelector, maxDepth){
6882             return this.findParentNode(simpleSelector, maxDepth, true);
6883         },
6884
6885
6886
6887         /**
6888          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6889          * @param {String} selector The simple selector to test
6890          * @return {Boolean} True if this element matches the selector, else false
6891          */
6892         is : function(simpleSelector){
6893             return Roo.DomQuery.is(this.dom, simpleSelector);
6894         },
6895
6896         /**
6897          * Perform animation on this element.
6898          * @param {Object} args The YUI animation control args
6899          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6900          * @param {Function} onComplete (optional) Function to call when animation completes
6901          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6902          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6903          * @return {Roo.Element} this
6904          */
6905         animate : function(args, duration, onComplete, easing, animType){
6906             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6907             return this;
6908         },
6909
6910         /*
6911          * @private Internal animation call
6912          */
6913         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6914             animType = animType || 'run';
6915             opt = opt || {};
6916             var anim = Roo.lib.Anim[animType](
6917                 this.dom, args,
6918                 (opt.duration || defaultDur) || .35,
6919                 (opt.easing || defaultEase) || 'easeOut',
6920                 function(){
6921                     Roo.callback(cb, this);
6922                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6923                 },
6924                 this
6925             );
6926             opt.anim = anim;
6927             return anim;
6928         },
6929
6930         // private legacy anim prep
6931         preanim : function(a, i){
6932             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6933         },
6934
6935         /**
6936          * Removes worthless text nodes
6937          * @param {Boolean} forceReclean (optional) By default the element
6938          * keeps track if it has been cleaned already so
6939          * you can call this over and over. However, if you update the element and
6940          * need to force a reclean, you can pass true.
6941          */
6942         clean : function(forceReclean){
6943             if(this.isCleaned && forceReclean !== true){
6944                 return this;
6945             }
6946             var ns = /\S/;
6947             var d = this.dom, n = d.firstChild, ni = -1;
6948             while(n){
6949                 var nx = n.nextSibling;
6950                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6951                     d.removeChild(n);
6952                 }else{
6953                     n.nodeIndex = ++ni;
6954                 }
6955                 n = nx;
6956             }
6957             this.isCleaned = true;
6958             return this;
6959         },
6960
6961         // private
6962         calcOffsetsTo : function(el){
6963             el = Roo.get(el);
6964             var d = el.dom;
6965             var restorePos = false;
6966             if(el.getStyle('position') == 'static'){
6967                 el.position('relative');
6968                 restorePos = true;
6969             }
6970             var x = 0, y =0;
6971             var op = this.dom;
6972             while(op && op != d && op.tagName != 'HTML'){
6973                 x+= op.offsetLeft;
6974                 y+= op.offsetTop;
6975                 op = op.offsetParent;
6976             }
6977             if(restorePos){
6978                 el.position('static');
6979             }
6980             return [x, y];
6981         },
6982
6983         /**
6984          * Scrolls this element into view within the passed container.
6985          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6986          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6987          * @return {Roo.Element} this
6988          */
6989         scrollIntoView : function(container, hscroll){
6990             var c = Roo.getDom(container) || document.body;
6991             var el = this.dom;
6992
6993             var o = this.calcOffsetsTo(c),
6994                 l = o[0],
6995                 t = o[1],
6996                 b = t+el.offsetHeight,
6997                 r = l+el.offsetWidth;
6998
6999             var ch = c.clientHeight;
7000             var ct = parseInt(c.scrollTop, 10);
7001             var cl = parseInt(c.scrollLeft, 10);
7002             var cb = ct + ch;
7003             var cr = cl + c.clientWidth;
7004
7005             if(t < ct){
7006                 c.scrollTop = t;
7007             }else if(b > cb){
7008                 c.scrollTop = b-ch;
7009             }
7010
7011             if(hscroll !== false){
7012                 if(l < cl){
7013                     c.scrollLeft = l;
7014                 }else if(r > cr){
7015                     c.scrollLeft = r-c.clientWidth;
7016                 }
7017             }
7018             return this;
7019         },
7020
7021         // private
7022         scrollChildIntoView : function(child, hscroll){
7023             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7024         },
7025
7026         /**
7027          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7028          * the new height may not be available immediately.
7029          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7030          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7031          * @param {Function} onComplete (optional) Function to call when animation completes
7032          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7033          * @return {Roo.Element} this
7034          */
7035         autoHeight : function(animate, duration, onComplete, easing){
7036             var oldHeight = this.getHeight();
7037             this.clip();
7038             this.setHeight(1); // force clipping
7039             setTimeout(function(){
7040                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7041                 if(!animate){
7042                     this.setHeight(height);
7043                     this.unclip();
7044                     if(typeof onComplete == "function"){
7045                         onComplete();
7046                     }
7047                 }else{
7048                     this.setHeight(oldHeight); // restore original height
7049                     this.setHeight(height, animate, duration, function(){
7050                         this.unclip();
7051                         if(typeof onComplete == "function") onComplete();
7052                     }.createDelegate(this), easing);
7053                 }
7054             }.createDelegate(this), 0);
7055             return this;
7056         },
7057
7058         /**
7059          * Returns true if this element is an ancestor of the passed element
7060          * @param {HTMLElement/String} el The element to check
7061          * @return {Boolean} True if this element is an ancestor of el, else false
7062          */
7063         contains : function(el){
7064             if(!el){return false;}
7065             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7066         },
7067
7068         /**
7069          * Checks whether the element is currently visible using both visibility and display properties.
7070          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7071          * @return {Boolean} True if the element is currently visible, else false
7072          */
7073         isVisible : function(deep) {
7074             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7075             if(deep !== true || !vis){
7076                 return vis;
7077             }
7078             var p = this.dom.parentNode;
7079             while(p && p.tagName.toLowerCase() != "body"){
7080                 if(!Roo.fly(p, '_isVisible').isVisible()){
7081                     return false;
7082                 }
7083                 p = p.parentNode;
7084             }
7085             return true;
7086         },
7087
7088         /**
7089          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7090          * @param {String} selector The CSS selector
7091          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7092          * @return {CompositeElement/CompositeElementLite} The composite element
7093          */
7094         select : function(selector, unique){
7095             return El.select(selector, unique, this.dom);
7096         },
7097
7098         /**
7099          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7100          * @param {String} selector The CSS selector
7101          * @return {Array} An array of the matched nodes
7102          */
7103         query : function(selector, unique){
7104             return Roo.DomQuery.select(selector, this.dom);
7105         },
7106
7107         /**
7108          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7109          * @param {String} selector The CSS selector
7110          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7111          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7112          */
7113         child : function(selector, returnDom){
7114             var n = Roo.DomQuery.selectNode(selector, this.dom);
7115             return returnDom ? n : Roo.get(n);
7116         },
7117
7118         /**
7119          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7120          * @param {String} selector The CSS selector
7121          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7122          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7123          */
7124         down : function(selector, returnDom){
7125             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7126             return returnDom ? n : Roo.get(n);
7127         },
7128
7129         /**
7130          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7131          * @param {String} group The group the DD object is member of
7132          * @param {Object} config The DD config object
7133          * @param {Object} overrides An object containing methods to override/implement on the DD object
7134          * @return {Roo.dd.DD} The DD object
7135          */
7136         initDD : function(group, config, overrides){
7137             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7138             return Roo.apply(dd, overrides);
7139         },
7140
7141         /**
7142          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7143          * @param {String} group The group the DDProxy object is member of
7144          * @param {Object} config The DDProxy config object
7145          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7146          * @return {Roo.dd.DDProxy} The DDProxy object
7147          */
7148         initDDProxy : function(group, config, overrides){
7149             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7150             return Roo.apply(dd, overrides);
7151         },
7152
7153         /**
7154          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7155          * @param {String} group The group the DDTarget object is member of
7156          * @param {Object} config The DDTarget config object
7157          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7158          * @return {Roo.dd.DDTarget} The DDTarget object
7159          */
7160         initDDTarget : function(group, config, overrides){
7161             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7162             return Roo.apply(dd, overrides);
7163         },
7164
7165         /**
7166          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7167          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7168          * @param {Boolean} visible Whether the element is visible
7169          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7170          * @return {Roo.Element} this
7171          */
7172          setVisible : function(visible, animate){
7173             if(!animate || !A){
7174                 if(this.visibilityMode == El.DISPLAY){
7175                     this.setDisplayed(visible);
7176                 }else{
7177                     this.fixDisplay();
7178                     this.dom.style.visibility = visible ? "visible" : "hidden";
7179                 }
7180             }else{
7181                 // closure for composites
7182                 var dom = this.dom;
7183                 var visMode = this.visibilityMode;
7184                 if(visible){
7185                     this.setOpacity(.01);
7186                     this.setVisible(true);
7187                 }
7188                 this.anim({opacity: { to: (visible?1:0) }},
7189                       this.preanim(arguments, 1),
7190                       null, .35, 'easeIn', function(){
7191                          if(!visible){
7192                              if(visMode == El.DISPLAY){
7193                                  dom.style.display = "none";
7194                              }else{
7195                                  dom.style.visibility = "hidden";
7196                              }
7197                              Roo.get(dom).setOpacity(1);
7198                          }
7199                      });
7200             }
7201             return this;
7202         },
7203
7204         /**
7205          * Returns true if display is not "none"
7206          * @return {Boolean}
7207          */
7208         isDisplayed : function() {
7209             return this.getStyle("display") != "none";
7210         },
7211
7212         /**
7213          * Toggles the element's visibility or display, depending on visibility mode.
7214          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7215          * @return {Roo.Element} this
7216          */
7217         toggle : function(animate){
7218             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7219             return this;
7220         },
7221
7222         /**
7223          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7224          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7225          * @return {Roo.Element} this
7226          */
7227         setDisplayed : function(value) {
7228             if(typeof value == "boolean"){
7229                value = value ? this.originalDisplay : "none";
7230             }
7231             this.setStyle("display", value);
7232             return this;
7233         },
7234
7235         /**
7236          * Tries to focus the element. Any exceptions are caught and ignored.
7237          * @return {Roo.Element} this
7238          */
7239         focus : function() {
7240             try{
7241                 this.dom.focus();
7242             }catch(e){}
7243             return this;
7244         },
7245
7246         /**
7247          * Tries to blur the element. Any exceptions are caught and ignored.
7248          * @return {Roo.Element} this
7249          */
7250         blur : function() {
7251             try{
7252                 this.dom.blur();
7253             }catch(e){}
7254             return this;
7255         },
7256
7257         /**
7258          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7259          * @param {String/Array} className The CSS class to add, or an array of classes
7260          * @return {Roo.Element} this
7261          */
7262         addClass : function(className){
7263             if(className instanceof Array){
7264                 for(var i = 0, len = className.length; i < len; i++) {
7265                     this.addClass(className[i]);
7266                 }
7267             }else{
7268                 if(className && !this.hasClass(className)){
7269                     this.dom.className = this.dom.className + " " + className;
7270                 }
7271             }
7272             return this;
7273         },
7274
7275         /**
7276          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7277          * @param {String/Array} className The CSS class to add, or an array of classes
7278          * @return {Roo.Element} this
7279          */
7280         radioClass : function(className){
7281             var siblings = this.dom.parentNode.childNodes;
7282             for(var i = 0; i < siblings.length; i++) {
7283                 var s = siblings[i];
7284                 if(s.nodeType == 1){
7285                     Roo.get(s).removeClass(className);
7286                 }
7287             }
7288             this.addClass(className);
7289             return this;
7290         },
7291
7292         /**
7293          * Removes one or more CSS classes from the element.
7294          * @param {String/Array} className The CSS class to remove, or an array of classes
7295          * @return {Roo.Element} this
7296          */
7297         removeClass : function(className){
7298             if(!className || !this.dom.className){
7299                 return this;
7300             }
7301             if(className instanceof Array){
7302                 for(var i = 0, len = className.length; i < len; i++) {
7303                     this.removeClass(className[i]);
7304                 }
7305             }else{
7306                 if(this.hasClass(className)){
7307                     var re = this.classReCache[className];
7308                     if (!re) {
7309                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7310                        this.classReCache[className] = re;
7311                     }
7312                     this.dom.className =
7313                         this.dom.className.replace(re, " ");
7314                 }
7315             }
7316             return this;
7317         },
7318
7319         // private
7320         classReCache: {},
7321
7322         /**
7323          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7324          * @param {String} className The CSS class to toggle
7325          * @return {Roo.Element} this
7326          */
7327         toggleClass : function(className){
7328             if(this.hasClass(className)){
7329                 this.removeClass(className);
7330             }else{
7331                 this.addClass(className);
7332             }
7333             return this;
7334         },
7335
7336         /**
7337          * Checks if the specified CSS class exists on this element's DOM node.
7338          * @param {String} className The CSS class to check for
7339          * @return {Boolean} True if the class exists, else false
7340          */
7341         hasClass : function(className){
7342             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7343         },
7344
7345         /**
7346          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7347          * @param {String} oldClassName The CSS class to replace
7348          * @param {String} newClassName The replacement CSS class
7349          * @return {Roo.Element} this
7350          */
7351         replaceClass : function(oldClassName, newClassName){
7352             this.removeClass(oldClassName);
7353             this.addClass(newClassName);
7354             return this;
7355         },
7356
7357         /**
7358          * Returns an object with properties matching the styles requested.
7359          * For example, el.getStyles('color', 'font-size', 'width') might return
7360          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7361          * @param {String} style1 A style name
7362          * @param {String} style2 A style name
7363          * @param {String} etc.
7364          * @return {Object} The style object
7365          */
7366         getStyles : function(){
7367             var a = arguments, len = a.length, r = {};
7368             for(var i = 0; i < len; i++){
7369                 r[a[i]] = this.getStyle(a[i]);
7370             }
7371             return r;
7372         },
7373
7374         /**
7375          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7376          * @param {String} property The style property whose value is returned.
7377          * @return {String} The current value of the style property for this element.
7378          */
7379         getStyle : function(){
7380             return view && view.getComputedStyle ?
7381                 function(prop){
7382                     var el = this.dom, v, cs, camel;
7383                     if(prop == 'float'){
7384                         prop = "cssFloat";
7385                     }
7386                     if(el.style && (v = el.style[prop])){
7387                         return v;
7388                     }
7389                     if(cs = view.getComputedStyle(el, "")){
7390                         if(!(camel = propCache[prop])){
7391                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7392                         }
7393                         return cs[camel];
7394                     }
7395                     return null;
7396                 } :
7397                 function(prop){
7398                     var el = this.dom, v, cs, camel;
7399                     if(prop == 'opacity'){
7400                         if(typeof el.style.filter == 'string'){
7401                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7402                             if(m){
7403                                 var fv = parseFloat(m[1]);
7404                                 if(!isNaN(fv)){
7405                                     return fv ? fv / 100 : 0;
7406                                 }
7407                             }
7408                         }
7409                         return 1;
7410                     }else if(prop == 'float'){
7411                         prop = "styleFloat";
7412                     }
7413                     if(!(camel = propCache[prop])){
7414                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7415                     }
7416                     if(v = el.style[camel]){
7417                         return v;
7418                     }
7419                     if(cs = el.currentStyle){
7420                         return cs[camel];
7421                     }
7422                     return null;
7423                 };
7424         }(),
7425
7426         /**
7427          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7428          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7429          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7430          * @return {Roo.Element} this
7431          */
7432         setStyle : function(prop, value){
7433             if(typeof prop == "string"){
7434                 
7435                 if (prop == 'float') {
7436                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7437                     return this;
7438                 }
7439                 
7440                 var camel;
7441                 if(!(camel = propCache[prop])){
7442                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7443                 }
7444                 
7445                 if(camel == 'opacity') {
7446                     this.setOpacity(value);
7447                 }else{
7448                     this.dom.style[camel] = value;
7449                 }
7450             }else{
7451                 for(var style in prop){
7452                     if(typeof prop[style] != "function"){
7453                        this.setStyle(style, prop[style]);
7454                     }
7455                 }
7456             }
7457             return this;
7458         },
7459
7460         /**
7461          * More flexible version of {@link #setStyle} for setting style properties.
7462          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7463          * a function which returns such a specification.
7464          * @return {Roo.Element} this
7465          */
7466         applyStyles : function(style){
7467             Roo.DomHelper.applyStyles(this.dom, style);
7468             return this;
7469         },
7470
7471         /**
7472           * Gets the current X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7473           * @return {Number} The X position of the element
7474           */
7475         getX : function(){
7476             return D.getX(this.dom);
7477         },
7478
7479         /**
7480           * Gets the current Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7481           * @return {Number} The Y position of the element
7482           */
7483         getY : function(){
7484             return D.getY(this.dom);
7485         },
7486
7487         /**
7488           * Gets the current position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7489           * @return {Array} The XY position of the element
7490           */
7491         getXY : function(){
7492             return D.getXY(this.dom);
7493         },
7494
7495         /**
7496          * Sets the X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7497          * @param {Number} The X position of the element
7498          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7499          * @return {Roo.Element} this
7500          */
7501         setX : function(x, animate){
7502             if(!animate || !A){
7503                 D.setX(this.dom, x);
7504             }else{
7505                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7506             }
7507             return this;
7508         },
7509
7510         /**
7511          * Sets the Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7512          * @param {Number} The Y position of the element
7513          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7514          * @return {Roo.Element} this
7515          */
7516         setY : function(y, animate){
7517             if(!animate || !A){
7518                 D.setY(this.dom, y);
7519             }else{
7520                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7521             }
7522             return this;
7523         },
7524
7525         /**
7526          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7527          * @param {String} left The left CSS property value
7528          * @return {Roo.Element} this
7529          */
7530         setLeft : function(left){
7531             this.setStyle("left", this.addUnits(left));
7532             return this;
7533         },
7534
7535         /**
7536          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7537          * @param {String} top The top CSS property value
7538          * @return {Roo.Element} this
7539          */
7540         setTop : function(top){
7541             this.setStyle("top", this.addUnits(top));
7542             return this;
7543         },
7544
7545         /**
7546          * Sets the element's CSS right style.
7547          * @param {String} right The right CSS property value
7548          * @return {Roo.Element} this
7549          */
7550         setRight : function(right){
7551             this.setStyle("right", this.addUnits(right));
7552             return this;
7553         },
7554
7555         /**
7556          * Sets the element's CSS bottom style.
7557          * @param {String} bottom The bottom CSS property value
7558          * @return {Roo.Element} this
7559          */
7560         setBottom : function(bottom){
7561             this.setStyle("bottom", this.addUnits(bottom));
7562             return this;
7563         },
7564
7565         /**
7566          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7567          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7568          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7569          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7570          * @return {Roo.Element} this
7571          */
7572         setXY : function(pos, animate){
7573             if(!animate || !A){
7574                 D.setXY(this.dom, pos);
7575             }else{
7576                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7577             }
7578             return this;
7579         },
7580
7581         /**
7582          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7583          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7584          * @param {Number} x X value for new position (coordinates are page-based)
7585          * @param {Number} y Y value for new position (coordinates are page-based)
7586          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7587          * @return {Roo.Element} this
7588          */
7589         setLocation : function(x, y, animate){
7590             this.setXY([x, y], this.preanim(arguments, 2));
7591             return this;
7592         },
7593
7594         /**
7595          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7596          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7597          * @param {Number} x X value for new position (coordinates are page-based)
7598          * @param {Number} y Y value for new position (coordinates are page-based)
7599          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7600          * @return {Roo.Element} this
7601          */
7602         moveTo : function(x, y, animate){
7603             this.setXY([x, y], this.preanim(arguments, 2));
7604             return this;
7605         },
7606
7607         /**
7608          * Returns the region of the given element.
7609          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7610          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7611          */
7612         getRegion : function(){
7613             return D.getRegion(this.dom);
7614         },
7615
7616         /**
7617          * Returns the offset height of the element
7618          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7619          * @return {Number} The element's height
7620          */
7621         getHeight : function(contentHeight){
7622             var h = this.dom.offsetHeight || 0;
7623             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7624         },
7625
7626         /**
7627          * Returns the offset width of the element
7628          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7629          * @return {Number} The element's width
7630          */
7631         getWidth : function(contentWidth){
7632             var w = this.dom.offsetWidth || 0;
7633             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7634         },
7635
7636         /**
7637          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7638          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7639          * if a height has not been set using CSS.
7640          * @return {Number}
7641          */
7642         getComputedHeight : function(){
7643             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7644             if(!h){
7645                 h = parseInt(this.getStyle('height'), 10) || 0;
7646                 if(!this.isBorderBox()){
7647                     h += this.getFrameWidth('tb');
7648                 }
7649             }
7650             return h;
7651         },
7652
7653         /**
7654          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7655          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7656          * if a width has not been set using CSS.
7657          * @return {Number}
7658          */
7659         getComputedWidth : function(){
7660             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7661             if(!w){
7662                 w = parseInt(this.getStyle('width'), 10) || 0;
7663                 if(!this.isBorderBox()){
7664                     w += this.getFrameWidth('lr');
7665                 }
7666             }
7667             return w;
7668         },
7669
7670         /**
7671          * Returns the size of the element.
7672          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7673          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7674          */
7675         getSize : function(contentSize){
7676             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7677         },
7678
7679         /**
7680          * Returns the width and height of the viewport.
7681          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7682          */
7683         getViewSize : function(){
7684             var d = this.dom, doc = document, aw = 0, ah = 0;
7685             if(d == doc || d == doc.body){
7686                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7687             }else{
7688                 return {
7689                     width : d.clientWidth,
7690                     height: d.clientHeight
7691                 };
7692             }
7693         },
7694
7695         /**
7696          * Returns the value of the "value" attribute
7697          * @param {Boolean} asNumber true to parse the value as a number
7698          * @return {String/Number}
7699          */
7700         getValue : function(asNumber){
7701             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7702         },
7703
7704         // private
7705         adjustWidth : function(width){
7706             if(typeof width == "number"){
7707                 if(this.autoBoxAdjust && !this.isBorderBox()){
7708                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7709                 }
7710                 if(width < 0){
7711                     width = 0;
7712                 }
7713             }
7714             return width;
7715         },
7716
7717         // private
7718         adjustHeight : function(height){
7719             if(typeof height == "number"){
7720                if(this.autoBoxAdjust && !this.isBorderBox()){
7721                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7722                }
7723                if(height < 0){
7724                    height = 0;
7725                }
7726             }
7727             return height;
7728         },
7729
7730         /**
7731          * Set the width of the element
7732          * @param {Number} width The new width
7733          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7734          * @return {Roo.Element} this
7735          */
7736         setWidth : function(width, animate){
7737             width = this.adjustWidth(width);
7738             if(!animate || !A){
7739                 this.dom.style.width = this.addUnits(width);
7740             }else{
7741                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7742             }
7743             return this;
7744         },
7745
7746         /**
7747          * Set the height of the element
7748          * @param {Number} height The new height
7749          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7750          * @return {Roo.Element} this
7751          */
7752          setHeight : function(height, animate){
7753             height = this.adjustHeight(height);
7754             if(!animate || !A){
7755                 this.dom.style.height = this.addUnits(height);
7756             }else{
7757                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7758             }
7759             return this;
7760         },
7761
7762         /**
7763          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7764          * @param {Number} width The new width
7765          * @param {Number} height The new height
7766          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7767          * @return {Roo.Element} this
7768          */
7769          setSize : function(width, height, animate){
7770             if(typeof width == "object"){ // in case of object from getSize()
7771                 height = width.height; width = width.width;
7772             }
7773             width = this.adjustWidth(width); height = this.adjustHeight(height);
7774             if(!animate || !A){
7775                 this.dom.style.width = this.addUnits(width);
7776                 this.dom.style.height = this.addUnits(height);
7777             }else{
7778                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7779             }
7780             return this;
7781         },
7782
7783         /**
7784          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7785          * @param {Number} x X value for new position (coordinates are page-based)
7786          * @param {Number} y Y value for new position (coordinates are page-based)
7787          * @param {Number} width The new width
7788          * @param {Number} height The new height
7789          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7790          * @return {Roo.Element} this
7791          */
7792         setBounds : function(x, y, width, height, animate){
7793             if(!animate || !A){
7794                 this.setSize(width, height);
7795                 this.setLocation(x, y);
7796             }else{
7797                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7798                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7799                               this.preanim(arguments, 4), 'motion');
7800             }
7801             return this;
7802         },
7803
7804         /**
7805          * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7806          * @param {Roo.lib.Region} region The region to fill
7807          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7808          * @return {Roo.Element} this
7809          */
7810         setRegion : function(region, animate){
7811             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7812             return this;
7813         },
7814
7815         /**
7816          * Appends an event handler
7817          *
7818          * @param {String}   eventName     The type of event to append
7819          * @param {Function} fn        The method the event invokes
7820          * @param {Object} scope       (optional) The scope (this object) of the fn
7821          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7822          */
7823         addListener : function(eventName, fn, scope, options){
7824             if (this.dom) {
7825                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7826             }
7827         },
7828
7829         /**
7830          * Removes an event handler from this element
7831          * @param {String} eventName the type of event to remove
7832          * @param {Function} fn the method the event invokes
7833          * @return {Roo.Element} this
7834          */
7835         removeListener : function(eventName, fn){
7836             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7837             return this;
7838         },
7839
7840         /**
7841          * Removes all previous added listeners from this element
7842          * @return {Roo.Element} this
7843          */
7844         removeAllListeners : function(){
7845             E.purgeElement(this.dom);
7846             return this;
7847         },
7848
7849         relayEvent : function(eventName, observable){
7850             this.on(eventName, function(e){
7851                 observable.fireEvent(eventName, e);
7852             });
7853         },
7854
7855         /**
7856          * Set the opacity of the element
7857          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7858          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7859          * @return {Roo.Element} this
7860          */
7861          setOpacity : function(opacity, animate){
7862             if(!animate || !A){
7863                 var s = this.dom.style;
7864                 if(Roo.isIE){
7865                     s.zoom = 1;
7866                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7867                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7868                 }else{
7869                     s.opacity = opacity;
7870                 }
7871             }else{
7872                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7873             }
7874             return this;
7875         },
7876
7877         /**
7878          * Gets the left X coordinate
7879          * @param {Boolean} local True to get the local css position instead of page coordinate
7880          * @return {Number}
7881          */
7882         getLeft : function(local){
7883             if(!local){
7884                 return this.getX();
7885             }else{
7886                 return parseInt(this.getStyle("left"), 10) || 0;
7887             }
7888         },
7889
7890         /**
7891          * Gets the right X coordinate of the element (element X position + element width)
7892          * @param {Boolean} local True to get the local css position instead of page coordinate
7893          * @return {Number}
7894          */
7895         getRight : function(local){
7896             if(!local){
7897                 return this.getX() + this.getWidth();
7898             }else{
7899                 return (this.getLeft(true) + this.getWidth()) || 0;
7900             }
7901         },
7902
7903         /**
7904          * Gets the top Y coordinate
7905          * @param {Boolean} local True to get the local css position instead of page coordinate
7906          * @return {Number}
7907          */
7908         getTop : function(local) {
7909             if(!local){
7910                 return this.getY();
7911             }else{
7912                 return parseInt(this.getStyle("top"), 10) || 0;
7913             }
7914         },
7915
7916         /**
7917          * Gets the bottom Y coordinate of the element (element Y position + element height)
7918          * @param {Boolean} local True to get the local css position instead of page coordinate
7919          * @return {Number}
7920          */
7921         getBottom : function(local){
7922             if(!local){
7923                 return this.getY() + this.getHeight();
7924             }else{
7925                 return (this.getTop(true) + this.getHeight()) || 0;
7926             }
7927         },
7928
7929         /**
7930         * Initializes positioning on this element. If a desired position is not passed, it will make the
7931         * the element positioned relative IF it is not already positioned.
7932         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7933         * @param {Number} zIndex (optional) The zIndex to apply
7934         * @param {Number} x (optional) Set the page X position
7935         * @param {Number} y (optional) Set the page Y position
7936         */
7937         position : function(pos, zIndex, x, y){
7938             if(!pos){
7939                if(this.getStyle('position') == 'static'){
7940                    this.setStyle('position', 'relative');
7941                }
7942             }else{
7943                 this.setStyle("position", pos);
7944             }
7945             if(zIndex){
7946                 this.setStyle("z-index", zIndex);
7947             }
7948             if(x !== undefined && y !== undefined){
7949                 this.setXY([x, y]);
7950             }else if(x !== undefined){
7951                 this.setX(x);
7952             }else if(y !== undefined){
7953                 this.setY(y);
7954             }
7955         },
7956
7957         /**
7958         * Clear positioning back to the default when the document was loaded
7959         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7960         * @return {Roo.Element} this
7961          */
7962         clearPositioning : function(value){
7963             value = value ||'';
7964             this.setStyle({
7965                 "left": value,
7966                 "right": value,
7967                 "top": value,
7968                 "bottom": value,
7969                 "z-index": "",
7970                 "position" : "static"
7971             });
7972             return this;
7973         },
7974
7975         /**
7976         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7977         * snapshot before performing an update and then restoring the element.
7978         * @return {Object}
7979         */
7980         getPositioning : function(){
7981             var l = this.getStyle("left");
7982             var t = this.getStyle("top");
7983             return {
7984                 "position" : this.getStyle("position"),
7985                 "left" : l,
7986                 "right" : l ? "" : this.getStyle("right"),
7987                 "top" : t,
7988                 "bottom" : t ? "" : this.getStyle("bottom"),
7989                 "z-index" : this.getStyle("z-index")
7990             };
7991         },
7992
7993         /**
7994          * Gets the width of the border(s) for the specified side(s)
7995          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7996          * passing lr would get the border (l)eft width + the border (r)ight width.
7997          * @return {Number} The width of the sides passed added together
7998          */
7999         getBorderWidth : function(side){
8000             return this.addStyles(side, El.borders);
8001         },
8002
8003         /**
8004          * Gets the width of the padding(s) for the specified side(s)
8005          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8006          * passing lr would get the padding (l)eft + the padding (r)ight.
8007          * @return {Number} The padding of the sides passed added together
8008          */
8009         getPadding : function(side){
8010             return this.addStyles(side, El.paddings);
8011         },
8012
8013         /**
8014         * Set positioning with an object returned by getPositioning().
8015         * @param {Object} posCfg
8016         * @return {Roo.Element} this
8017          */
8018         setPositioning : function(pc){
8019             this.applyStyles(pc);
8020             if(pc.right == "auto"){
8021                 this.dom.style.right = "";
8022             }
8023             if(pc.bottom == "auto"){
8024                 this.dom.style.bottom = "";
8025             }
8026             return this;
8027         },
8028
8029         // private
8030         fixDisplay : function(){
8031             if(this.getStyle("display") == "none"){
8032                 this.setStyle("visibility", "hidden");
8033                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8034                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8035                     this.setStyle("display", "block");
8036                 }
8037             }
8038         },
8039
8040         /**
8041          * Quick set left and top adding default units
8042          * @param {String} left The left CSS property value
8043          * @param {String} top The top CSS property value
8044          * @return {Roo.Element} this
8045          */
8046          setLeftTop : function(left, top){
8047             this.dom.style.left = this.addUnits(left);
8048             this.dom.style.top = this.addUnits(top);
8049             return this;
8050         },
8051
8052         /**
8053          * Move this element relative to its current position.
8054          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8055          * @param {Number} distance How far to move the element in pixels
8056          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8057          * @return {Roo.Element} this
8058          */
8059          move : function(direction, distance, animate){
8060             var xy = this.getXY();
8061             direction = direction.toLowerCase();
8062             switch(direction){
8063                 case "l":
8064                 case "left":
8065                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8066                     break;
8067                case "r":
8068                case "right":
8069                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8070                     break;
8071                case "t":
8072                case "top":
8073                case "up":
8074                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8075                     break;
8076                case "b":
8077                case "bottom":
8078                case "down":
8079                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8080                     break;
8081             }
8082             return this;
8083         },
8084
8085         /**
8086          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8087          * @return {Roo.Element} this
8088          */
8089         clip : function(){
8090             if(!this.isClipped){
8091                this.isClipped = true;
8092                this.originalClip = {
8093                    "o": this.getStyle("overflow"),
8094                    "x": this.getStyle("overflow-x"),
8095                    "y": this.getStyle("overflow-y")
8096                };
8097                this.setStyle("overflow", "hidden");
8098                this.setStyle("overflow-x", "hidden");
8099                this.setStyle("overflow-y", "hidden");
8100             }
8101             return this;
8102         },
8103
8104         /**
8105          *  Return clipping (overflow) to original clipping before clip() was called
8106          * @return {Roo.Element} this
8107          */
8108         unclip : function(){
8109             if(this.isClipped){
8110                 this.isClipped = false;
8111                 var o = this.originalClip;
8112                 if(o.o){this.setStyle("overflow", o.o);}
8113                 if(o.x){this.setStyle("overflow-x", o.x);}
8114                 if(o.y){this.setStyle("overflow-y", o.y);}
8115             }
8116             return this;
8117         },
8118
8119
8120         /**
8121          * Gets the x,y coordinates specified by the anchor position on the element.
8122          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8123          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8124          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8125          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8126          * @return {Array} [x, y] An array containing the element's x and y coordinates
8127          */
8128         getAnchorXY : function(anchor, local, s){
8129             //Passing a different size is useful for pre-calculating anchors,
8130             //especially for anchored animations that change the el size.
8131
8132             var w, h, vp = false;
8133             if(!s){
8134                 var d = this.dom;
8135                 if(d == document.body || d == document){
8136                     vp = true;
8137                     w = D.getViewWidth(); h = D.getViewHeight();
8138                 }else{
8139                     w = this.getWidth(); h = this.getHeight();
8140                 }
8141             }else{
8142                 w = s.width;  h = s.height;
8143             }
8144             var x = 0, y = 0, r = Math.round;
8145             switch((anchor || "tl").toLowerCase()){
8146                 case "c":
8147                     x = r(w*.5);
8148                     y = r(h*.5);
8149                 break;
8150                 case "t":
8151                     x = r(w*.5);
8152                     y = 0;
8153                 break;
8154                 case "l":
8155                     x = 0;
8156                     y = r(h*.5);
8157                 break;
8158                 case "r":
8159                     x = w;
8160                     y = r(h*.5);
8161                 break;
8162                 case "b":
8163                     x = r(w*.5);
8164                     y = h;
8165                 break;
8166                 case "tl":
8167                     x = 0;
8168                     y = 0;
8169                 break;
8170                 case "bl":
8171                     x = 0;
8172                     y = h;
8173                 break;
8174                 case "br":
8175                     x = w;
8176                     y = h;
8177                 break;
8178                 case "tr":
8179                     x = w;
8180                     y = 0;
8181                 break;
8182             }
8183             if(local === true){
8184                 return [x, y];
8185             }
8186             if(vp){
8187                 var sc = this.getScroll();
8188                 return [x + sc.left, y + sc.top];
8189             }
8190             //Add the element's offset xy
8191             var o = this.getXY();
8192             return [x+o[0], y+o[1]];
8193         },
8194
8195         /**
8196          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8197          * supported position values.
8198          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8199          * @param {String} position The position to align to.
8200          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8201          * @return {Array} [x, y]
8202          */
8203         getAlignToXY : function(el, p, o){
8204             el = Roo.get(el);
8205             var d = this.dom;
8206             if(!el.dom){
8207                 throw "Element.alignTo with an element that doesn't exist";
8208             }
8209             var c = false; //constrain to viewport
8210             var p1 = "", p2 = "";
8211             o = o || [0,0];
8212
8213             if(!p){
8214                 p = "tl-bl";
8215             }else if(p == "?"){
8216                 p = "tl-bl?";
8217             }else if(p.indexOf("-") == -1){
8218                 p = "tl-" + p;
8219             }
8220             p = p.toLowerCase();
8221             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8222             if(!m){
8223                throw "Element.alignTo with an invalid alignment " + p;
8224             }
8225             p1 = m[1]; p2 = m[2]; c = !!m[3];
8226
8227             //Subtract the aligned el's internal xy from the target's offset xy
8228             //plus custom offset to get the aligned el's new offset xy
8229             var a1 = this.getAnchorXY(p1, true);
8230             var a2 = el.getAnchorXY(p2, false);
8231             var x = a2[0] - a1[0] + o[0];
8232             var y = a2[1] - a1[1] + o[1];
8233             if(c){
8234                 //constrain the aligned el to viewport if necessary
8235                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8236                 // 5px of margin for ie
8237                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8238
8239                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8240                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8241                 //otherwise swap the aligned el to the opposite border of the target.
8242                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8243                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8244                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8245                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8246
8247                var doc = document;
8248                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8249                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8250
8251                if((x+w) > dw + scrollX){
8252                     x = swapX ? r.left-w : dw+scrollX-w;
8253                 }
8254                if(x < scrollX){
8255                    x = swapX ? r.right : scrollX;
8256                }
8257                if((y+h) > dh + scrollY){
8258                     y = swapY ? r.top-h : dh+scrollY-h;
8259                 }
8260                if (y < scrollY){
8261                    y = swapY ? r.bottom : scrollY;
8262                }
8263             }
8264             return [x,y];
8265         },
8266
8267         // private
8268         getConstrainToXY : function(){
8269             var os = {top:0, left:0, bottom:0, right: 0};
8270
8271             return function(el, local, offsets, proposedXY){
8272                 el = Roo.get(el);
8273                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8274
8275                 var vw, vh, vx = 0, vy = 0;
8276                 if(el.dom == document.body || el.dom == document){
8277                     vw = Roo.lib.Dom.getViewWidth();
8278                     vh = Roo.lib.Dom.getViewHeight();
8279                 }else{
8280                     vw = el.dom.clientWidth;
8281                     vh = el.dom.clientHeight;
8282                     if(!local){
8283                         var vxy = el.getXY();
8284                         vx = vxy[0];
8285                         vy = vxy[1];
8286                     }
8287                 }
8288
8289                 var s = el.getScroll();
8290
8291                 vx += offsets.left + s.left;
8292                 vy += offsets.top + s.top;
8293
8294                 vw -= offsets.right;
8295                 vh -= offsets.bottom;
8296
8297                 var vr = vx+vw;
8298                 var vb = vy+vh;
8299
8300                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8301                 var x = xy[0], y = xy[1];
8302                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8303
8304                 // only move it if it needs it
8305                 var moved = false;
8306
8307                 // first validate right/bottom
8308                 if((x + w) > vr){
8309                     x = vr - w;
8310                     moved = true;
8311                 }
8312                 if((y + h) > vb){
8313                     y = vb - h;
8314                     moved = true;
8315                 }
8316                 // then make sure top/left isn't negative
8317                 if(x < vx){
8318                     x = vx;
8319                     moved = true;
8320                 }
8321                 if(y < vy){
8322                     y = vy;
8323                     moved = true;
8324                 }
8325                 return moved ? [x, y] : false;
8326             };
8327         }(),
8328
8329         // private
8330         adjustForConstraints : function(xy, parent, offsets){
8331             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8332         },
8333
8334         /**
8335          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8336          * document it aligns it to the viewport.
8337          * The position parameter is optional, and can be specified in any one of the following formats:
8338          * <ul>
8339          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8340          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8341          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8342          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8343          *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8344          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8345          * </ul>
8346          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8347          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8348          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8349          * that specified in order to enforce the viewport constraints.
8350          * Following are all of the supported anchor positions:
8351     <pre>
8352     Value  Description
8353     -----  -----------------------------
8354     tl     The top left corner (default)
8355     t      The center of the top edge
8356     tr     The top right corner
8357     l      The center of the left edge
8358     c      In the center of the element
8359     r      The center of the right edge
8360     bl     The bottom left corner
8361     b      The center of the bottom edge
8362     br     The bottom right corner
8363     </pre>
8364     Example Usage:
8365     <pre><code>
8366     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8367     el.alignTo("other-el");
8368
8369     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8370     el.alignTo("other-el", "tr?");
8371
8372     // align the bottom right corner of el with the center left edge of other-el
8373     el.alignTo("other-el", "br-l?");
8374
8375     // align the center of el with the bottom left corner of other-el and
8376     // adjust the x position by -6 pixels (and the y position by 0)
8377     el.alignTo("other-el", "c-bl", [-6, 0]);
8378     </code></pre>
8379          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8380          * @param {String} position The position to align to.
8381          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8382          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8383          * @return {Roo.Element} this
8384          */
8385         alignTo : function(element, position, offsets, animate){
8386             var xy = this.getAlignToXY(element, position, offsets);
8387             this.setXY(xy, this.preanim(arguments, 3));
8388             return this;
8389         },
8390
8391         /**
8392          * Anchors an element to another element and realigns it when the window is resized.
8393          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8394          * @param {String} position The position to align to.
8395          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8396          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8397          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8398          * is a number, it is used as the buffer delay (defaults to 50ms).
8399          * @param {Function} callback The function to call after the animation finishes
8400          * @return {Roo.Element} this
8401          */
8402         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8403             var action = function(){
8404                 this.alignTo(el, alignment, offsets, animate);
8405                 Roo.callback(callback, this);
8406             };
8407             Roo.EventManager.onWindowResize(action, this);
8408             var tm = typeof monitorScroll;
8409             if(tm != 'undefined'){
8410                 Roo.EventManager.on(window, 'scroll', action, this,
8411                     {buffer: tm == 'number' ? monitorScroll : 50});
8412             }
8413             action.call(this); // align immediately
8414             return this;
8415         },
8416         /**
8417          * Clears any opacity settings from this element. Required in some cases for IE.
8418          * @return {Roo.Element} this
8419          */
8420         clearOpacity : function(){
8421             if (window.ActiveXObject) {
8422                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8423                     this.dom.style.filter = "";
8424                 }
8425             } else {
8426                 this.dom.style.opacity = "";
8427                 this.dom.style["-moz-opacity"] = "";
8428                 this.dom.style["-khtml-opacity"] = "";
8429             }
8430             return this;
8431         },
8432
8433         /**
8434          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8435          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8436          * @return {Roo.Element} this
8437          */
8438         hide : function(animate){
8439             this.setVisible(false, this.preanim(arguments, 0));
8440             return this;
8441         },
8442
8443         /**
8444         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8445         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8446          * @return {Roo.Element} this
8447          */
8448         show : function(animate){
8449             this.setVisible(true, this.preanim(arguments, 0));
8450             return this;
8451         },
8452
8453         /**
8454          * @private Test if size has a unit, otherwise appends the default
8455          */
8456         addUnits : function(size){
8457             return Roo.Element.addUnits(size, this.defaultUnit);
8458         },
8459
8460         /**
8461          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8462          * @return {Roo.Element} this
8463          */
8464         beginMeasure : function(){
8465             var el = this.dom;
8466             if(el.offsetWidth || el.offsetHeight){
8467                 return this; // offsets work already
8468             }
8469             var changed = [];
8470             var p = this.dom, b = document.body; // start with this element
8471             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8472                 var pe = Roo.get(p);
8473                 if(pe.getStyle('display') == 'none'){
8474                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8475                     p.style.visibility = "hidden";
8476                     p.style.display = "block";
8477                 }
8478                 p = p.parentNode;
8479             }
8480             this._measureChanged = changed;
8481             return this;
8482
8483         },
8484
8485         /**
8486          * Restores displays to before beginMeasure was called
8487          * @return {Roo.Element} this
8488          */
8489         endMeasure : function(){
8490             var changed = this._measureChanged;
8491             if(changed){
8492                 for(var i = 0, len = changed.length; i < len; i++) {
8493                     var r = changed[i];
8494                     r.el.style.visibility = r.visibility;
8495                     r.el.style.display = "none";
8496                 }
8497                 this._measureChanged = null;
8498             }
8499             return this;
8500         },
8501
8502         /**
8503         * Update the innerHTML of this element, optionally searching for and processing scripts
8504         * @param {String} html The new HTML
8505         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8506         * @param {Function} callback For async script loading you can be noticed when the update completes
8507         * @return {Roo.Element} this
8508          */
8509         update : function(html, loadScripts, callback){
8510             if(typeof html == "undefined"){
8511                 html = "";
8512             }
8513             if(loadScripts !== true){
8514                 this.dom.innerHTML = html;
8515                 if(typeof callback == "function"){
8516                     callback();
8517                 }
8518                 return this;
8519             }
8520             var id = Roo.id();
8521             var dom = this.dom;
8522
8523             html += '<span id="' + id + '"></span>';
8524
8525             E.onAvailable(id, function(){
8526                 var hd = document.getElementsByTagName("head")[0];
8527                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8528                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8529                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8530
8531                 var match;
8532                 while(match = re.exec(html)){
8533                     var attrs = match[1];
8534                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8535                     if(srcMatch && srcMatch[2]){
8536                        var s = document.createElement("script");
8537                        s.src = srcMatch[2];
8538                        var typeMatch = attrs.match(typeRe);
8539                        if(typeMatch && typeMatch[2]){
8540                            s.type = typeMatch[2];
8541                        }
8542                        hd.appendChild(s);
8543                     }else if(match[2] && match[2].length > 0){
8544                         if(window.execScript) {
8545                            window.execScript(match[2]);
8546                         } else {
8547                             /**
8548                              * eval:var:id
8549                              * eval:var:dom
8550                              * eval:var:html
8551                              * 
8552                              */
8553                            window.eval(match[2]);
8554                         }
8555                     }
8556                 }
8557                 var el = document.getElementById(id);
8558                 if(el){el.parentNode.removeChild(el);}
8559                 if(typeof callback == "function"){
8560                     callback();
8561                 }
8562             });
8563             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8564             return this;
8565         },
8566
8567         /**
8568          * Direct access to the UpdateManager update() method (takes the same parameters).
8569          * @param {String/Function} url The url for this request or a function to call to get the url
8570          * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
8571          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8572          * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8573          * @return {Roo.Element} this
8574          */
8575         load : function(){
8576             var um = this.getUpdateManager();
8577             um.update.apply(um, arguments);
8578             return this;
8579         },
8580
8581         /**
8582         * Gets this element's UpdateManager
8583         * @return {Roo.UpdateManager} The UpdateManager
8584         */
8585         getUpdateManager : function(){
8586             if(!this.updateManager){
8587                 this.updateManager = new Roo.UpdateManager(this);
8588             }
8589             return this.updateManager;
8590         },
8591
8592         /**
8593          * Disables text selection for this element (normalized across browsers)
8594          * @return {Roo.Element} this
8595          */
8596         unselectable : function(){
8597             this.dom.unselectable = "on";
8598             this.swallowEvent("selectstart", true);
8599             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8600             this.addClass("x-unselectable");
8601             return this;
8602         },
8603
8604         /**
8605         * Calculates the x, y to center this element on the screen
8606         * @return {Array} The x, y values [x, y]
8607         */
8608         getCenterXY : function(){
8609             return this.getAlignToXY(document, 'c-c');
8610         },
8611
8612         /**
8613         * Centers the Element in either the viewport, or another Element.
8614         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8615         */
8616         center : function(centerIn){
8617             this.alignTo(centerIn || document, 'c-c');
8618             return this;
8619         },
8620
8621         /**
8622          * Tests various css rules/browsers to determine if this element uses a border box
8623          * @return {Boolean}
8624          */
8625         isBorderBox : function(){
8626             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8627         },
8628
8629         /**
8630          * Return a box {x, y, width, height} that can be used to set another elements
8631          * size/location to match this element.
8632          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8633          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8634          * @return {Object} box An object in the format {x, y, width, height}
8635          */
8636         getBox : function(contentBox, local){
8637             var xy;
8638             if(!local){
8639                 xy = this.getXY();
8640             }else{
8641                 var left = parseInt(this.getStyle("left"), 10) || 0;
8642                 var top = parseInt(this.getStyle("top"), 10) || 0;
8643                 xy = [left, top];
8644             }
8645             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8646             if(!contentBox){
8647                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8648             }else{
8649                 var l = this.getBorderWidth("l")+this.getPadding("l");
8650                 var r = this.getBorderWidth("r")+this.getPadding("r");
8651                 var t = this.getBorderWidth("t")+this.getPadding("t");
8652                 var b = this.getBorderWidth("b")+this.getPadding("b");
8653                 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8654             }
8655             bx.right = bx.x + bx.width;
8656             bx.bottom = bx.y + bx.height;
8657             return bx;
8658         },
8659
8660         /**
8661          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8662          for more information about the sides.
8663          * @param {String} sides
8664          * @return {Number}
8665          */
8666         getFrameWidth : function(sides, onlyContentBox){
8667             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8668         },
8669
8670         /**
8671          * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8672          * @param {Object} box The box to fill {x, y, width, height}
8673          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8674          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8675          * @return {Roo.Element} this
8676          */
8677         setBox : function(box, adjust, animate){
8678             var w = box.width, h = box.height;
8679             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8680                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8681                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8682             }
8683             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8684             return this;
8685         },
8686
8687         /**
8688          * Forces the browser to repaint this element
8689          * @return {Roo.Element} this
8690          */
8691          repaint : function(){
8692             var dom = this.dom;
8693             this.addClass("x-repaint");
8694             setTimeout(function(){
8695                 Roo.get(dom).removeClass("x-repaint");
8696             }, 1);
8697             return this;
8698         },
8699
8700         /**
8701          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8702          * then it returns the calculated width of the sides (see getPadding)
8703          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8704          * @return {Object/Number}
8705          */
8706         getMargins : function(side){
8707             if(!side){
8708                 return {
8709                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8710                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8711                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8712                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8713                 };
8714             }else{
8715                 return this.addStyles(side, El.margins);
8716              }
8717         },
8718
8719         // private
8720         addStyles : function(sides, styles){
8721             var val = 0, v, w;
8722             for(var i = 0, len = sides.length; i < len; i++){
8723                 v = this.getStyle(styles[sides.charAt(i)]);
8724                 if(v){
8725                      w = parseInt(v, 10);
8726                      if(w){ val += w; }
8727                 }
8728             }
8729             return val;
8730         },
8731
8732         /**
8733          * Creates a proxy element of this element
8734          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8735          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8736          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8737          * @return {Roo.Element} The new proxy element
8738          */
8739         createProxy : function(config, renderTo, matchBox){
8740             if(renderTo){
8741                 renderTo = Roo.getDom(renderTo);
8742             }else{
8743                 renderTo = document.body;
8744             }
8745             config = typeof config == "object" ?
8746                 config : {tag : "div", cls: config};
8747             var proxy = Roo.DomHelper.append(renderTo, config, true);
8748             if(matchBox){
8749                proxy.setBox(this.getBox());
8750             }
8751             return proxy;
8752         },
8753
8754         /**
8755          * Puts a mask over this element to disable user interaction. Requires core.css.
8756          * This method can only be applied to elements which accept child nodes.
8757          * @param {String} msg (optional) A message to display in the mask
8758          * @param {String} msgCls (optional) A css class to apply to the msg element
8759          * @return {Element} The mask  element
8760          */
8761         mask : function(msg, msgCls){
8762             if(this.getStyle("position") == "static"){
8763                 this.setStyle("position", "relative");
8764             }
8765             if(!this._mask){
8766                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8767             }
8768             this.addClass("x-masked");
8769             this._mask.setDisplayed(true);
8770             if(typeof msg == 'string'){
8771                 if(!this._maskMsg){
8772                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8773                 }
8774                 var mm = this._maskMsg;
8775                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8776                 mm.dom.firstChild.innerHTML = msg;
8777                 mm.setDisplayed(true);
8778                 mm.center(this);
8779             }
8780             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8781                 this._mask.setHeight(this.getHeight());
8782             }
8783             return this._mask;
8784         },
8785
8786         /**
8787          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8788          * it is cached for reuse.
8789          */
8790         unmask : function(removeEl){
8791             if(this._mask){
8792                 if(removeEl === true){
8793                     this._mask.remove();
8794                     delete this._mask;
8795                     if(this._maskMsg){
8796                         this._maskMsg.remove();
8797                         delete this._maskMsg;
8798                     }
8799                 }else{
8800                     this._mask.setDisplayed(false);
8801                     if(this._maskMsg){
8802                         this._maskMsg.setDisplayed(false);
8803                     }
8804                 }
8805             }
8806             this.removeClass("x-masked");
8807         },
8808
8809         /**
8810          * Returns true if this element is masked
8811          * @return {Boolean}
8812          */
8813         isMasked : function(){
8814             return this._mask && this._mask.isVisible();
8815         },
8816
8817         /**
8818          * Creates an iframe shim for this element to keep selects and other windowed objects from
8819          * showing through.
8820          * @return {Roo.Element} The new shim element
8821          */
8822         createShim : function(){
8823             var el = document.createElement('iframe');
8824             el.frameBorder = 'no';
8825             el.className = 'roo-shim';
8826             if(Roo.isIE && Roo.isSecure){
8827                 el.src = Roo.SSL_SECURE_URL;
8828             }
8829             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8830             shim.autoBoxAdjust = false;
8831             return shim;
8832         },
8833
8834         /**
8835          * Removes this element from the DOM and deletes it from the cache
8836          */
8837         remove : function(){
8838             if(this.dom.parentNode){
8839                 this.dom.parentNode.removeChild(this.dom);
8840             }
8841             delete El.cache[this.dom.id];
8842         },
8843
8844         /**
8845          * Sets up event handlers to add and remove a css class when the mouse is over this element
8846          * @param {String} className
8847          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8848          * mouseout events for children elements
8849          * @return {Roo.Element} this
8850          */
8851         addClassOnOver : function(className, preventFlicker){
8852             this.on("mouseover", function(){
8853                 Roo.fly(this, '_internal').addClass(className);
8854             }, this.dom);
8855             var removeFn = function(e){
8856                 if(preventFlicker !== true || !e.within(this, true)){
8857                     Roo.fly(this, '_internal').removeClass(className);
8858                 }
8859             };
8860             this.on("mouseout", removeFn, this.dom);
8861             return this;
8862         },
8863
8864         /**
8865          * Sets up event handlers to add and remove a css class when this element has the focus
8866          * @param {String} className
8867          * @return {Roo.Element} this
8868          */
8869         addClassOnFocus : function(className){
8870             this.on("focus", function(){
8871                 Roo.fly(this, '_internal').addClass(className);
8872             }, this.dom);
8873             this.on("blur", function(){
8874                 Roo.fly(this, '_internal').removeClass(className);
8875             }, this.dom);
8876             return this;
8877         },
8878         /**
8879          * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
8880          * @param {String} className
8881          * @return {Roo.Element} this
8882          */
8883         addClassOnClick : function(className){
8884             var dom = this.dom;
8885             this.on("mousedown", function(){
8886                 Roo.fly(dom, '_internal').addClass(className);
8887                 var d = Roo.get(document);
8888                 var fn = function(){
8889                     Roo.fly(dom, '_internal').removeClass(className);
8890                     d.removeListener("mouseup", fn);
8891                 };
8892                 d.on("mouseup", fn);
8893             });
8894             return this;
8895         },
8896
8897         /**
8898          * Stops the specified event from bubbling and optionally prevents the default action
8899          * @param {String} eventName
8900          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8901          * @return {Roo.Element} this
8902          */
8903         swallowEvent : function(eventName, preventDefault){
8904             var fn = function(e){
8905                 e.stopPropagation();
8906                 if(preventDefault){
8907                     e.preventDefault();
8908                 }
8909             };
8910             if(eventName instanceof Array){
8911                 for(var i = 0, len = eventName.length; i < len; i++){
8912                      this.on(eventName[i], fn);
8913                 }
8914                 return this;
8915             }
8916             this.on(eventName, fn);
8917             return this;
8918         },
8919
8920         /**
8921          * @private
8922          */
8923       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8924
8925         /**
8926          * Sizes this element to its parent element's dimensions performing
8927          * neccessary box adjustments.
8928          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8929          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8930          * @return {Roo.Element} this
8931          */
8932         fitToParent : function(monitorResize, targetParent) {
8933           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8934           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8935           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8936             return;
8937           }
8938           var p = Roo.get(targetParent || this.dom.parentNode);
8939           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8940           if (monitorResize === true) {
8941             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8942             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8943           }
8944           return this;
8945         },
8946
8947         /**
8948          * Gets the next sibling, skipping text nodes
8949          * @return {HTMLElement} The next sibling or null
8950          */
8951         getNextSibling : function(){
8952             var n = this.dom.nextSibling;
8953             while(n && n.nodeType != 1){
8954                 n = n.nextSibling;
8955             }
8956             return n;
8957         },
8958
8959         /**
8960          * Gets the previous sibling, skipping text nodes
8961          * @return {HTMLElement} The previous sibling or null
8962          */
8963         getPrevSibling : function(){
8964             var n = this.dom.previousSibling;
8965             while(n && n.nodeType != 1){
8966                 n = n.previousSibling;
8967             }
8968             return n;
8969         },
8970
8971
8972         /**
8973          * Appends the passed element(s) to this element
8974          * @param {String/HTMLElement/Array/Element/CompositeElement} el
8975          * @return {Roo.Element} this
8976          */
8977         appendChild: function(el){
8978             el = Roo.get(el);
8979             el.appendTo(this);
8980             return this;
8981         },
8982
8983         /**
8984          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8985          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
8986          * automatically generated with the specified attributes.
8987          * @param {HTMLElement} insertBefore (optional) a child element of this element
8988          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8989          * @return {Roo.Element} The new child element
8990          */
8991         createChild: function(config, insertBefore, returnDom){
8992             config = config || {tag:'div'};
8993             if(insertBefore){
8994                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8995             }
8996             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
8997         },
8998
8999         /**
9000          * Appends this element to the passed element
9001          * @param {String/HTMLElement/Element} el The new parent element
9002          * @return {Roo.Element} this
9003          */
9004         appendTo: function(el){
9005             el = Roo.getDom(el);
9006             el.appendChild(this.dom);
9007             return this;
9008         },
9009
9010         /**
9011          * Inserts this element before the passed element in the DOM
9012          * @param {String/HTMLElement/Element} el The element to insert before
9013          * @return {Roo.Element} this
9014          */
9015         insertBefore: function(el){
9016             el = Roo.getDom(el);
9017             el.parentNode.insertBefore(this.dom, el);
9018             return this;
9019         },
9020
9021         /**
9022          * Inserts this element after the passed element in the DOM
9023          * @param {String/HTMLElement/Element} el The element to insert after
9024          * @return {Roo.Element} this
9025          */
9026         insertAfter: function(el){
9027             el = Roo.getDom(el);
9028             el.parentNode.insertBefore(this.dom, el.nextSibling);
9029             return this;
9030         },
9031
9032         /**
9033          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9034          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9035          * @return {Roo.Element} The new child
9036          */
9037         insertFirst: function(el, returnDom){
9038             el = el || {};
9039             if(typeof el == 'object' && !el.nodeType){ // dh config
9040                 return this.createChild(el, this.dom.firstChild, returnDom);
9041             }else{
9042                 el = Roo.getDom(el);
9043                 this.dom.insertBefore(el, this.dom.firstChild);
9044                 return !returnDom ? Roo.get(el) : el;
9045             }
9046         },
9047
9048         /**
9049          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9050          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9051          * @param {String} where (optional) 'before' or 'after' defaults to before
9052          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9053          * @return {Roo.Element} the inserted Element
9054          */
9055         insertSibling: function(el, where, returnDom){
9056             where = where ? where.toLowerCase() : 'before';
9057             el = el || {};
9058             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9059
9060             if(typeof el == 'object' && !el.nodeType){ // dh config
9061                 if(where == 'after' && !this.dom.nextSibling){
9062                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9063                 }else{
9064                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9065                 }
9066
9067             }else{
9068                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9069                             where == 'before' ? this.dom : this.dom.nextSibling);
9070                 if(!returnDom){
9071                     rt = Roo.get(rt);
9072                 }
9073             }
9074             return rt;
9075         },
9076
9077         /**
9078          * Creates and wraps this element with another element
9079          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9080          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9081          * @return {HTMLElement/Element} The newly created wrapper element
9082          */
9083         wrap: function(config, returnDom){
9084             if(!config){
9085                 config = {tag: "div"};
9086             }
9087             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9088             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9089             return newEl;
9090         },
9091
9092         /**
9093          * Replaces the passed element with this element
9094          * @param {String/HTMLElement/Element} el The element to replace
9095          * @return {Roo.Element} this
9096          */
9097         replace: function(el){
9098             el = Roo.get(el);
9099             this.insertBefore(el);
9100             el.remove();
9101             return this;
9102         },
9103
9104         /**
9105          * Inserts an html fragment into this element
9106          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9107          * @param {String} html The HTML fragment
9108          * @param {Boolean} returnEl True to return an Roo.Element
9109          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9110          */
9111         insertHtml : function(where, html, returnEl){
9112             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9113             return returnEl ? Roo.get(el) : el;
9114         },
9115
9116         /**
9117          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9118          * @param {Object} o The object with the attributes
9119          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9120          * @return {Roo.Element} this
9121          */
9122         set : function(o, useSet){
9123             var el = this.dom;
9124             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9125             for(var attr in o){
9126                 if(attr == "style" || typeof o[attr] == "function") continue;
9127                 if(attr=="cls"){
9128                     el.className = o["cls"];
9129                 }else{
9130                     if(useSet) el.setAttribute(attr, o[attr]);
9131                     else el[attr] = o[attr];
9132                 }
9133             }
9134             if(o.style){
9135                 Roo.DomHelper.applyStyles(el, o.style);
9136             }
9137             return this;
9138         },
9139
9140         /**
9141          * Convenience method for constructing a KeyMap
9142          * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9143          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9144          * @param {Function} fn The function to call
9145          * @param {Object} scope (optional) The scope of the function
9146          * @return {Roo.KeyMap} The KeyMap created
9147          */
9148         addKeyListener : function(key, fn, scope){
9149             var config;
9150             if(typeof key != "object" || key instanceof Array){
9151                 config = {
9152                     key: key,
9153                     fn: fn,
9154                     scope: scope
9155                 };
9156             }else{
9157                 config = {
9158                     key : key.key,
9159                     shift : key.shift,
9160                     ctrl : key.ctrl,
9161                     alt : key.alt,
9162                     fn: fn,
9163                     scope: scope
9164                 };
9165             }
9166             return new Roo.KeyMap(this, config);
9167         },
9168
9169         /**
9170          * Creates a KeyMap for this element
9171          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9172          * @return {Roo.KeyMap} The KeyMap created
9173          */
9174         addKeyMap : function(config){
9175             return new Roo.KeyMap(this, config);
9176         },
9177
9178         /**
9179          * Returns true if this element is scrollable.
9180          * @return {Boolean}
9181          */
9182          isScrollable : function(){
9183             var dom = this.dom;
9184             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9185         },
9186
9187         /**
9188          * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9189          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9190          * @param {Number} value The new scroll value
9191          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9192          * @return {Element} this
9193          */
9194
9195         scrollTo : function(side, value, animate){
9196             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9197             if(!animate || !A){
9198                 this.dom[prop] = value;
9199             }else{
9200                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9201                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9202             }
9203             return this;
9204         },
9205
9206         /**
9207          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9208          * within this element's scrollable range.
9209          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9210          * @param {Number} distance How far to scroll the element in pixels
9211          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9212          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9213          * was scrolled as far as it could go.
9214          */
9215          scroll : function(direction, distance, animate){
9216              if(!this.isScrollable()){
9217                  return;
9218              }
9219              var el = this.dom;
9220              var l = el.scrollLeft, t = el.scrollTop;
9221              var w = el.scrollWidth, h = el.scrollHeight;
9222              var cw = el.clientWidth, ch = el.clientHeight;
9223              direction = direction.toLowerCase();
9224              var scrolled = false;
9225              var a = this.preanim(arguments, 2);
9226              switch(direction){
9227                  case "l":
9228                  case "left":
9229                      if(w - l > cw){
9230                          var v = Math.min(l + distance, w-cw);
9231                          this.scrollTo("left", v, a);
9232                          scrolled = true;
9233                      }
9234                      break;
9235                 case "r":
9236                 case "right":
9237                      if(l > 0){
9238                          var v = Math.max(l - distance, 0);
9239                          this.scrollTo("left", v, a);
9240                          scrolled = true;
9241                      }
9242                      break;
9243                 case "t":
9244                 case "top":
9245                 case "up":
9246                      if(t > 0){
9247                          var v = Math.max(t - distance, 0);
9248                          this.scrollTo("top", v, a);
9249                          scrolled = true;
9250                      }
9251                      break;
9252                 case "b":
9253                 case "bottom":
9254                 case "down":
9255                      if(h - t > ch){
9256                          var v = Math.min(t + distance, h-ch);
9257                          this.scrollTo("top", v, a);
9258                          scrolled = true;
9259                      }
9260                      break;
9261              }
9262              return scrolled;
9263         },
9264
9265         /**
9266          * Translates the passed page coordinates into left/top css values for this element
9267          * @param {Number/Array} x The page x or an array containing [x, y]
9268          * @param {Number} y The page y
9269          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9270          */
9271         translatePoints : function(x, y){
9272             if(typeof x == 'object' || x instanceof Array){
9273                 y = x[1]; x = x[0];
9274             }
9275             var p = this.getStyle('position');
9276             var o = this.getXY();
9277
9278             var l = parseInt(this.getStyle('left'), 10);
9279             var t = parseInt(this.getStyle('top'), 10);
9280
9281             if(isNaN(l)){
9282                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9283             }
9284             if(isNaN(t)){
9285                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9286             }
9287
9288             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9289         },
9290
9291         /**
9292          * Returns the current scroll position of the element.
9293          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9294          */
9295         getScroll : function(){
9296             var d = this.dom, doc = document;
9297             if(d == doc || d == doc.body){
9298                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9299                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9300                 return {left: l, top: t};
9301             }else{
9302                 return {left: d.scrollLeft, top: d.scrollTop};
9303             }
9304         },
9305
9306         /**
9307          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9308          * are convert to standard 6 digit hex color.
9309          * @param {String} attr The css attribute
9310          * @param {String} defaultValue The default value to use when a valid color isn't found
9311          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9312          * YUI color anims.
9313          */
9314         getColor : function(attr, defaultValue, prefix){
9315             var v = this.getStyle(attr);
9316             if(!v || v == "transparent" || v == "inherit") {
9317                 return defaultValue;
9318             }
9319             var color = typeof prefix == "undefined" ? "#" : prefix;
9320             if(v.substr(0, 4) == "rgb("){
9321                 var rvs = v.slice(4, v.length -1).split(",");
9322                 for(var i = 0; i < 3; i++){
9323                     var h = parseInt(rvs[i]).toString(16);
9324                     if(h < 16){
9325                         h = "0" + h;
9326                     }
9327                     color += h;
9328                 }
9329             } else {
9330                 if(v.substr(0, 1) == "#"){
9331                     if(v.length == 4) {
9332                         for(var i = 1; i < 4; i++){
9333                             var c = v.charAt(i);
9334                             color +=  c + c;
9335                         }
9336                     }else if(v.length == 7){
9337                         color += v.substr(1);
9338                     }
9339                 }
9340             }
9341             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9342         },
9343
9344         /**
9345          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9346          * gradient background, rounded corners and a 4-way shadow.
9347          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9348          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9349          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9350          * @return {Roo.Element} this
9351          */
9352         boxWrap : function(cls){
9353             cls = cls || 'x-box';
9354             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9355             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9356             return el;
9357         },
9358
9359         /**
9360          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9361          * @param {String} namespace The namespace in which to look for the attribute
9362          * @param {String} name The attribute name
9363          * @return {String} The attribute value
9364          */
9365         getAttributeNS : Roo.isIE ? function(ns, name){
9366             var d = this.dom;
9367             var type = typeof d[ns+":"+name];
9368             if(type != 'undefined' && type != 'unknown'){
9369                 return d[ns+":"+name];
9370             }
9371             return d[name];
9372         } : function(ns, name){
9373             var d = this.dom;
9374             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9375         }
9376     };
9377
9378     var ep = El.prototype;
9379
9380     /**
9381      * Appends an event handler (Shorthand for addListener)
9382      * @param {String}   eventName     The type of event to append
9383      * @param {Function} fn        The method the event invokes
9384      * @param {Object} scope       (optional) The scope (this object) of the fn
9385      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9386      * @method
9387      */
9388     ep.on = ep.addListener;
9389         // backwards compat
9390     ep.mon = ep.addListener;
9391
9392     /**
9393      * Removes an event handler from this element (shorthand for removeListener)
9394      * @param {String} eventName the type of event to remove
9395      * @param {Function} fn the method the event invokes
9396      * @return {Roo.Element} this
9397      * @method
9398      */
9399     ep.un = ep.removeListener;
9400
9401     /**
9402      * true to automatically adjust width and height settings for box-model issues (default to true)
9403      */
9404     ep.autoBoxAdjust = true;
9405
9406     // private
9407     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9408
9409     // private
9410     El.addUnits = function(v, defaultUnit){
9411         if(v === "" || v == "auto"){
9412             return v;
9413         }
9414         if(v === undefined){
9415             return '';
9416         }
9417         if(typeof v == "number" || !El.unitPattern.test(v)){
9418             return v + (defaultUnit || 'px');
9419         }
9420         return v;
9421     };
9422
9423     // special markup used throughout Roo when box wrapping elements
9424     El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9425     /**
9426      * Visibility mode constant - Use visibility to hide element
9427      * @static
9428      * @type Number
9429      */
9430     El.VISIBILITY = 1;
9431     /**
9432      * Visibility mode constant - Use display to hide element
9433      * @static
9434      * @type Number
9435      */
9436     El.DISPLAY = 2;
9437
9438     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9439     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9440     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9441
9442
9443
9444     /**
9445      * @private
9446      */
9447     El.cache = {};
9448
9449     var docEl;
9450
9451     /**
9452      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9453      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9454      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9455      * @return {Element} The Element object
9456      * @static
9457      */
9458     El.get = function(el){
9459         var ex, elm, id;
9460         if(!el){ return null; }
9461         if(typeof el == "string"){ // element id
9462             if(!(elm = document.getElementById(el))){
9463                 return null;
9464             }
9465             if(ex = El.cache[el]){
9466                 ex.dom = elm;
9467             }else{
9468                 ex = El.cache[el] = new El(elm);
9469             }
9470             return ex;
9471         }else if(el.tagName){ // dom element
9472             if(!(id = el.id)){
9473                 id = Roo.id(el);
9474             }
9475             if(ex = El.cache[id]){
9476                 ex.dom = el;
9477             }else{
9478                 ex = El.cache[id] = new El(el);
9479             }
9480             return ex;
9481         }else if(el instanceof El){
9482             if(el != docEl){
9483                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9484                                                               // catch case where it hasn't been appended
9485                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9486             }
9487             return el;
9488         }else if(el.isComposite){
9489             return el;
9490         }else if(el instanceof Array){
9491             return El.select(el);
9492         }else if(el == document){
9493             // create a bogus element object representing the document object
9494             if(!docEl){
9495                 var f = function(){};
9496                 f.prototype = El.prototype;
9497                 docEl = new f();
9498                 docEl.dom = document;
9499             }
9500             return docEl;
9501         }
9502         return null;
9503     };
9504
9505     // private
9506     El.uncache = function(el){
9507         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9508             if(a[i]){
9509                 delete El.cache[a[i].id || a[i]];
9510             }
9511         }
9512     };
9513
9514     // private
9515     // Garbage collection - uncache elements/purge listeners on orphaned elements
9516     // so we don't hold a reference and cause the browser to retain them
9517     El.garbageCollect = function(){
9518         if(!Roo.enableGarbageCollector){
9519             clearInterval(El.collectorThread);
9520             return;
9521         }
9522         for(var eid in El.cache){
9523             var el = El.cache[eid], d = el.dom;
9524             // -------------------------------------------------------
9525             // Determining what is garbage:
9526             // -------------------------------------------------------
9527             // !d
9528             // dom node is null, definitely garbage
9529             // -------------------------------------------------------
9530             // !d.parentNode
9531             // no parentNode == direct orphan, definitely garbage
9532             // -------------------------------------------------------
9533             // !d.offsetParent && !document.getElementById(eid)
9534             // display none elements have no offsetParent so we will
9535             // also try to look it up by it's id. However, check
9536             // offsetParent first so we don't do unneeded lookups.
9537             // This enables collection of elements that are not orphans
9538             // directly, but somewhere up the line they have an orphan
9539             // parent.
9540             // -------------------------------------------------------
9541             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9542                 delete El.cache[eid];
9543                 if(d && Roo.enableListenerCollection){
9544                     E.purgeElement(d);
9545                 }
9546             }
9547         }
9548     }
9549     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9550
9551
9552     // dom is optional
9553     El.Flyweight = function(dom){
9554         this.dom = dom;
9555     };
9556     El.Flyweight.prototype = El.prototype;
9557
9558     El._flyweights = {};
9559     /**
9560      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9561      * the dom node can be overwritten by other code.
9562      * @param {String/HTMLElement} el The dom node or id
9563      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9564      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9565      * @static
9566      * @return {Element} The shared Element object
9567      */
9568     El.fly = function(el, named){
9569         named = named || '_global';
9570         el = Roo.getDom(el);
9571         if(!el){
9572             return null;
9573         }
9574         if(!El._flyweights[named]){
9575             El._flyweights[named] = new El.Flyweight();
9576         }
9577         El._flyweights[named].dom = el;
9578         return El._flyweights[named];
9579     };
9580
9581     /**
9582      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9583      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9584      * Shorthand of {@link Roo.Element#get}
9585      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9586      * @return {Element} The Element object
9587      * @member Roo
9588      * @method get
9589      */
9590     Roo.get = El.get;
9591     /**
9592      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9593      * the dom node can be overwritten by other code.
9594      * Shorthand of {@link Roo.Element#fly}
9595      * @param {String/HTMLElement} el The dom node or id
9596      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9597      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9598      * @static
9599      * @return {Element} The shared Element object
9600      * @member Roo
9601      * @method fly
9602      */
9603     Roo.fly = El.fly;
9604
9605     // speedy lookup for elements never to box adjust
9606     var noBoxAdjust = Roo.isStrict ? {
9607         select:1
9608     } : {
9609         input:1, select:1, textarea:1
9610     };
9611     if(Roo.isIE || Roo.isGecko){
9612         noBoxAdjust['button'] = 1;
9613     }
9614
9615
9616     Roo.EventManager.on(window, 'unload', function(){
9617         delete El.cache;
9618         delete El._flyweights;
9619     });
9620 })();
9621
9622
9623
9624
9625 if(Roo.DomQuery){
9626     Roo.Element.selectorFunction = Roo.DomQuery.select;
9627 }
9628
9629 Roo.Element.select = function(selector, unique, root){
9630     var els;
9631     if(typeof selector == "string"){
9632         els = Roo.Element.selectorFunction(selector, root);
9633     }else if(selector.length !== undefined){
9634         els = selector;
9635     }else{
9636         throw "Invalid selector";
9637     }
9638     if(unique === true){
9639         return new Roo.CompositeElement(els);
9640     }else{
9641         return new Roo.CompositeElementLite(els);
9642     }
9643 };
9644 /**
9645  * Selects elements based on the passed CSS selector to enable working on them as 1.
9646  * @param {String/Array} selector The CSS selector or an array of elements
9647  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9648  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9649  * @return {CompositeElementLite/CompositeElement}
9650  * @member Roo
9651  * @method select
9652  */
9653 Roo.select = Roo.Element.select;
9654
9655
9656
9657
9658
9659
9660
9661
9662
9663
9664
9665
9666
9667
9668 /*
9669  * Based on:
9670  * Ext JS Library 1.1.1
9671  * Copyright(c) 2006-2007, Ext JS, LLC.
9672  *
9673  * Originally Released Under LGPL - original licence link has changed is not relivant.
9674  *
9675  * Fork - LGPL
9676  * <script type="text/javascript">
9677  */
9678
9679
9680
9681 //Notifies Element that fx methods are available
9682 Roo.enableFx = true;
9683
9684 /**
9685  * @class Roo.Fx
9686  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9687  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9688  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9689  * Element effects to work.</p><br/>
9690  *
9691  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9692  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9693  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9694  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9695  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9696  * expected results and should be done with care.</p><br/>
9697  *
9698  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9699  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9700 <pre>
9701 Value  Description
9702 -----  -----------------------------
9703 tl     The top left corner
9704 t      The center of the top edge
9705 tr     The top right corner
9706 l      The center of the left edge
9707 r      The center of the right edge
9708 bl     The bottom left corner
9709 b      The center of the bottom edge
9710 br     The bottom right corner
9711 </pre>
9712  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9713  * below are common options that can be passed to any Fx method.</b>
9714  * @cfg {Function} callback A function called when the effect is finished
9715  * @cfg {Object} scope The scope of the effect function
9716  * @cfg {String} easing A valid Easing value for the effect
9717  * @cfg {String} afterCls A css class to apply after the effect
9718  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9719  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9720  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9721  * effects that end with the element being visually hidden, ignored otherwise)
9722  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9723  * a function which returns such a specification that will be applied to the Element after the effect finishes
9724  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9725  * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9726  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9727  */
9728 Roo.Fx = {
9729         /**
9730          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9731          * origin for the slide effect.  This function automatically handles wrapping the element with
9732          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9733          * Usage:
9734          *<pre><code>
9735 // default: slide the element in from the top
9736 el.slideIn();
9737
9738 // custom: slide the element in from the right with a 2-second duration
9739 el.slideIn('r', { duration: 2 });
9740
9741 // common config options shown with default values
9742 el.slideIn('t', {
9743     easing: 'easeOut',
9744     duration: .5
9745 });
9746 </code></pre>
9747          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9748          * @param {Object} options (optional) Object literal with any of the Fx config options
9749          * @return {Roo.Element} The Element
9750          */
9751     slideIn : function(anchor, o){
9752         var el = this.getFxEl();
9753         o = o || {};
9754
9755         el.queueFx(o, function(){
9756
9757             anchor = anchor || "t";
9758
9759             // fix display to visibility
9760             this.fixDisplay();
9761
9762             // restore values after effect
9763             var r = this.getFxRestore();
9764             var b = this.getBox();
9765             // fixed size for slide
9766             this.setSize(b);
9767
9768             // wrap if needed
9769             var wrap = this.fxWrap(r.pos, o, "hidden");
9770
9771             var st = this.dom.style;
9772             st.visibility = "visible";
9773             st.position = "absolute";
9774
9775             // clear out temp styles after slide and unwrap
9776             var after = function(){
9777                 el.fxUnwrap(wrap, r.pos, o);
9778                 st.width = r.width;
9779                 st.height = r.height;
9780                 el.afterFx(o);
9781             };
9782             // time to calc the positions
9783             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9784
9785             switch(anchor.toLowerCase()){
9786                 case "t":
9787                     wrap.setSize(b.width, 0);
9788                     st.left = st.bottom = "0";
9789                     a = {height: bh};
9790                 break;
9791                 case "l":
9792                     wrap.setSize(0, b.height);
9793                     st.right = st.top = "0";
9794                     a = {width: bw};
9795                 break;
9796                 case "r":
9797                     wrap.setSize(0, b.height);
9798                     wrap.setX(b.right);
9799                     st.left = st.top = "0";
9800                     a = {width: bw, points: pt};
9801                 break;
9802                 case "b":
9803                     wrap.setSize(b.width, 0);
9804                     wrap.setY(b.bottom);
9805                     st.left = st.top = "0";
9806                     a = {height: bh, points: pt};
9807                 break;
9808                 case "tl":
9809                     wrap.setSize(0, 0);
9810                     st.right = st.bottom = "0";
9811                     a = {width: bw, height: bh};
9812                 break;
9813                 case "bl":
9814                     wrap.setSize(0, 0);
9815                     wrap.setY(b.y+b.height);
9816                     st.right = st.top = "0";
9817                     a = {width: bw, height: bh, points: pt};
9818                 break;
9819                 case "br":
9820                     wrap.setSize(0, 0);
9821                     wrap.setXY([b.right, b.bottom]);
9822                     st.left = st.top = "0";
9823                     a = {width: bw, height: bh, points: pt};
9824                 break;
9825                 case "tr":
9826                     wrap.setSize(0, 0);
9827                     wrap.setX(b.x+b.width);
9828                     st.left = st.bottom = "0";
9829                     a = {width: bw, height: bh, points: pt};
9830                 break;
9831             }
9832             this.dom.style.visibility = "visible";
9833             wrap.show();
9834
9835             arguments.callee.anim = wrap.fxanim(a,
9836                 o,
9837                 'motion',
9838                 .5,
9839                 'easeOut', after);
9840         });
9841         return this;
9842     },
9843     
9844         /**
9845          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9846          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9847          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9848          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9849          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9850          * Usage:
9851          *<pre><code>
9852 // default: slide the element out to the top
9853 el.slideOut();
9854
9855 // custom: slide the element out to the right with a 2-second duration
9856 el.slideOut('r', { duration: 2 });
9857
9858 // common config options shown with default values
9859 el.slideOut('t', {
9860     easing: 'easeOut',
9861     duration: .5,
9862     remove: false,
9863     useDisplay: false
9864 });
9865 </code></pre>
9866          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9867          * @param {Object} options (optional) Object literal with any of the Fx config options
9868          * @return {Roo.Element} The Element
9869          */
9870     slideOut : function(anchor, o){
9871         var el = this.getFxEl();
9872         o = o || {};
9873
9874         el.queueFx(o, function(){
9875
9876             anchor = anchor || "t";
9877
9878             // restore values after effect
9879             var r = this.getFxRestore();
9880             
9881             var b = this.getBox();
9882             // fixed size for slide
9883             this.setSize(b);
9884
9885             // wrap if needed
9886             var wrap = this.fxWrap(r.pos, o, "visible");
9887
9888             var st = this.dom.style;
9889             st.visibility = "visible";
9890             st.position = "absolute";
9891
9892             wrap.setSize(b);
9893
9894             var after = function(){
9895                 if(o.useDisplay){
9896                     el.setDisplayed(false);
9897                 }else{
9898                     el.hide();
9899                 }
9900
9901                 el.fxUnwrap(wrap, r.pos, o);
9902
9903                 st.width = r.width;
9904                 st.height = r.height;
9905
9906                 el.afterFx(o);
9907             };
9908
9909             var a, zero = {to: 0};
9910             switch(anchor.toLowerCase()){
9911                 case "t":
9912                     st.left = st.bottom = "0";
9913                     a = {height: zero};
9914                 break;
9915                 case "l":
9916                     st.right = st.top = "0";
9917                     a = {width: zero};
9918                 break;
9919                 case "r":
9920                     st.left = st.top = "0";
9921                     a = {width: zero, points: {to:[b.right, b.y]}};
9922                 break;
9923                 case "b":
9924                     st.left = st.top = "0";
9925                     a = {height: zero, points: {to:[b.x, b.bottom]}};
9926                 break;
9927                 case "tl":
9928                     st.right = st.bottom = "0";
9929                     a = {width: zero, height: zero};
9930                 break;
9931                 case "bl":
9932                     st.right = st.top = "0";
9933                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9934                 break;
9935                 case "br":
9936                     st.left = st.top = "0";
9937                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9938                 break;
9939                 case "tr":
9940                     st.left = st.bottom = "0";
9941                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9942                 break;
9943             }
9944
9945             arguments.callee.anim = wrap.fxanim(a,
9946                 o,
9947                 'motion',
9948                 .5,
9949                 "easeOut", after);
9950         });
9951         return this;
9952     },
9953
9954         /**
9955          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
9956          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
9957          * The element must be removed from the DOM using the 'remove' config option if desired.
9958          * Usage:
9959          *<pre><code>
9960 // default
9961 el.puff();
9962
9963 // common config options shown with default values
9964 el.puff({
9965     easing: 'easeOut',
9966     duration: .5,
9967     remove: false,
9968     useDisplay: false
9969 });
9970 </code></pre>
9971          * @param {Object} options (optional) Object literal with any of the Fx config options
9972          * @return {Roo.Element} The Element
9973          */
9974     puff : function(o){
9975         var el = this.getFxEl();
9976         o = o || {};
9977
9978         el.queueFx(o, function(){
9979             this.clearOpacity();
9980             this.show();
9981
9982             // restore values after effect
9983             var r = this.getFxRestore();
9984             var st = this.dom.style;
9985
9986             var after = function(){
9987                 if(o.useDisplay){
9988                     el.setDisplayed(false);
9989                 }else{
9990                     el.hide();
9991                 }
9992
9993                 el.clearOpacity();
9994
9995                 el.setPositioning(r.pos);
9996                 st.width = r.width;
9997                 st.height = r.height;
9998                 st.fontSize = '';
9999                 el.afterFx(o);
10000             };
10001
10002             var width = this.getWidth();
10003             var height = this.getHeight();
10004
10005             arguments.callee.anim = this.fxanim({
10006                     width : {to: this.adjustWidth(width * 2)},
10007                     height : {to: this.adjustHeight(height * 2)},
10008                     points : {by: [-(width * .5), -(height * .5)]},
10009                     opacity : {to: 0},
10010                     fontSize: {to:200, unit: "%"}
10011                 },
10012                 o,
10013                 'motion',
10014                 .5,
10015                 "easeOut", after);
10016         });
10017         return this;
10018     },
10019
10020         /**
10021          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10022          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10023          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10024          * Usage:
10025          *<pre><code>
10026 // default
10027 el.switchOff();
10028
10029 // all config options shown with default values
10030 el.switchOff({
10031     easing: 'easeIn',
10032     duration: .3,
10033     remove: false,
10034     useDisplay: false
10035 });
10036 </code></pre>
10037          * @param {Object} options (optional) Object literal with any of the Fx config options
10038          * @return {Roo.Element} The Element
10039          */
10040     switchOff : function(o){
10041         var el = this.getFxEl();
10042         o = o || {};
10043
10044         el.queueFx(o, function(){
10045             this.clearOpacity();
10046             this.clip();
10047
10048             // restore values after effect
10049             var r = this.getFxRestore();
10050             var st = this.dom.style;
10051
10052             var after = function(){
10053                 if(o.useDisplay){
10054                     el.setDisplayed(false);
10055                 }else{
10056                     el.hide();
10057                 }
10058
10059                 el.clearOpacity();
10060                 el.setPositioning(r.pos);
10061                 st.width = r.width;
10062                 st.height = r.height;
10063
10064                 el.afterFx(o);
10065             };
10066
10067             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10068                 this.clearOpacity();
10069                 (function(){
10070                     this.fxanim({
10071                         height:{to:1},
10072                         points:{by:[0, this.getHeight() * .5]}
10073                     }, o, 'motion', 0.3, 'easeIn', after);
10074                 }).defer(100, this);
10075             });
10076         });
10077         return this;
10078     },
10079
10080     /**
10081      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10082      * changed using the "attr" config option) and then fading back to the original color. If no original
10083      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10084      * Usage:
10085 <pre><code>
10086 // default: highlight background to yellow
10087 el.highlight();
10088
10089 // custom: highlight foreground text to blue for 2 seconds
10090 el.highlight("0000ff", { attr: 'color', duration: 2 });
10091
10092 // common config options shown with default values
10093 el.highlight("ffff9c", {
10094     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10095     endColor: (current color) or "ffffff",
10096     easing: 'easeIn',
10097     duration: 1
10098 });
10099 </code></pre>
10100      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10101      * @param {Object} options (optional) Object literal with any of the Fx config options
10102      * @return {Roo.Element} The Element
10103      */ 
10104     highlight : function(color, o){
10105         var el = this.getFxEl();
10106         o = o || {};
10107
10108         el.queueFx(o, function(){
10109             color = color || "ffff9c";
10110             attr = o.attr || "backgroundColor";
10111
10112             this.clearOpacity();
10113             this.show();
10114
10115             var origColor = this.getColor(attr);
10116             var restoreColor = this.dom.style[attr];
10117             endColor = (o.endColor || origColor) || "ffffff";
10118
10119             var after = function(){
10120                 el.dom.style[attr] = restoreColor;
10121                 el.afterFx(o);
10122             };
10123
10124             var a = {};
10125             a[attr] = {from: color, to: endColor};
10126             arguments.callee.anim = this.fxanim(a,
10127                 o,
10128                 'color',
10129                 1,
10130                 'easeIn', after);
10131         });
10132         return this;
10133     },
10134
10135    /**
10136     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10137     * Usage:
10138 <pre><code>
10139 // default: a single light blue ripple
10140 el.frame();
10141
10142 // custom: 3 red ripples lasting 3 seconds total
10143 el.frame("ff0000", 3, { duration: 3 });
10144
10145 // common config options shown with default values
10146 el.frame("C3DAF9", 1, {
10147     duration: 1 //duration of entire animation (not each individual ripple)
10148     // Note: Easing is not configurable and will be ignored if included
10149 });
10150 </code></pre>
10151     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10152     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10153     * @param {Object} options (optional) Object literal with any of the Fx config options
10154     * @return {Roo.Element} The Element
10155     */
10156     frame : function(color, count, o){
10157         var el = this.getFxEl();
10158         o = o || {};
10159
10160         el.queueFx(o, function(){
10161             color = color || "#C3DAF9";
10162             if(color.length == 6){
10163                 color = "#" + color;
10164             }
10165             count = count || 1;
10166             duration = o.duration || 1;
10167             this.show();
10168
10169             var b = this.getBox();
10170             var animFn = function(){
10171                 var proxy = this.createProxy({
10172
10173                      style:{
10174                         visbility:"hidden",
10175                         position:"absolute",
10176                         "z-index":"35000", // yee haw
10177                         border:"0px solid " + color
10178                      }
10179                   });
10180                 var scale = Roo.isBorderBox ? 2 : 1;
10181                 proxy.animate({
10182                     top:{from:b.y, to:b.y - 20},
10183                     left:{from:b.x, to:b.x - 20},
10184                     borderWidth:{from:0, to:10},
10185                     opacity:{from:1, to:0},
10186                     height:{from:b.height, to:(b.height + (20*scale))},
10187                     width:{from:b.width, to:(b.width + (20*scale))}
10188                 }, duration, function(){
10189                     proxy.remove();
10190                 });
10191                 if(--count > 0){
10192                      animFn.defer((duration/2)*1000, this);
10193                 }else{
10194                     el.afterFx(o);
10195                 }
10196             };
10197             animFn.call(this);
10198         });
10199         return this;
10200     },
10201
10202    /**
10203     * Creates a pause before any subsequent queued effects begin.  If there are
10204     * no effects queued after the pause it will have no effect.
10205     * Usage:
10206 <pre><code>
10207 el.pause(1);
10208 </code></pre>
10209     * @param {Number} seconds The length of time to pause (in seconds)
10210     * @return {Roo.Element} The Element
10211     */
10212     pause : function(seconds){
10213         var el = this.getFxEl();
10214         var o = {};
10215
10216         el.queueFx(o, function(){
10217             setTimeout(function(){
10218                 el.afterFx(o);
10219             }, seconds * 1000);
10220         });
10221         return this;
10222     },
10223
10224    /**
10225     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10226     * using the "endOpacity" config option.
10227     * Usage:
10228 <pre><code>
10229 // default: fade in from opacity 0 to 100%
10230 el.fadeIn();
10231
10232 // custom: fade in from opacity 0 to 75% over 2 seconds
10233 el.fadeIn({ endOpacity: .75, duration: 2});
10234
10235 // common config options shown with default values
10236 el.fadeIn({
10237     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10238     easing: 'easeOut',
10239     duration: .5
10240 });
10241 </code></pre>
10242     * @param {Object} options (optional) Object literal with any of the Fx config options
10243     * @return {Roo.Element} The Element
10244     */
10245     fadeIn : function(o){
10246         var el = this.getFxEl();
10247         o = o || {};
10248         el.queueFx(o, function(){
10249             this.setOpacity(0);
10250             this.fixDisplay();
10251             this.dom.style.visibility = 'visible';
10252             var to = o.endOpacity || 1;
10253             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10254                 o, null, .5, "easeOut", function(){
10255                 if(to == 1){
10256                     this.clearOpacity();
10257                 }
10258                 el.afterFx(o);
10259             });
10260         });
10261         return this;
10262     },
10263
10264    /**
10265     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10266     * using the "endOpacity" config option.
10267     * Usage:
10268 <pre><code>
10269 // default: fade out from the element's current opacity to 0
10270 el.fadeOut();
10271
10272 // custom: fade out from the element's current opacity to 25% over 2 seconds
10273 el.fadeOut({ endOpacity: .25, duration: 2});
10274
10275 // common config options shown with default values
10276 el.fadeOut({
10277     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10278     easing: 'easeOut',
10279     duration: .5
10280     remove: false,
10281     useDisplay: false
10282 });
10283 </code></pre>
10284     * @param {Object} options (optional) Object literal with any of the Fx config options
10285     * @return {Roo.Element} The Element
10286     */
10287     fadeOut : function(o){
10288         var el = this.getFxEl();
10289         o = o || {};
10290         el.queueFx(o, function(){
10291             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10292                 o, null, .5, "easeOut", function(){
10293                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10294                      this.dom.style.display = "none";
10295                 }else{
10296                      this.dom.style.visibility = "hidden";
10297                 }
10298                 this.clearOpacity();
10299                 el.afterFx(o);
10300             });
10301         });
10302         return this;
10303     },
10304
10305    /**
10306     * Animates the transition of an element's dimensions from a starting height/width
10307     * to an ending height/width.
10308     * Usage:
10309 <pre><code>
10310 // change height and width to 100x100 pixels
10311 el.scale(100, 100);
10312
10313 // common config options shown with default values.  The height and width will default to
10314 // the element's existing values if passed as null.
10315 el.scale(
10316     [element's width],
10317     [element's height], {
10318     easing: 'easeOut',
10319     duration: .35
10320 });
10321 </code></pre>
10322     * @param {Number} width  The new width (pass undefined to keep the original width)
10323     * @param {Number} height  The new height (pass undefined to keep the original height)
10324     * @param {Object} options (optional) Object literal with any of the Fx config options
10325     * @return {Roo.Element} The Element
10326     */
10327     scale : function(w, h, o){
10328         this.shift(Roo.apply({}, o, {
10329             width: w,
10330             height: h
10331         }));
10332         return this;
10333     },
10334
10335    /**
10336     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10337     * Any of these properties not specified in the config object will not be changed.  This effect 
10338     * requires that at least one new dimension, position or opacity setting must be passed in on
10339     * the config object in order for the function to have any effect.
10340     * Usage:
10341 <pre><code>
10342 // slide the element horizontally to x position 200 while changing the height and opacity
10343 el.shift({ x: 200, height: 50, opacity: .8 });
10344
10345 // common config options shown with default values.
10346 el.shift({
10347     width: [element's width],
10348     height: [element's height],
10349     x: [element's x position],
10350     y: [element's y position],
10351     opacity: [element's opacity],
10352     easing: 'easeOut',
10353     duration: .35
10354 });
10355 </code></pre>
10356     * @param {Object} options  Object literal with any of the Fx config options
10357     * @return {Roo.Element} The Element
10358     */
10359     shift : function(o){
10360         var el = this.getFxEl();
10361         o = o || {};
10362         el.queueFx(o, function(){
10363             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10364             if(w !== undefined){
10365                 a.width = {to: this.adjustWidth(w)};
10366             }
10367             if(h !== undefined){
10368                 a.height = {to: this.adjustHeight(h)};
10369             }
10370             if(x !== undefined || y !== undefined){
10371                 a.points = {to: [
10372                     x !== undefined ? x : this.getX(),
10373                     y !== undefined ? y : this.getY()
10374                 ]};
10375             }
10376             if(op !== undefined){
10377                 a.opacity = {to: op};
10378             }
10379             if(o.xy !== undefined){
10380                 a.points = {to: o.xy};
10381             }
10382             arguments.callee.anim = this.fxanim(a,
10383                 o, 'motion', .35, "easeOut", function(){
10384                 el.afterFx(o);
10385             });
10386         });
10387         return this;
10388     },
10389
10390         /**
10391          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10392          * ending point of the effect.
10393          * Usage:
10394          *<pre><code>
10395 // default: slide the element downward while fading out
10396 el.ghost();
10397
10398 // custom: slide the element out to the right with a 2-second duration
10399 el.ghost('r', { duration: 2 });
10400
10401 // common config options shown with default values
10402 el.ghost('b', {
10403     easing: 'easeOut',
10404     duration: .5
10405     remove: false,
10406     useDisplay: false
10407 });
10408 </code></pre>
10409          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10410          * @param {Object} options (optional) Object literal with any of the Fx config options
10411          * @return {Roo.Element} The Element
10412          */
10413     ghost : function(anchor, o){
10414         var el = this.getFxEl();
10415         o = o || {};
10416
10417         el.queueFx(o, function(){
10418             anchor = anchor || "b";
10419
10420             // restore values after effect
10421             var r = this.getFxRestore();
10422             var w = this.getWidth(),
10423                 h = this.getHeight();
10424
10425             var st = this.dom.style;
10426
10427             var after = function(){
10428                 if(o.useDisplay){
10429                     el.setDisplayed(false);
10430                 }else{
10431                     el.hide();
10432                 }
10433
10434                 el.clearOpacity();
10435                 el.setPositioning(r.pos);
10436                 st.width = r.width;
10437                 st.height = r.height;
10438
10439                 el.afterFx(o);
10440             };
10441
10442             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10443             switch(anchor.toLowerCase()){
10444                 case "t":
10445                     pt.by = [0, -h];
10446                 break;
10447                 case "l":
10448                     pt.by = [-w, 0];
10449                 break;
10450                 case "r":
10451                     pt.by = [w, 0];
10452                 break;
10453                 case "b":
10454                     pt.by = [0, h];
10455                 break;
10456                 case "tl":
10457                     pt.by = [-w, -h];
10458                 break;
10459                 case "bl":
10460                     pt.by = [-w, h];
10461                 break;
10462                 case "br":
10463                     pt.by = [w, h];
10464                 break;
10465                 case "tr":
10466                     pt.by = [w, -h];
10467                 break;
10468             }
10469
10470             arguments.callee.anim = this.fxanim(a,
10471                 o,
10472                 'motion',
10473                 .5,
10474                 "easeOut", after);
10475         });
10476         return this;
10477     },
10478
10479         /**
10480          * Ensures that all effects queued after syncFx is called on the element are
10481          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10482          * @return {Roo.Element} The Element
10483          */
10484     syncFx : function(){
10485         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10486             block : false,
10487             concurrent : true,
10488             stopFx : false
10489         });
10490         return this;
10491     },
10492
10493         /**
10494          * Ensures that all effects queued after sequenceFx is called on the element are
10495          * run in sequence.  This is the opposite of {@link #syncFx}.
10496          * @return {Roo.Element} The Element
10497          */
10498     sequenceFx : function(){
10499         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10500             block : false,
10501             concurrent : false,
10502             stopFx : false
10503         });
10504         return this;
10505     },
10506
10507         /* @private */
10508     nextFx : function(){
10509         var ef = this.fxQueue[0];
10510         if(ef){
10511             ef.call(this);
10512         }
10513     },
10514
10515         /**
10516          * Returns true if the element has any effects actively running or queued, else returns false.
10517          * @return {Boolean} True if element has active effects, else false
10518          */
10519     hasActiveFx : function(){
10520         return this.fxQueue && this.fxQueue[0];
10521     },
10522
10523         /**
10524          * Stops any running effects and clears the element's internal effects queue if it contains
10525          * any additional effects that haven't started yet.
10526          * @return {Roo.Element} The Element
10527          */
10528     stopFx : function(){
10529         if(this.hasActiveFx()){
10530             var cur = this.fxQueue[0];
10531             if(cur && cur.anim && cur.anim.isAnimated()){
10532                 this.fxQueue = [cur]; // clear out others
10533                 cur.anim.stop(true);
10534             }
10535         }
10536         return this;
10537     },
10538
10539         /* @private */
10540     beforeFx : function(o){
10541         if(this.hasActiveFx() && !o.concurrent){
10542            if(o.stopFx){
10543                this.stopFx();
10544                return true;
10545            }
10546            return false;
10547         }
10548         return true;
10549     },
10550
10551         /**
10552          * Returns true if the element is currently blocking so that no other effect can be queued
10553          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10554          * used to ensure that an effect initiated by a user action runs to completion prior to the
10555          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10556          * @return {Boolean} True if blocking, else false
10557          */
10558     hasFxBlock : function(){
10559         var q = this.fxQueue;
10560         return q && q[0] && q[0].block;
10561     },
10562
10563         /* @private */
10564     queueFx : function(o, fn){
10565         if(!this.fxQueue){
10566             this.fxQueue = [];
10567         }
10568         if(!this.hasFxBlock()){
10569             Roo.applyIf(o, this.fxDefaults);
10570             if(!o.concurrent){
10571                 var run = this.beforeFx(o);
10572                 fn.block = o.block;
10573                 this.fxQueue.push(fn);
10574                 if(run){
10575                     this.nextFx();
10576                 }
10577             }else{
10578                 fn.call(this);
10579             }
10580         }
10581         return this;
10582     },
10583
10584         /* @private */
10585     fxWrap : function(pos, o, vis){
10586         var wrap;
10587         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10588             var wrapXY;
10589             if(o.fixPosition){
10590                 wrapXY = this.getXY();
10591             }
10592             var div = document.createElement("div");
10593             div.style.visibility = vis;
10594             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10595             wrap.setPositioning(pos);
10596             if(wrap.getStyle("position") == "static"){
10597                 wrap.position("relative");
10598             }
10599             this.clearPositioning('auto');
10600             wrap.clip();
10601             wrap.dom.appendChild(this.dom);
10602             if(wrapXY){
10603                 wrap.setXY(wrapXY);
10604             }
10605         }
10606         return wrap;
10607     },
10608
10609         /* @private */
10610     fxUnwrap : function(wrap, pos, o){
10611         this.clearPositioning();
10612         this.setPositioning(pos);
10613         if(!o.wrap){
10614             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10615             wrap.remove();
10616         }
10617     },
10618
10619         /* @private */
10620     getFxRestore : function(){
10621         var st = this.dom.style;
10622         return {pos: this.getPositioning(), width: st.width, height : st.height};
10623     },
10624
10625         /* @private */
10626     afterFx : function(o){
10627         if(o.afterStyle){
10628             this.applyStyles(o.afterStyle);
10629         }
10630         if(o.afterCls){
10631             this.addClass(o.afterCls);
10632         }
10633         if(o.remove === true){
10634             this.remove();
10635         }
10636         Roo.callback(o.callback, o.scope, [this]);
10637         if(!o.concurrent){
10638             this.fxQueue.shift();
10639             this.nextFx();
10640         }
10641     },
10642
10643         /* @private */
10644     getFxEl : function(){ // support for composite element fx
10645         return Roo.get(this.dom);
10646     },
10647
10648         /* @private */
10649     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10650         animType = animType || 'run';
10651         opt = opt || {};
10652         var anim = Roo.lib.Anim[animType](
10653             this.dom, args,
10654             (opt.duration || defaultDur) || .35,
10655             (opt.easing || defaultEase) || 'easeOut',
10656             function(){
10657                 Roo.callback(cb, this);
10658             },
10659             this
10660         );
10661         opt.anim = anim;
10662         return anim;
10663     }
10664 };
10665
10666 // backwords compat
10667 Roo.Fx.resize = Roo.Fx.scale;
10668
10669 //When included, Roo.Fx is automatically applied to Element so that all basic
10670 //effects are available directly via the Element API
10671 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10672  * Based on:
10673  * Ext JS Library 1.1.1
10674  * Copyright(c) 2006-2007, Ext JS, LLC.
10675  *
10676  * Originally Released Under LGPL - original licence link has changed is not relivant.
10677  *
10678  * Fork - LGPL
10679  * <script type="text/javascript">
10680  */
10681
10682
10683 /**
10684  * @class Roo.CompositeElement
10685  * Standard composite class. Creates a Roo.Element for every element in the collection.
10686  * <br><br>
10687  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10688  * actions will be performed on all the elements in this collection.</b>
10689  * <br><br>
10690  * All methods return <i>this</i> and can be chained.
10691  <pre><code>
10692  var els = Roo.select("#some-el div.some-class", true);
10693  // or select directly from an existing element
10694  var el = Roo.get('some-el');
10695  el.select('div.some-class', true);
10696
10697  els.setWidth(100); // all elements become 100 width
10698  els.hide(true); // all elements fade out and hide
10699  // or
10700  els.setWidth(100).hide(true);
10701  </code></pre>
10702  */
10703 Roo.CompositeElement = function(els){
10704     this.elements = [];
10705     this.addElements(els);
10706 };
10707 Roo.CompositeElement.prototype = {
10708     isComposite: true,
10709     addElements : function(els){
10710         if(!els) return this;
10711         if(typeof els == "string"){
10712             els = Roo.Element.selectorFunction(els);
10713         }
10714         var yels = this.elements;
10715         var index = yels.length-1;
10716         for(var i = 0, len = els.length; i < len; i++) {
10717                 yels[++index] = Roo.get(els[i]);
10718         }
10719         return this;
10720     },
10721
10722     /**
10723     * Clears this composite and adds the elements returned by the passed selector.
10724     * @param {String/Array} els A string CSS selector, an array of elements or an element
10725     * @return {CompositeElement} this
10726     */
10727     fill : function(els){
10728         this.elements = [];
10729         this.add(els);
10730         return this;
10731     },
10732
10733     /**
10734     * Filters this composite to only elements that match the passed selector.
10735     * @param {String} selector A string CSS selector
10736     * @return {CompositeElement} this
10737     */
10738     filter : function(selector){
10739         var els = [];
10740         this.each(function(el){
10741             if(el.is(selector)){
10742                 els[els.length] = el.dom;
10743             }
10744         });
10745         this.fill(els);
10746         return this;
10747     },
10748
10749     invoke : function(fn, args){
10750         var els = this.elements;
10751         for(var i = 0, len = els.length; i < len; i++) {
10752                 Roo.Element.prototype[fn].apply(els[i], args);
10753         }
10754         return this;
10755     },
10756     /**
10757     * Adds elements to this composite.
10758     * @param {String/Array} els A string CSS selector, an array of elements or an element
10759     * @return {CompositeElement} this
10760     */
10761     add : function(els){
10762         if(typeof els == "string"){
10763             this.addElements(Roo.Element.selectorFunction(els));
10764         }else if(els.length !== undefined){
10765             this.addElements(els);
10766         }else{
10767             this.addElements([els]);
10768         }
10769         return this;
10770     },
10771     /**
10772     * Calls the passed function passing (el, this, index) for each element in this composite.
10773     * @param {Function} fn The function to call
10774     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10775     * @return {CompositeElement} this
10776     */
10777     each : function(fn, scope){
10778         var els = this.elements;
10779         for(var i = 0, len = els.length; i < len; i++){
10780             if(fn.call(scope || els[i], els[i], this, i) === false) {
10781                 break;
10782             }
10783         }
10784         return this;
10785     },
10786
10787     /**
10788      * Returns the Element object at the specified index
10789      * @param {Number} index
10790      * @return {Roo.Element}
10791      */
10792     item : function(index){
10793         return this.elements[index] || null;
10794     },
10795
10796     /**
10797      * Returns the first Element
10798      * @return {Roo.Element}
10799      */
10800     first : function(){
10801         return this.item(0);
10802     },
10803
10804     /**
10805      * Returns the last Element
10806      * @return {Roo.Element}
10807      */
10808     last : function(){
10809         return this.item(this.elements.length-1);
10810     },
10811
10812     /**
10813      * Returns the number of elements in this composite
10814      * @return Number
10815      */
10816     getCount : function(){
10817         return this.elements.length;
10818     },
10819
10820     /**
10821      * Returns true if this composite contains the passed element
10822      * @return Boolean
10823      */
10824     contains : function(el){
10825         return this.indexOf(el) !== -1;
10826     },
10827
10828     /**
10829      * Returns true if this composite contains the passed element
10830      * @return Boolean
10831      */
10832     indexOf : function(el){
10833         return this.elements.indexOf(Roo.get(el));
10834     },
10835
10836
10837     /**
10838     * Removes the specified element(s).
10839     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10840     * or an array of any of those.
10841     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10842     * @return {CompositeElement} this
10843     */
10844     removeElement : function(el, removeDom){
10845         if(el instanceof Array){
10846             for(var i = 0, len = el.length; i < len; i++){
10847                 this.removeElement(el[i]);
10848             }
10849             return this;
10850         }
10851         var index = typeof el == 'number' ? el : this.indexOf(el);
10852         if(index !== -1){
10853             if(removeDom){
10854                 var d = this.elements[index];
10855                 if(d.dom){
10856                     d.remove();
10857                 }else{
10858                     d.parentNode.removeChild(d);
10859                 }
10860             }
10861             this.elements.splice(index, 1);
10862         }
10863         return this;
10864     },
10865
10866     /**
10867     * Replaces the specified element with the passed element.
10868     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10869     * to replace.
10870     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10871     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10872     * @return {CompositeElement} this
10873     */
10874     replaceElement : function(el, replacement, domReplace){
10875         var index = typeof el == 'number' ? el : this.indexOf(el);
10876         if(index !== -1){
10877             if(domReplace){
10878                 this.elements[index].replaceWith(replacement);
10879             }else{
10880                 this.elements.splice(index, 1, Roo.get(replacement))
10881             }
10882         }
10883         return this;
10884     },
10885
10886     /**
10887      * Removes all elements.
10888      */
10889     clear : function(){
10890         this.elements = [];
10891     }
10892 };
10893 (function(){
10894     Roo.CompositeElement.createCall = function(proto, fnName){
10895         if(!proto[fnName]){
10896             proto[fnName] = function(){
10897                 return this.invoke(fnName, arguments);
10898             };
10899         }
10900     };
10901     for(var fnName in Roo.Element.prototype){
10902         if(typeof Roo.Element.prototype[fnName] == "function"){
10903             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10904         }
10905     };
10906 })();
10907 /*
10908  * Based on:
10909  * Ext JS Library 1.1.1
10910  * Copyright(c) 2006-2007, Ext JS, LLC.
10911  *
10912  * Originally Released Under LGPL - original licence link has changed is not relivant.
10913  *
10914  * Fork - LGPL
10915  * <script type="text/javascript">
10916  */
10917
10918 /**
10919  * @class Roo.CompositeElementLite
10920  * @extends Roo.CompositeElement
10921  * Flyweight composite class. Reuses the same Roo.Element for element operations.
10922  <pre><code>
10923  var els = Roo.select("#some-el div.some-class");
10924  // or select directly from an existing element
10925  var el = Roo.get('some-el');
10926  el.select('div.some-class');
10927
10928  els.setWidth(100); // all elements become 100 width
10929  els.hide(true); // all elements fade out and hide
10930  // or
10931  els.setWidth(100).hide(true);
10932  </code></pre><br><br>
10933  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10934  * actions will be performed on all the elements in this collection.</b>
10935  */
10936 Roo.CompositeElementLite = function(els){
10937     Roo.CompositeElementLite.superclass.constructor.call(this, els);
10938     this.el = new Roo.Element.Flyweight();
10939 };
10940 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10941     addElements : function(els){
10942         if(els){
10943             if(els instanceof Array){
10944                 this.elements = this.elements.concat(els);
10945             }else{
10946                 var yels = this.elements;
10947                 var index = yels.length-1;
10948                 for(var i = 0, len = els.length; i < len; i++) {
10949                     yels[++index] = els[i];
10950                 }
10951             }
10952         }
10953         return this;
10954     },
10955     invoke : function(fn, args){
10956         var els = this.elements;
10957         var el = this.el;
10958         for(var i = 0, len = els.length; i < len; i++) {
10959             el.dom = els[i];
10960                 Roo.Element.prototype[fn].apply(el, args);
10961         }
10962         return this;
10963     },
10964     /**
10965      * Returns a flyweight Element of the dom element object at the specified index
10966      * @param {Number} index
10967      * @return {Roo.Element}
10968      */
10969     item : function(index){
10970         if(!this.elements[index]){
10971             return null;
10972         }
10973         this.el.dom = this.elements[index];
10974         return this.el;
10975     },
10976
10977     // fixes scope with flyweight
10978     addListener : function(eventName, handler, scope, opt){
10979         var els = this.elements;
10980         for(var i = 0, len = els.length; i < len; i++) {
10981             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10982         }
10983         return this;
10984     },
10985
10986     /**
10987     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10988     * passed is the flyweight (shared) Roo.Element instance, so if you require a
10989     * a reference to the dom node, use el.dom.</b>
10990     * @param {Function} fn The function to call
10991     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10992     * @return {CompositeElement} this
10993     */
10994     each : function(fn, scope){
10995         var els = this.elements;
10996         var el = this.el;
10997         for(var i = 0, len = els.length; i < len; i++){
10998             el.dom = els[i];
10999                 if(fn.call(scope || el, el, this, i) === false){
11000                 break;
11001             }
11002         }
11003         return this;
11004     },
11005
11006     indexOf : function(el){
11007         return this.elements.indexOf(Roo.getDom(el));
11008     },
11009
11010     replaceElement : function(el, replacement, domReplace){
11011         var index = typeof el == 'number' ? el : this.indexOf(el);
11012         if(index !== -1){
11013             replacement = Roo.getDom(replacement);
11014             if(domReplace){
11015                 var d = this.elements[index];
11016                 d.parentNode.insertBefore(replacement, d);
11017                 d.parentNode.removeChild(d);
11018             }
11019             this.elements.splice(index, 1, replacement);
11020         }
11021         return this;
11022     }
11023 });
11024 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11025
11026 /*
11027  * Based on:
11028  * Ext JS Library 1.1.1
11029  * Copyright(c) 2006-2007, Ext JS, LLC.
11030  *
11031  * Originally Released Under LGPL - original licence link has changed is not relivant.
11032  *
11033  * Fork - LGPL
11034  * <script type="text/javascript">
11035  */
11036
11037  
11038
11039 /**
11040  * @class Roo.data.Connection
11041  * @extends Roo.util.Observable
11042  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11043  * either to a configured URL, or to a URL specified at request time.<br><br>
11044  * <p>
11045  * Requests made by this class are asynchronous, and will return immediately. No data from
11046  * the server will be available to the statement immediately following the {@link #request} call.
11047  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11048  * <p>
11049  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11050  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11051  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11052  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11053  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11054  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11055  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11056  * standard DOM methods.
11057  * @constructor
11058  * @param {Object} config a configuration object.
11059  */
11060 Roo.data.Connection = function(config){
11061     Roo.apply(this, config);
11062     this.addEvents({
11063         /**
11064          * @event beforerequest
11065          * Fires before a network request is made to retrieve a data object.
11066          * @param {Connection} conn This Connection object.
11067          * @param {Object} options The options config object passed to the {@link #request} method.
11068          */
11069         "beforerequest" : true,
11070         /**
11071          * @event requestcomplete
11072          * Fires if the request was successfully completed.
11073          * @param {Connection} conn This Connection object.
11074          * @param {Object} response The XHR object containing the response data.
11075          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11076          * @param {Object} options The options config object passed to the {@link #request} method.
11077          */
11078         "requestcomplete" : true,
11079         /**
11080          * @event requestexception
11081          * Fires if an error HTTP status was returned from the server.
11082          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11083          * @param {Connection} conn This Connection object.
11084          * @param {Object} response The XHR object containing the response data.
11085          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11086          * @param {Object} options The options config object passed to the {@link #request} method.
11087          */
11088         "requestexception" : true
11089     });
11090     Roo.data.Connection.superclass.constructor.call(this);
11091 };
11092
11093 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11094     /**
11095      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11096      */
11097     /**
11098      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11099      * extra parameters to each request made by this object. (defaults to undefined)
11100      */
11101     /**
11102      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11103      *  to each request made by this object. (defaults to undefined)
11104      */
11105     /**
11106      * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11107      */
11108     /**
11109      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11110      */
11111     timeout : 30000,
11112     /**
11113      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11114      * @type Boolean
11115      */
11116     autoAbort:false,
11117
11118     /**
11119      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11120      * @type Boolean
11121      */
11122     disableCaching: true,
11123
11124     /**
11125      * Sends an HTTP request to a remote server.
11126      * @param {Object} options An object which may contain the following properties:<ul>
11127      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11128      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11129      * request, a url encoded string or a function to call to get either.</li>
11130      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11131      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11132      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11133      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11134      * <li>options {Object} The parameter to the request call.</li>
11135      * <li>success {Boolean} True if the request succeeded.</li>
11136      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11137      * </ul></li>
11138      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11139      * The callback is passed the following parameters:<ul>
11140      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11141      * <li>options {Object} The parameter to the request call.</li>
11142      * </ul></li>
11143      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11144      * The callback is passed the following parameters:<ul>
11145      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11146      * <li>options {Object} The parameter to the request call.</li>
11147      * </ul></li>
11148      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11149      * for the callback function. Defaults to the browser window.</li>
11150      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11151      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11152      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11153      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11154      * params for the post data. Any params will be appended to the URL.</li>
11155      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11156      * </ul>
11157      * @return {Number} transactionId
11158      */
11159     request : function(o){
11160         if(this.fireEvent("beforerequest", this, o) !== false){
11161             var p = o.params;
11162
11163             if(typeof p == "function"){
11164                 p = p.call(o.scope||window, o);
11165             }
11166             if(typeof p == "object"){
11167                 p = Roo.urlEncode(o.params);
11168             }
11169             if(this.extraParams){
11170                 var extras = Roo.urlEncode(this.extraParams);
11171                 p = p ? (p + '&' + extras) : extras;
11172             }
11173
11174             var url = o.url || this.url;
11175             if(typeof url == 'function'){
11176                 url = url.call(o.scope||window, o);
11177             }
11178
11179             if(o.form){
11180                 var form = Roo.getDom(o.form);
11181                 url = url || form.action;
11182
11183                 var enctype = form.getAttribute("enctype");
11184                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11185                     return this.doFormUpload(o, p, url);
11186                 }
11187                 var f = Roo.lib.Ajax.serializeForm(form);
11188                 p = p ? (p + '&' + f) : f;
11189             }
11190
11191             var hs = o.headers;
11192             if(this.defaultHeaders){
11193                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11194                 if(!o.headers){
11195                     o.headers = hs;
11196                 }
11197             }
11198
11199             var cb = {
11200                 success: this.handleResponse,
11201                 failure: this.handleFailure,
11202                 scope: this,
11203                 argument: {options: o},
11204                 timeout : this.timeout
11205             };
11206
11207             var method = o.method||this.method||(p ? "POST" : "GET");
11208
11209             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11210                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11211             }
11212
11213             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11214                 if(o.autoAbort){
11215                     this.abort();
11216                 }
11217             }else if(this.autoAbort !== false){
11218                 this.abort();
11219             }
11220
11221             if((method == 'GET' && p) || o.xmlData){
11222                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11223                 p = '';
11224             }
11225             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11226             return this.transId;
11227         }else{
11228             Roo.callback(o.callback, o.scope, [o, null, null]);
11229             return null;
11230         }
11231     },
11232
11233     /**
11234      * Determine whether this object has a request outstanding.
11235      * @param {Number} transactionId (Optional) defaults to the last transaction
11236      * @return {Boolean} True if there is an outstanding request.
11237      */
11238     isLoading : function(transId){
11239         if(transId){
11240             return Roo.lib.Ajax.isCallInProgress(transId);
11241         }else{
11242             return this.transId ? true : false;
11243         }
11244     },
11245
11246     /**
11247      * Aborts any outstanding request.
11248      * @param {Number} transactionId (Optional) defaults to the last transaction
11249      */
11250     abort : function(transId){
11251         if(transId || this.isLoading()){
11252             Roo.lib.Ajax.abort(transId || this.transId);
11253         }
11254     },
11255
11256     // private
11257     handleResponse : function(response){
11258         this.transId = false;
11259         var options = response.argument.options;
11260         response.argument = options ? options.argument : null;
11261         this.fireEvent("requestcomplete", this, response, options);
11262         Roo.callback(options.success, options.scope, [response, options]);
11263         Roo.callback(options.callback, options.scope, [options, true, response]);
11264     },
11265
11266     // private
11267     handleFailure : function(response, e){
11268         this.transId = false;
11269         var options = response.argument.options;
11270         response.argument = options ? options.argument : null;
11271         this.fireEvent("requestexception", this, response, options, e);
11272         Roo.callback(options.failure, options.scope, [response, options]);
11273         Roo.callback(options.callback, options.scope, [options, false, response]);
11274     },
11275
11276     // private
11277     doFormUpload : function(o, ps, url){
11278         var id = Roo.id();
11279         var frame = document.createElement('iframe');
11280         frame.id = id;
11281         frame.name = id;
11282         frame.className = 'x-hidden';
11283         if(Roo.isIE){
11284             frame.src = Roo.SSL_SECURE_URL;
11285         }
11286         document.body.appendChild(frame);
11287
11288         if(Roo.isIE){
11289            document.frames[id].name = id;
11290         }
11291
11292         var form = Roo.getDom(o.form);
11293         form.target = id;
11294         form.method = 'POST';
11295         form.enctype = form.encoding = 'multipart/form-data';
11296         if(url){
11297             form.action = url;
11298         }
11299
11300         var hiddens, hd;
11301         if(ps){ // add dynamic params
11302             hiddens = [];
11303             ps = Roo.urlDecode(ps, false);
11304             for(var k in ps){
11305                 if(ps.hasOwnProperty(k)){
11306                     hd = document.createElement('input');
11307                     hd.type = 'hidden';
11308                     hd.name = k;
11309                     hd.value = ps[k];
11310                     form.appendChild(hd);
11311                     hiddens.push(hd);
11312                 }
11313             }
11314         }
11315
11316         function cb(){
11317             var r = {  // bogus response object
11318                 responseText : '',
11319                 responseXML : null
11320             };
11321
11322             r.argument = o ? o.argument : null;
11323
11324             try { //
11325                 var doc;
11326                 if(Roo.isIE){
11327                     doc = frame.contentWindow.document;
11328                 }else {
11329                     doc = (frame.contentDocument || window.frames[id].document);
11330                 }
11331                 if(doc && doc.body){
11332                     r.responseText = doc.body.innerHTML;
11333                 }
11334                 if(doc && doc.XMLDocument){
11335                     r.responseXML = doc.XMLDocument;
11336                 }else {
11337                     r.responseXML = doc;
11338                 }
11339             }
11340             catch(e) {
11341                 // ignore
11342             }
11343
11344             Roo.EventManager.removeListener(frame, 'load', cb, this);
11345
11346             this.fireEvent("requestcomplete", this, r, o);
11347             Roo.callback(o.success, o.scope, [r, o]);
11348             Roo.callback(o.callback, o.scope, [o, true, r]);
11349
11350             setTimeout(function(){document.body.removeChild(frame);}, 100);
11351         }
11352
11353         Roo.EventManager.on(frame, 'load', cb, this);
11354         form.submit();
11355
11356         if(hiddens){ // remove dynamic params
11357             for(var i = 0, len = hiddens.length; i < len; i++){
11358                 form.removeChild(hiddens[i]);
11359             }
11360         }
11361     }
11362 });
11363
11364 /**
11365  * @class Roo.Ajax
11366  * @extends Roo.data.Connection
11367  * Global Ajax request class.
11368  *
11369  * @singleton
11370  */
11371 Roo.Ajax = new Roo.data.Connection({
11372     // fix up the docs
11373    /**
11374      * @cfg {String} url @hide
11375      */
11376     /**
11377      * @cfg {Object} extraParams @hide
11378      */
11379     /**
11380      * @cfg {Object} defaultHeaders @hide
11381      */
11382     /**
11383      * @cfg {String} method (Optional) @hide
11384      */
11385     /**
11386      * @cfg {Number} timeout (Optional) @hide
11387      */
11388     /**
11389      * @cfg {Boolean} autoAbort (Optional) @hide
11390      */
11391
11392     /**
11393      * @cfg {Boolean} disableCaching (Optional) @hide
11394      */
11395
11396     /**
11397      * @property  disableCaching
11398      * True to add a unique cache-buster param to GET requests. (defaults to true)
11399      * @type Boolean
11400      */
11401     /**
11402      * @property  url
11403      * The default URL to be used for requests to the server. (defaults to undefined)
11404      * @type String
11405      */
11406     /**
11407      * @property  extraParams
11408      * An object containing properties which are used as
11409      * extra parameters to each request made by this object. (defaults to undefined)
11410      * @type Object
11411      */
11412     /**
11413      * @property  defaultHeaders
11414      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11415      * @type Object
11416      */
11417     /**
11418      * @property  method
11419      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11420      * @type String
11421      */
11422     /**
11423      * @property  timeout
11424      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11425      * @type Number
11426      */
11427
11428     /**
11429      * @property  autoAbort
11430      * Whether a new request should abort any pending requests. (defaults to false)
11431      * @type Boolean
11432      */
11433     autoAbort : false,
11434
11435     /**
11436      * Serialize the passed form into a url encoded string
11437      * @param {String/HTMLElement} form
11438      * @return {String}
11439      */
11440     serializeForm : function(form){
11441         return Roo.lib.Ajax.serializeForm(form);
11442     }
11443 });/*
11444  * Based on:
11445  * Ext JS Library 1.1.1
11446  * Copyright(c) 2006-2007, Ext JS, LLC.
11447  *
11448  * Originally Released Under LGPL - original licence link has changed is not relivant.
11449  *
11450  * Fork - LGPL
11451  * <script type="text/javascript">
11452  */
11453  
11454 /**
11455  * @class Roo.Ajax
11456  * @extends Roo.data.Connection
11457  * Global Ajax request class.
11458  *
11459  * @instanceOf  Roo.data.Connection
11460  */
11461 Roo.Ajax = new Roo.data.Connection({
11462     // fix up the docs
11463     
11464     /**
11465      * fix up scoping
11466      * @scope Roo.Ajax
11467      */
11468     
11469    /**
11470      * @cfg {String} url @hide
11471      */
11472     /**
11473      * @cfg {Object} extraParams @hide
11474      */
11475     /**
11476      * @cfg {Object} defaultHeaders @hide
11477      */
11478     /**
11479      * @cfg {String} method (Optional) @hide
11480      */
11481     /**
11482      * @cfg {Number} timeout (Optional) @hide
11483      */
11484     /**
11485      * @cfg {Boolean} autoAbort (Optional) @hide
11486      */
11487
11488     /**
11489      * @cfg {Boolean} disableCaching (Optional) @hide
11490      */
11491
11492     /**
11493      * @property  disableCaching
11494      * True to add a unique cache-buster param to GET requests. (defaults to true)
11495      * @type Boolean
11496      */
11497     /**
11498      * @property  url
11499      * The default URL to be used for requests to the server. (defaults to undefined)
11500      * @type String
11501      */
11502     /**
11503      * @property  extraParams
11504      * An object containing properties which are used as
11505      * extra parameters to each request made by this object. (defaults to undefined)
11506      * @type Object
11507      */
11508     /**
11509      * @property  defaultHeaders
11510      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11511      * @type Object
11512      */
11513     /**
11514      * @property  method
11515      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11516      * @type String
11517      */
11518     /**
11519      * @property  timeout
11520      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11521      * @type Number
11522      */
11523
11524     /**
11525      * @property  autoAbort
11526      * Whether a new request should abort any pending requests. (defaults to false)
11527      * @type Boolean
11528      */
11529     autoAbort : false,
11530
11531     /**
11532      * Serialize the passed form into a url encoded string
11533      * @param {String/HTMLElement} form
11534      * @return {String}
11535      */
11536     serializeForm : function(form){
11537         return Roo.lib.Ajax.serializeForm(form);
11538     }
11539 });/*
11540  * Based on:
11541  * Ext JS Library 1.1.1
11542  * Copyright(c) 2006-2007, Ext JS, LLC.
11543  *
11544  * Originally Released Under LGPL - original licence link has changed is not relivant.
11545  *
11546  * Fork - LGPL
11547  * <script type="text/javascript">
11548  */
11549
11550  
11551 /**
11552  * @class Roo.UpdateManager
11553  * @extends Roo.util.Observable
11554  * Provides AJAX-style update for Element object.<br><br>
11555  * Usage:<br>
11556  * <pre><code>
11557  * // Get it from a Roo.Element object
11558  * var el = Roo.get("foo");
11559  * var mgr = el.getUpdateManager();
11560  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11561  * ...
11562  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11563  * <br>
11564  * // or directly (returns the same UpdateManager instance)
11565  * var mgr = new Roo.UpdateManager("myElementId");
11566  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11567  * mgr.on("update", myFcnNeedsToKnow);
11568  * <br>
11569    // short handed call directly from the element object
11570    Roo.get("foo").load({
11571         url: "bar.php",
11572         scripts:true,
11573         params: "for=bar",
11574         text: "Loading Foo..."
11575    });
11576  * </code></pre>
11577  * @constructor
11578  * Create new UpdateManager directly.
11579  * @param {String/HTMLElement/Roo.Element} el The element to update
11580  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11581  */
11582 Roo.UpdateManager = function(el, forceNew){
11583     el = Roo.get(el);
11584     if(!forceNew && el.updateManager){
11585         return el.updateManager;
11586     }
11587     /**
11588      * The Element object
11589      * @type Roo.Element
11590      */
11591     this.el = el;
11592     /**
11593      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11594      * @type String
11595      */
11596     this.defaultUrl = null;
11597
11598     this.addEvents({
11599         /**
11600          * @event beforeupdate
11601          * Fired before an update is made, return false from your handler and the update is cancelled.
11602          * @param {Roo.Element} el
11603          * @param {String/Object/Function} url
11604          * @param {String/Object} params
11605          */
11606         "beforeupdate": true,
11607         /**
11608          * @event update
11609          * Fired after successful update is made.
11610          * @param {Roo.Element} el
11611          * @param {Object} oResponseObject The response Object
11612          */
11613         "update": true,
11614         /**
11615          * @event failure
11616          * Fired on update failure.
11617          * @param {Roo.Element} el
11618          * @param {Object} oResponseObject The response Object
11619          */
11620         "failure": true
11621     });
11622     var d = Roo.UpdateManager.defaults;
11623     /**
11624      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11625      * @type String
11626      */
11627     this.sslBlankUrl = d.sslBlankUrl;
11628     /**
11629      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11630      * @type Boolean
11631      */
11632     this.disableCaching = d.disableCaching;
11633     /**
11634      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11635      * @type String
11636      */
11637     this.indicatorText = d.indicatorText;
11638     /**
11639      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11640      * @type String
11641      */
11642     this.showLoadIndicator = d.showLoadIndicator;
11643     /**
11644      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11645      * @type Number
11646      */
11647     this.timeout = d.timeout;
11648
11649     /**
11650      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11651      * @type Boolean
11652      */
11653     this.loadScripts = d.loadScripts;
11654
11655     /**
11656      * Transaction object of current executing transaction
11657      */
11658     this.transaction = null;
11659
11660     /**
11661      * @private
11662      */
11663     this.autoRefreshProcId = null;
11664     /**
11665      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11666      * @type Function
11667      */
11668     this.refreshDelegate = this.refresh.createDelegate(this);
11669     /**
11670      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11671      * @type Function
11672      */
11673     this.updateDelegate = this.update.createDelegate(this);
11674     /**
11675      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11676      * @type Function
11677      */
11678     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11679     /**
11680      * @private
11681      */
11682     this.successDelegate = this.processSuccess.createDelegate(this);
11683     /**
11684      * @private
11685      */
11686     this.failureDelegate = this.processFailure.createDelegate(this);
11687
11688     if(!this.renderer){
11689      /**
11690       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11691       */
11692     this.renderer = new Roo.UpdateManager.BasicRenderer();
11693     }
11694     
11695     Roo.UpdateManager.superclass.constructor.call(this);
11696 };
11697
11698 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11699     /**
11700      * Get the Element this UpdateManager is bound to
11701      * @return {Roo.Element} The element
11702      */
11703     getEl : function(){
11704         return this.el;
11705     },
11706     /**
11707      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11708      * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11709 <pre><code>
11710 um.update({<br/>
11711     url: "your-url.php",<br/>
11712     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11713     callback: yourFunction,<br/>
11714     scope: yourObject, //(optional scope)  <br/>
11715     discardUrl: false, <br/>
11716     nocache: false,<br/>
11717     text: "Loading...",<br/>
11718     timeout: 30,<br/>
11719     scripts: false<br/>
11720 });
11721 </code></pre>
11722      * The only required property is url. The optional properties nocache, text and scripts
11723      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11724      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
11725      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11726      * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11727      */
11728     update : function(url, params, callback, discardUrl){
11729         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11730             var method = this.method, cfg;
11731             if(typeof url == "object"){ // must be config object
11732                 cfg = url;
11733                 url = cfg.url;
11734                 params = params || cfg.params;
11735                 callback = callback || cfg.callback;
11736                 discardUrl = discardUrl || cfg.discardUrl;
11737                 if(callback && cfg.scope){
11738                     callback = callback.createDelegate(cfg.scope);
11739                 }
11740                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11741                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11742                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11743                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11744                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11745             }
11746             this.showLoading();
11747             if(!discardUrl){
11748                 this.defaultUrl = url;
11749             }
11750             if(typeof url == "function"){
11751                 url = url.call(this);
11752             }
11753
11754             method = method || (params ? "POST" : "GET");
11755             if(method == "GET"){
11756                 url = this.prepareUrl(url);
11757             }
11758
11759             var o = Roo.apply(cfg ||{}, {
11760                 url : url,
11761                 params: params,
11762                 success: this.successDelegate,
11763                 failure: this.failureDelegate,
11764                 callback: undefined,
11765                 timeout: (this.timeout*1000),
11766                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11767             });
11768
11769             this.transaction = Roo.Ajax.request(o);
11770         }
11771     },
11772
11773     /**
11774      * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11775      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11776      * @param {String/HTMLElement} form The form Id or form element
11777      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11778      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11779      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11780      */
11781     formUpdate : function(form, url, reset, callback){
11782         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11783             if(typeof url == "function"){
11784                 url = url.call(this);
11785             }
11786             form = Roo.getDom(form);
11787             this.transaction = Roo.Ajax.request({
11788                 form: form,
11789                 url:url,
11790                 success: this.successDelegate,
11791                 failure: this.failureDelegate,
11792                 timeout: (this.timeout*1000),
11793                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11794             });
11795             this.showLoading.defer(1, this);
11796         }
11797     },
11798
11799     /**
11800      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11801      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11802      */
11803     refresh : function(callback){
11804         if(this.defaultUrl == null){
11805             return;
11806         }
11807         this.update(this.defaultUrl, null, callback, true);
11808     },
11809
11810     /**
11811      * Set this element to auto refresh.
11812      * @param {Number} interval How often to update (in seconds).
11813      * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11814      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
11815      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11816      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11817      */
11818     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11819         if(refreshNow){
11820             this.update(url || this.defaultUrl, params, callback, true);
11821         }
11822         if(this.autoRefreshProcId){
11823             clearInterval(this.autoRefreshProcId);
11824         }
11825         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11826     },
11827
11828     /**
11829      * Stop auto refresh on this element.
11830      */
11831      stopAutoRefresh : function(){
11832         if(this.autoRefreshProcId){
11833             clearInterval(this.autoRefreshProcId);
11834             delete this.autoRefreshProcId;
11835         }
11836     },
11837
11838     isAutoRefreshing : function(){
11839        return this.autoRefreshProcId ? true : false;
11840     },
11841     /**
11842      * Called to update the element to "Loading" state. Override to perform custom action.
11843      */
11844     showLoading : function(){
11845         if(this.showLoadIndicator){
11846             this.el.update(this.indicatorText);
11847         }
11848     },
11849
11850     /**
11851      * Adds unique parameter to query string if disableCaching = true
11852      * @private
11853      */
11854     prepareUrl : function(url){
11855         if(this.disableCaching){
11856             var append = "_dc=" + (new Date().getTime());
11857             if(url.indexOf("?") !== -1){
11858                 url += "&" + append;
11859             }else{
11860                 url += "?" + append;
11861             }
11862         }
11863         return url;
11864     },
11865
11866     /**
11867      * @private
11868      */
11869     processSuccess : function(response){
11870         this.transaction = null;
11871         if(response.argument.form && response.argument.reset){
11872             try{ // put in try/catch since some older FF releases had problems with this
11873                 response.argument.form.reset();
11874             }catch(e){}
11875         }
11876         if(this.loadScripts){
11877             this.renderer.render(this.el, response, this,
11878                 this.updateComplete.createDelegate(this, [response]));
11879         }else{
11880             this.renderer.render(this.el, response, this);
11881             this.updateComplete(response);
11882         }
11883     },
11884
11885     updateComplete : function(response){
11886         this.fireEvent("update", this.el, response);
11887         if(typeof response.argument.callback == "function"){
11888             response.argument.callback(this.el, true, response);
11889         }
11890     },
11891
11892     /**
11893      * @private
11894      */
11895     processFailure : function(response){
11896         this.transaction = null;
11897         this.fireEvent("failure", this.el, response);
11898         if(typeof response.argument.callback == "function"){
11899             response.argument.callback(this.el, false, response);
11900         }
11901     },
11902
11903     /**
11904      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11905      * @param {Object} renderer The object implementing the render() method
11906      */
11907     setRenderer : function(renderer){
11908         this.renderer = renderer;
11909     },
11910
11911     getRenderer : function(){
11912        return this.renderer;
11913     },
11914
11915     /**
11916      * Set the defaultUrl used for updates
11917      * @param {String/Function} defaultUrl The url or a function to call to get the url
11918      */
11919     setDefaultUrl : function(defaultUrl){
11920         this.defaultUrl = defaultUrl;
11921     },
11922
11923     /**
11924      * Aborts the executing transaction
11925      */
11926     abort : function(){
11927         if(this.transaction){
11928             Roo.Ajax.abort(this.transaction);
11929         }
11930     },
11931
11932     /**
11933      * Returns true if an update is in progress
11934      * @return {Boolean}
11935      */
11936     isUpdating : function(){
11937         if(this.transaction){
11938             return Roo.Ajax.isLoading(this.transaction);
11939         }
11940         return false;
11941     }
11942 });
11943
11944 /**
11945  * @class Roo.UpdateManager.defaults
11946  * @static (not really - but it helps the doc tool)
11947  * The defaults collection enables customizing the default properties of UpdateManager
11948  */
11949    Roo.UpdateManager.defaults = {
11950        /**
11951          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11952          * @type Number
11953          */
11954          timeout : 30,
11955
11956          /**
11957          * True to process scripts by default (Defaults to false).
11958          * @type Boolean
11959          */
11960         loadScripts : false,
11961
11962         /**
11963         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11964         * @type String
11965         */
11966         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11967         /**
11968          * Whether to append unique parameter on get request to disable caching (Defaults to false).
11969          * @type Boolean
11970          */
11971         disableCaching : false,
11972         /**
11973          * Whether to show indicatorText when loading (Defaults to true).
11974          * @type Boolean
11975          */
11976         showLoadIndicator : true,
11977         /**
11978          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11979          * @type String
11980          */
11981         indicatorText : '<div class="loading-indicator">Loading...</div>'
11982    };
11983
11984 /**
11985  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11986  *Usage:
11987  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11988  * @param {String/HTMLElement/Roo.Element} el The element to update
11989  * @param {String} url The url
11990  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11991  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11992  * @static
11993  * @deprecated
11994  * @member Roo.UpdateManager
11995  */
11996 Roo.UpdateManager.updateElement = function(el, url, params, options){
11997     var um = Roo.get(el, true).getUpdateManager();
11998     Roo.apply(um, options);
11999     um.update(url, params, options ? options.callback : null);
12000 };
12001 // alias for backwards compat
12002 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12003 /**
12004  * @class Roo.UpdateManager.BasicRenderer
12005  * Default Content renderer. Updates the elements innerHTML with the responseText.
12006  */
12007 Roo.UpdateManager.BasicRenderer = function(){};
12008
12009 Roo.UpdateManager.BasicRenderer.prototype = {
12010     /**
12011      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12012      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12013      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12014      * @param {Roo.Element} el The element being rendered
12015      * @param {Object} response The YUI Connect response object
12016      * @param {UpdateManager} updateManager The calling update manager
12017      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12018      */
12019      render : function(el, response, updateManager, callback){
12020         el.update(response.responseText, updateManager.loadScripts, callback);
12021     }
12022 };
12023 /*
12024  * Based on:
12025  * Ext JS Library 1.1.1
12026  * Copyright(c) 2006-2007, Ext JS, LLC.
12027  *
12028  * Originally Released Under LGPL - original licence link has changed is not relivant.
12029  *
12030  * Fork - LGPL
12031  * <script type="text/javascript">
12032  */
12033
12034 /**
12035  * @class Roo.util.DelayedTask
12036  * Provides a convenient method of performing setTimeout where a new
12037  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12038  * You can use this class to buffer
12039  * the keypress events for a certain number of milliseconds, and perform only if they stop
12040  * for that amount of time.
12041  * @constructor The parameters to this constructor serve as defaults and are not required.
12042  * @param {Function} fn (optional) The default function to timeout
12043  * @param {Object} scope (optional) The default scope of that timeout
12044  * @param {Array} args (optional) The default Array of arguments
12045  */
12046 Roo.util.DelayedTask = function(fn, scope, args){
12047     var id = null, d, t;
12048
12049     var call = function(){
12050         var now = new Date().getTime();
12051         if(now - t >= d){
12052             clearInterval(id);
12053             id = null;
12054             fn.apply(scope, args || []);
12055         }
12056     };
12057     /**
12058      * Cancels any pending timeout and queues a new one
12059      * @param {Number} delay The milliseconds to delay
12060      * @param {Function} newFn (optional) Overrides function passed to constructor
12061      * @param {Object} newScope (optional) Overrides scope passed to constructor
12062      * @param {Array} newArgs (optional) Overrides args passed to constructor
12063      */
12064     this.delay = function(delay, newFn, newScope, newArgs){
12065         if(id && delay != d){
12066             this.cancel();
12067         }
12068         d = delay;
12069         t = new Date().getTime();
12070         fn = newFn || fn;
12071         scope = newScope || scope;
12072         args = newArgs || args;
12073         if(!id){
12074             id = setInterval(call, d);
12075         }
12076     };
12077
12078     /**
12079      * Cancel the last queued timeout
12080      */
12081     this.cancel = function(){
12082         if(id){
12083             clearInterval(id);
12084             id = null;
12085         }
12086     };
12087 };/*
12088  * Based on:
12089  * Ext JS Library 1.1.1
12090  * Copyright(c) 2006-2007, Ext JS, LLC.
12091  *
12092  * Originally Released Under LGPL - original licence link has changed is not relivant.
12093  *
12094  * Fork - LGPL
12095  * <script type="text/javascript">
12096  */
12097  
12098  
12099 Roo.util.TaskRunner = function(interval){
12100     interval = interval || 10;
12101     var tasks = [], removeQueue = [];
12102     var id = 0;
12103     var running = false;
12104
12105     var stopThread = function(){
12106         running = false;
12107         clearInterval(id);
12108         id = 0;
12109     };
12110
12111     var startThread = function(){
12112         if(!running){
12113             running = true;
12114             id = setInterval(runTasks, interval);
12115         }
12116     };
12117
12118     var removeTask = function(task){
12119         removeQueue.push(task);
12120         if(task.onStop){
12121             task.onStop();
12122         }
12123     };
12124
12125     var runTasks = function(){
12126         if(removeQueue.length > 0){
12127             for(var i = 0, len = removeQueue.length; i < len; i++){
12128                 tasks.remove(removeQueue[i]);
12129             }
12130             removeQueue = [];
12131             if(tasks.length < 1){
12132                 stopThread();
12133                 return;
12134             }
12135         }
12136         var now = new Date().getTime();
12137         for(var i = 0, len = tasks.length; i < len; ++i){
12138             var t = tasks[i];
12139             var itime = now - t.taskRunTime;
12140             if(t.interval <= itime){
12141                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12142                 t.taskRunTime = now;
12143                 if(rt === false || t.taskRunCount === t.repeat){
12144                     removeTask(t);
12145                     return;
12146                 }
12147             }
12148             if(t.duration && t.duration <= (now - t.taskStartTime)){
12149                 removeTask(t);
12150             }
12151         }
12152     };
12153
12154     /**
12155      * Queues a new task.
12156      * @param {Object} task
12157      */
12158     this.start = function(task){
12159         tasks.push(task);
12160         task.taskStartTime = new Date().getTime();
12161         task.taskRunTime = 0;
12162         task.taskRunCount = 0;
12163         startThread();
12164         return task;
12165     };
12166
12167     this.stop = function(task){
12168         removeTask(task);
12169         return task;
12170     };
12171
12172     this.stopAll = function(){
12173         stopThread();
12174         for(var i = 0, len = tasks.length; i < len; i++){
12175             if(tasks[i].onStop){
12176                 tasks[i].onStop();
12177             }
12178         }
12179         tasks = [];
12180         removeQueue = [];
12181     };
12182 };
12183
12184 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12185  * Based on:
12186  * Ext JS Library 1.1.1
12187  * Copyright(c) 2006-2007, Ext JS, LLC.
12188  *
12189  * Originally Released Under LGPL - original licence link has changed is not relivant.
12190  *
12191  * Fork - LGPL
12192  * <script type="text/javascript">
12193  */
12194
12195  
12196 /**
12197  * @class Roo.util.MixedCollection
12198  * @extends Roo.util.Observable
12199  * A Collection class that maintains both numeric indexes and keys and exposes events.
12200  * @constructor
12201  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12202  * collection (defaults to false)
12203  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12204  * and return the key value for that item.  This is used when available to look up the key on items that
12205  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12206  * equivalent to providing an implementation for the {@link #getKey} method.
12207  */
12208 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12209     this.items = [];
12210     this.map = {};
12211     this.keys = [];
12212     this.length = 0;
12213     this.addEvents({
12214         /**
12215          * @event clear
12216          * Fires when the collection is cleared.
12217          */
12218         "clear" : true,
12219         /**
12220          * @event add
12221          * Fires when an item is added to the collection.
12222          * @param {Number} index The index at which the item was added.
12223          * @param {Object} o The item added.
12224          * @param {String} key The key associated with the added item.
12225          */
12226         "add" : true,
12227         /**
12228          * @event replace
12229          * Fires when an item is replaced in the collection.
12230          * @param {String} key he key associated with the new added.
12231          * @param {Object} old The item being replaced.
12232          * @param {Object} new The new item.
12233          */
12234         "replace" : true,
12235         /**
12236          * @event remove
12237          * Fires when an item is removed from the collection.
12238          * @param {Object} o The item being removed.
12239          * @param {String} key (optional) The key associated with the removed item.
12240          */
12241         "remove" : true,
12242         "sort" : true
12243     });
12244     this.allowFunctions = allowFunctions === true;
12245     if(keyFn){
12246         this.getKey = keyFn;
12247     }
12248     Roo.util.MixedCollection.superclass.constructor.call(this);
12249 };
12250
12251 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12252     allowFunctions : false,
12253     
12254 /**
12255  * Adds an item to the collection.
12256  * @param {String} key The key to associate with the item
12257  * @param {Object} o The item to add.
12258  * @return {Object} The item added.
12259  */
12260     add : function(key, o){
12261         if(arguments.length == 1){
12262             o = arguments[0];
12263             key = this.getKey(o);
12264         }
12265         if(typeof key == "undefined" || key === null){
12266             this.length++;
12267             this.items.push(o);
12268             this.keys.push(null);
12269         }else{
12270             var old = this.map[key];
12271             if(old){
12272                 return this.replace(key, o);
12273             }
12274             this.length++;
12275             this.items.push(o);
12276             this.map[key] = o;
12277             this.keys.push(key);
12278         }
12279         this.fireEvent("add", this.length-1, o, key);
12280         return o;
12281     },
12282        
12283 /**
12284   * MixedCollection has a generic way to fetch keys if you implement getKey.
12285 <pre><code>
12286 // normal way
12287 var mc = new Roo.util.MixedCollection();
12288 mc.add(someEl.dom.id, someEl);
12289 mc.add(otherEl.dom.id, otherEl);
12290 //and so on
12291
12292 // using getKey
12293 var mc = new Roo.util.MixedCollection();
12294 mc.getKey = function(el){
12295    return el.dom.id;
12296 };
12297 mc.add(someEl);
12298 mc.add(otherEl);
12299
12300 // or via the constructor
12301 var mc = new Roo.util.MixedCollection(false, function(el){
12302    return el.dom.id;
12303 });
12304 mc.add(someEl);
12305 mc.add(otherEl);
12306 </code></pre>
12307  * @param o {Object} The item for which to find the key.
12308  * @return {Object} The key for the passed item.
12309  */
12310     getKey : function(o){
12311          return o.id; 
12312     },
12313    
12314 /**
12315  * Replaces an item in the collection.
12316  * @param {String} key The key associated with the item to replace, or the item to replace.
12317  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12318  * @return {Object}  The new item.
12319  */
12320     replace : function(key, o){
12321         if(arguments.length == 1){
12322             o = arguments[0];
12323             key = this.getKey(o);
12324         }
12325         var old = this.item(key);
12326         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12327              return this.add(key, o);
12328         }
12329         var index = this.indexOfKey(key);
12330         this.items[index] = o;
12331         this.map[key] = o;
12332         this.fireEvent("replace", key, old, o);
12333         return o;
12334     },
12335    
12336 /**
12337  * Adds all elements of an Array or an Object to the collection.
12338  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12339  * an Array of values, each of which are added to the collection.
12340  */
12341     addAll : function(objs){
12342         if(arguments.length > 1 || objs instanceof Array){
12343             var args = arguments.length > 1 ? arguments : objs;
12344             for(var i = 0, len = args.length; i < len; i++){
12345                 this.add(args[i]);
12346             }
12347         }else{
12348             for(var key in objs){
12349                 if(this.allowFunctions || typeof objs[key] != "function"){
12350                     this.add(key, objs[key]);
12351                 }
12352             }
12353         }
12354     },
12355    
12356 /**
12357  * Executes the specified function once for every item in the collection, passing each
12358  * item as the first and only parameter. returning false from the function will stop the iteration.
12359  * @param {Function} fn The function to execute for each item.
12360  * @param {Object} scope (optional) The scope in which to execute the function.
12361  */
12362     each : function(fn, scope){
12363         var items = [].concat(this.items); // each safe for removal
12364         for(var i = 0, len = items.length; i < len; i++){
12365             if(fn.call(scope || items[i], items[i], i, len) === false){
12366                 break;
12367             }
12368         }
12369     },
12370    
12371 /**
12372  * Executes the specified function once for every key in the collection, passing each
12373  * key, and its associated item as the first two parameters.
12374  * @param {Function} fn The function to execute for each item.
12375  * @param {Object} scope (optional) The scope in which to execute the function.
12376  */
12377     eachKey : function(fn, scope){
12378         for(var i = 0, len = this.keys.length; i < len; i++){
12379             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12380         }
12381     },
12382    
12383 /**
12384  * Returns the first item in the collection which elicits a true return value from the
12385  * passed selection function.
12386  * @param {Function} fn The selection function to execute for each item.
12387  * @param {Object} scope (optional) The scope in which to execute the function.
12388  * @return {Object} The first item in the collection which returned true from the selection function.
12389  */
12390     find : function(fn, scope){
12391         for(var i = 0, len = this.items.length; i < len; i++){
12392             if(fn.call(scope || window, this.items[i], this.keys[i])){
12393                 return this.items[i];
12394             }
12395         }
12396         return null;
12397     },
12398    
12399 /**
12400  * Inserts an item at the specified index in the collection.
12401  * @param {Number} index The index to insert the item at.
12402  * @param {String} key The key to associate with the new item, or the item itself.
12403  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12404  * @return {Object} The item inserted.
12405  */
12406     insert : function(index, key, o){
12407         if(arguments.length == 2){
12408             o = arguments[1];
12409             key = this.getKey(o);
12410         }
12411         if(index >= this.length){
12412             return this.add(key, o);
12413         }
12414         this.length++;
12415         this.items.splice(index, 0, o);
12416         if(typeof key != "undefined" && key != null){
12417             this.map[key] = o;
12418         }
12419         this.keys.splice(index, 0, key);
12420         this.fireEvent("add", index, o, key);
12421         return o;
12422     },
12423    
12424 /**
12425  * Removed an item from the collection.
12426  * @param {Object} o The item to remove.
12427  * @return {Object} The item removed.
12428  */
12429     remove : function(o){
12430         return this.removeAt(this.indexOf(o));
12431     },
12432    
12433 /**
12434  * Remove an item from a specified index in the collection.
12435  * @param {Number} index The index within the collection of the item to remove.
12436  */
12437     removeAt : function(index){
12438         if(index < this.length && index >= 0){
12439             this.length--;
12440             var o = this.items[index];
12441             this.items.splice(index, 1);
12442             var key = this.keys[index];
12443             if(typeof key != "undefined"){
12444                 delete this.map[key];
12445             }
12446             this.keys.splice(index, 1);
12447             this.fireEvent("remove", o, key);
12448         }
12449     },
12450    
12451 /**
12452  * Removed an item associated with the passed key fom the collection.
12453  * @param {String} key The key of the item to remove.
12454  */
12455     removeKey : function(key){
12456         return this.removeAt(this.indexOfKey(key));
12457     },
12458    
12459 /**
12460  * Returns the number of items in the collection.
12461  * @return {Number} the number of items in the collection.
12462  */
12463     getCount : function(){
12464         return this.length; 
12465     },
12466    
12467 /**
12468  * Returns index within the collection of the passed Object.
12469  * @param {Object} o The item to find the index of.
12470  * @return {Number} index of the item.
12471  */
12472     indexOf : function(o){
12473         if(!this.items.indexOf){
12474             for(var i = 0, len = this.items.length; i < len; i++){
12475                 if(this.items[i] == o) return i;
12476             }
12477             return -1;
12478         }else{
12479             return this.items.indexOf(o);
12480         }
12481     },
12482    
12483 /**
12484  * Returns index within the collection of the passed key.
12485  * @param {String} key The key to find the index of.
12486  * @return {Number} index of the key.
12487  */
12488     indexOfKey : function(key){
12489         if(!this.keys.indexOf){
12490             for(var i = 0, len = this.keys.length; i < len; i++){
12491                 if(this.keys[i] == key) return i;
12492             }
12493             return -1;
12494         }else{
12495             return this.keys.indexOf(key);
12496         }
12497     },
12498    
12499 /**
12500  * Returns the item associated with the passed key OR index. Key has priority over index.
12501  * @param {String/Number} key The key or index of the item.
12502  * @return {Object} The item associated with the passed key.
12503  */
12504     item : function(key){
12505         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12506         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12507     },
12508     
12509 /**
12510  * Returns the item at the specified index.
12511  * @param {Number} index The index of the item.
12512  * @return {Object}
12513  */
12514     itemAt : function(index){
12515         return this.items[index];
12516     },
12517     
12518 /**
12519  * Returns the item associated with the passed key.
12520  * @param {String/Number} key The key of the item.
12521  * @return {Object} The item associated with the passed key.
12522  */
12523     key : function(key){
12524         return this.map[key];
12525     },
12526    
12527 /**
12528  * Returns true if the collection contains the passed Object as an item.
12529  * @param {Object} o  The Object to look for in the collection.
12530  * @return {Boolean} True if the collection contains the Object as an item.
12531  */
12532     contains : function(o){
12533         return this.indexOf(o) != -1;
12534     },
12535    
12536 /**
12537  * Returns true if the collection contains the passed Object as a key.
12538  * @param {String} key The key to look for in the collection.
12539  * @return {Boolean} True if the collection contains the Object as a key.
12540  */
12541     containsKey : function(key){
12542         return typeof this.map[key] != "undefined";
12543     },
12544    
12545 /**
12546  * Removes all items from the collection.
12547  */
12548     clear : function(){
12549         this.length = 0;
12550         this.items = [];
12551         this.keys = [];
12552         this.map = {};
12553         this.fireEvent("clear");
12554     },
12555    
12556 /**
12557  * Returns the first item in the collection.
12558  * @return {Object} the first item in the collection..
12559  */
12560     first : function(){
12561         return this.items[0]; 
12562     },
12563    
12564 /**
12565  * Returns the last item in the collection.
12566  * @return {Object} the last item in the collection..
12567  */
12568     last : function(){
12569         return this.items[this.length-1];   
12570     },
12571     
12572     _sort : function(property, dir, fn){
12573         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12574         fn = fn || function(a, b){
12575             return a-b;
12576         };
12577         var c = [], k = this.keys, items = this.items;
12578         for(var i = 0, len = items.length; i < len; i++){
12579             c[c.length] = {key: k[i], value: items[i], index: i};
12580         }
12581         c.sort(function(a, b){
12582             var v = fn(a[property], b[property]) * dsc;
12583             if(v == 0){
12584                 v = (a.index < b.index ? -1 : 1);
12585             }
12586             return v;
12587         });
12588         for(var i = 0, len = c.length; i < len; i++){
12589             items[i] = c[i].value;
12590             k[i] = c[i].key;
12591         }
12592         this.fireEvent("sort", this);
12593     },
12594     
12595     /**
12596      * Sorts this collection with the passed comparison function
12597      * @param {String} direction (optional) "ASC" or "DESC"
12598      * @param {Function} fn (optional) comparison function
12599      */
12600     sort : function(dir, fn){
12601         this._sort("value", dir, fn);
12602     },
12603     
12604     /**
12605      * Sorts this collection by keys
12606      * @param {String} direction (optional) "ASC" or "DESC"
12607      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12608      */
12609     keySort : function(dir, fn){
12610         this._sort("key", dir, fn || function(a, b){
12611             return String(a).toUpperCase()-String(b).toUpperCase();
12612         });
12613     },
12614     
12615     /**
12616      * Returns a range of items in this collection
12617      * @param {Number} startIndex (optional) defaults to 0
12618      * @param {Number} endIndex (optional) default to the last item
12619      * @return {Array} An array of items
12620      */
12621     getRange : function(start, end){
12622         var items = this.items;
12623         if(items.length < 1){
12624             return [];
12625         }
12626         start = start || 0;
12627         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12628         var r = [];
12629         if(start <= end){
12630             for(var i = start; i <= end; i++) {
12631                     r[r.length] = items[i];
12632             }
12633         }else{
12634             for(var i = start; i >= end; i--) {
12635                     r[r.length] = items[i];
12636             }
12637         }
12638         return r;
12639     },
12640         
12641     /**
12642      * Filter the <i>objects</i> in this collection by a specific property. 
12643      * Returns a new collection that has been filtered.
12644      * @param {String} property A property on your objects
12645      * @param {String/RegExp} value Either string that the property values 
12646      * should start with or a RegExp to test against the property
12647      * @return {MixedCollection} The new filtered collection
12648      */
12649     filter : function(property, value){
12650         if(!value.exec){ // not a regex
12651             value = String(value);
12652             if(value.length == 0){
12653                 return this.clone();
12654             }
12655             value = new RegExp("^" + Roo.escapeRe(value), "i");
12656         }
12657         return this.filterBy(function(o){
12658             return o && value.test(o[property]);
12659         });
12660         },
12661     
12662     /**
12663      * Filter by a function. * Returns a new collection that has been filtered.
12664      * The passed function will be called with each 
12665      * object in the collection. If the function returns true, the value is included 
12666      * otherwise it is filtered.
12667      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12668      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12669      * @return {MixedCollection} The new filtered collection
12670      */
12671     filterBy : function(fn, scope){
12672         var r = new Roo.util.MixedCollection();
12673         r.getKey = this.getKey;
12674         var k = this.keys, it = this.items;
12675         for(var i = 0, len = it.length; i < len; i++){
12676             if(fn.call(scope||this, it[i], k[i])){
12677                                 r.add(k[i], it[i]);
12678                         }
12679         }
12680         return r;
12681     },
12682     
12683     /**
12684      * Creates a duplicate of this collection
12685      * @return {MixedCollection}
12686      */
12687     clone : function(){
12688         var r = new Roo.util.MixedCollection();
12689         var k = this.keys, it = this.items;
12690         for(var i = 0, len = it.length; i < len; i++){
12691             r.add(k[i], it[i]);
12692         }
12693         r.getKey = this.getKey;
12694         return r;
12695     }
12696 });
12697 /**
12698  * Returns the item associated with the passed key or index.
12699  * @method
12700  * @param {String/Number} key The key or index of the item.
12701  * @return {Object} The item associated with the passed key.
12702  */
12703 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12704  * Based on:
12705  * Ext JS Library 1.1.1
12706  * Copyright(c) 2006-2007, Ext JS, LLC.
12707  *
12708  * Originally Released Under LGPL - original licence link has changed is not relivant.
12709  *
12710  * Fork - LGPL
12711  * <script type="text/javascript">
12712  */
12713 /**
12714  * @class Roo.util.JSON
12715  * Modified version of Douglas Crockford"s json.js that doesn"t
12716  * mess with the Object prototype 
12717  * http://www.json.org/js.html
12718  * @singleton
12719  */
12720 Roo.util.JSON = new (function(){
12721     var useHasOwn = {}.hasOwnProperty ? true : false;
12722     
12723     // crashes Safari in some instances
12724     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12725     
12726     var pad = function(n) {
12727         return n < 10 ? "0" + n : n;
12728     };
12729     
12730     var m = {
12731         "\b": '\\b',
12732         "\t": '\\t',
12733         "\n": '\\n',
12734         "\f": '\\f',
12735         "\r": '\\r',
12736         '"' : '\\"',
12737         "\\": '\\\\'
12738     };
12739
12740     var encodeString = function(s){
12741         if (/["\\\x00-\x1f]/.test(s)) {
12742             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12743                 var c = m[b];
12744                 if(c){
12745                     return c;
12746                 }
12747                 c = b.charCodeAt();
12748                 return "\\u00" +
12749                     Math.floor(c / 16).toString(16) +
12750                     (c % 16).toString(16);
12751             }) + '"';
12752         }
12753         return '"' + s + '"';
12754     };
12755     
12756     var encodeArray = function(o){
12757         var a = ["["], b, i, l = o.length, v;
12758             for (i = 0; i < l; i += 1) {
12759                 v = o[i];
12760                 switch (typeof v) {
12761                     case "undefined":
12762                     case "function":
12763                     case "unknown":
12764                         break;
12765                     default:
12766                         if (b) {
12767                             a.push(',');
12768                         }
12769                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12770                         b = true;
12771                 }
12772             }
12773             a.push("]");
12774             return a.join("");
12775     };
12776     
12777     var encodeDate = function(o){
12778         return '"' + o.getFullYear() + "-" +
12779                 pad(o.getMonth() + 1) + "-" +
12780                 pad(o.getDate()) + "T" +
12781                 pad(o.getHours()) + ":" +
12782                 pad(o.getMinutes()) + ":" +
12783                 pad(o.getSeconds()) + '"';
12784     };
12785     
12786     /**
12787      * Encodes an Object, Array or other value
12788      * @param {Mixed} o The variable to encode
12789      * @return {String} The JSON string
12790      */
12791     this.encode = function(o)
12792     {
12793         // should this be extended to fully wrap stringify..
12794         
12795         if(typeof o == "undefined" || o === null){
12796             return "null";
12797         }else if(o instanceof Array){
12798             return encodeArray(o);
12799         }else if(o instanceof Date){
12800             return encodeDate(o);
12801         }else if(typeof o == "string"){
12802             return encodeString(o);
12803         }else if(typeof o == "number"){
12804             return isFinite(o) ? String(o) : "null";
12805         }else if(typeof o == "boolean"){
12806             return String(o);
12807         }else {
12808             var a = ["{"], b, i, v;
12809             for (i in o) {
12810                 if(!useHasOwn || o.hasOwnProperty(i)) {
12811                     v = o[i];
12812                     switch (typeof v) {
12813                     case "undefined":
12814                     case "function":
12815                     case "unknown":
12816                         break;
12817                     default:
12818                         if(b){
12819                             a.push(',');
12820                         }
12821                         a.push(this.encode(i), ":",
12822                                 v === null ? "null" : this.encode(v));
12823                         b = true;
12824                     }
12825                 }
12826             }
12827             a.push("}");
12828             return a.join("");
12829         }
12830     };
12831     
12832     /**
12833      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12834      * @param {String} json The JSON string
12835      * @return {Object} The resulting object
12836      */
12837     this.decode = function(json){
12838         
12839         return  /** eval:var:json */ eval("(" + json + ')');
12840     };
12841 })();
12842 /** 
12843  * Shorthand for {@link Roo.util.JSON#encode}
12844  * @member Roo encode 
12845  * @method */
12846 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12847 /** 
12848  * Shorthand for {@link Roo.util.JSON#decode}
12849  * @member Roo decode 
12850  * @method */
12851 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12852 /*
12853  * Based on:
12854  * Ext JS Library 1.1.1
12855  * Copyright(c) 2006-2007, Ext JS, LLC.
12856  *
12857  * Originally Released Under LGPL - original licence link has changed is not relivant.
12858  *
12859  * Fork - LGPL
12860  * <script type="text/javascript">
12861  */
12862  
12863 /**
12864  * @class Roo.util.Format
12865  * Reusable data formatting functions
12866  * @singleton
12867  */
12868 Roo.util.Format = function(){
12869     var trimRe = /^\s+|\s+$/g;
12870     return {
12871         /**
12872          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12873          * @param {String} value The string to truncate
12874          * @param {Number} length The maximum length to allow before truncating
12875          * @return {String} The converted text
12876          */
12877         ellipsis : function(value, len){
12878             if(value && value.length > len){
12879                 return value.substr(0, len-3)+"...";
12880             }
12881             return value;
12882         },
12883
12884         /**
12885          * Checks a reference and converts it to empty string if it is undefined
12886          * @param {Mixed} value Reference to check
12887          * @return {Mixed} Empty string if converted, otherwise the original value
12888          */
12889         undef : function(value){
12890             return typeof value != "undefined" ? value : "";
12891         },
12892
12893         /**
12894          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12895          * @param {String} value The string to encode
12896          * @return {String} The encoded text
12897          */
12898         htmlEncode : function(value){
12899             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12900         },
12901
12902         /**
12903          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12904          * @param {String} value The string to decode
12905          * @return {String} The decoded text
12906          */
12907         htmlDecode : function(value){
12908             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12909         },
12910
12911         /**
12912          * Trims any whitespace from either side of a string
12913          * @param {String} value The text to trim
12914          * @return {String} The trimmed text
12915          */
12916         trim : function(value){
12917             return String(value).replace(trimRe, "");
12918         },
12919
12920         /**
12921          * Returns a substring from within an original string
12922          * @param {String} value The original text
12923          * @param {Number} start The start index of the substring
12924          * @param {Number} length The length of the substring
12925          * @return {String} The substring
12926          */
12927         substr : function(value, start, length){
12928             return String(value).substr(start, length);
12929         },
12930
12931         /**
12932          * Converts a string to all lower case letters
12933          * @param {String} value The text to convert
12934          * @return {String} The converted text
12935          */
12936         lowercase : function(value){
12937             return String(value).toLowerCase();
12938         },
12939
12940         /**
12941          * Converts a string to all upper case letters
12942          * @param {String} value The text to convert
12943          * @return {String} The converted text
12944          */
12945         uppercase : function(value){
12946             return String(value).toUpperCase();
12947         },
12948
12949         /**
12950          * Converts the first character only of a string to upper case
12951          * @param {String} value The text to convert
12952          * @return {String} The converted text
12953          */
12954         capitalize : function(value){
12955             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12956         },
12957
12958         // private
12959         call : function(value, fn){
12960             if(arguments.length > 2){
12961                 var args = Array.prototype.slice.call(arguments, 2);
12962                 args.unshift(value);
12963                  
12964                 return /** eval:var:value */  eval(fn).apply(window, args);
12965             }else{
12966                 /** eval:var:value */
12967                 return /** eval:var:value */ eval(fn).call(window, value);
12968             }
12969         },
12970
12971        
12972         /**
12973          * safer version of Math.toFixed..??/
12974          * @param {Number/String} value The numeric value to format
12975          * @param {Number/String} value Decimal places 
12976          * @return {String} The formatted currency string
12977          */
12978         toFixed : function(v, n)
12979         {
12980             // why not use to fixed - precision is buggered???
12981             if (!n) {
12982                 return Math.round(v-0);
12983             }
12984             var fact = Math.pow(10,n+1);
12985             v = (Math.round((v-0)*fact))/fact;
12986             var z = (''+fact).substring(2);
12987             if (v == Math.floor(v)) {
12988                 return Math.floor(v) + '.' + z;
12989             }
12990             
12991             // now just padd decimals..
12992             var ps = String(v).split('.');
12993             var fd = (ps[1] + z);
12994             var r = fd.substring(0,n); 
12995             var rm = fd.substring(n); 
12996             if (rm < 5) {
12997                 return ps[0] + '.' + r;
12998             }
12999             r*=1; // turn it into a number;
13000             r++;
13001             if (String(r).length != n) {
13002                 ps[0]*=1;
13003                 ps[0]++;
13004                 r = String(r).substring(1); // chop the end off.
13005             }
13006             
13007             return ps[0] + '.' + r;
13008              
13009         },
13010         
13011         /**
13012          * Format a number as US currency
13013          * @param {Number/String} value The numeric value to format
13014          * @return {String} The formatted currency string
13015          */
13016         usMoney : function(v){
13017             v = (Math.round((v-0)*100))/100;
13018             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13019             v = String(v);
13020             var ps = v.split('.');
13021             var whole = ps[0];
13022             var sub = ps[1] ? '.'+ ps[1] : '.00';
13023             var r = /(\d+)(\d{3})/;
13024             while (r.test(whole)) {
13025                 whole = whole.replace(r, '$1' + ',' + '$2');
13026             }
13027             return "$" + whole + sub ;
13028         },
13029         
13030         /**
13031          * Parse a value into a formatted date using the specified format pattern.
13032          * @param {Mixed} value The value to format
13033          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13034          * @return {String} The formatted date string
13035          */
13036         date : function(v, format){
13037             if(!v){
13038                 return "";
13039             }
13040             if(!(v instanceof Date)){
13041                 v = new Date(Date.parse(v));
13042             }
13043             return v.dateFormat(format || "m/d/Y");
13044         },
13045
13046         /**
13047          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13048          * @param {String} format Any valid date format string
13049          * @return {Function} The date formatting function
13050          */
13051         dateRenderer : function(format){
13052             return function(v){
13053                 return Roo.util.Format.date(v, format);  
13054             };
13055         },
13056
13057         // private
13058         stripTagsRE : /<\/?[^>]+>/gi,
13059         
13060         /**
13061          * Strips all HTML tags
13062          * @param {Mixed} value The text from which to strip tags
13063          * @return {String} The stripped text
13064          */
13065         stripTags : function(v){
13066             return !v ? v : String(v).replace(this.stripTagsRE, "");
13067         }
13068     };
13069 }();/*
13070  * Based on:
13071  * Ext JS Library 1.1.1
13072  * Copyright(c) 2006-2007, Ext JS, LLC.
13073  *
13074  * Originally Released Under LGPL - original licence link has changed is not relivant.
13075  *
13076  * Fork - LGPL
13077  * <script type="text/javascript">
13078  */
13079
13080
13081  
13082
13083 /**
13084  * @class Roo.MasterTemplate
13085  * @extends Roo.Template
13086  * Provides a template that can have child templates. The syntax is:
13087 <pre><code>
13088 var t = new Roo.MasterTemplate(
13089         '&lt;select name="{name}"&gt;',
13090                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13091         '&lt;/select&gt;'
13092 );
13093 t.add('options', {value: 'foo', text: 'bar'});
13094 // or you can add multiple child elements in one shot
13095 t.addAll('options', [
13096     {value: 'foo', text: 'bar'},
13097     {value: 'foo2', text: 'bar2'},
13098     {value: 'foo3', text: 'bar3'}
13099 ]);
13100 // then append, applying the master template values
13101 t.append('my-form', {name: 'my-select'});
13102 </code></pre>
13103 * A name attribute for the child template is not required if you have only one child
13104 * template or you want to refer to them by index.
13105  */
13106 Roo.MasterTemplate = function(){
13107     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13108     this.originalHtml = this.html;
13109     var st = {};
13110     var m, re = this.subTemplateRe;
13111     re.lastIndex = 0;
13112     var subIndex = 0;
13113     while(m = re.exec(this.html)){
13114         var name = m[1], content = m[2];
13115         st[subIndex] = {
13116             name: name,
13117             index: subIndex,
13118             buffer: [],
13119             tpl : new Roo.Template(content)
13120         };
13121         if(name){
13122             st[name] = st[subIndex];
13123         }
13124         st[subIndex].tpl.compile();
13125         st[subIndex].tpl.call = this.call.createDelegate(this);
13126         subIndex++;
13127     }
13128     this.subCount = subIndex;
13129     this.subs = st;
13130 };
13131 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13132     /**
13133     * The regular expression used to match sub templates
13134     * @type RegExp
13135     * @property
13136     */
13137     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13138
13139     /**
13140      * Applies the passed values to a child template.
13141      * @param {String/Number} name (optional) The name or index of the child template
13142      * @param {Array/Object} values The values to be applied to the template
13143      * @return {MasterTemplate} this
13144      */
13145      add : function(name, values){
13146         if(arguments.length == 1){
13147             values = arguments[0];
13148             name = 0;
13149         }
13150         var s = this.subs[name];
13151         s.buffer[s.buffer.length] = s.tpl.apply(values);
13152         return this;
13153     },
13154
13155     /**
13156      * Applies all the passed values to a child template.
13157      * @param {String/Number} name (optional) The name or index of the child template
13158      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13159      * @param {Boolean} reset (optional) True to reset the template first
13160      * @return {MasterTemplate} this
13161      */
13162     fill : function(name, values, reset){
13163         var a = arguments;
13164         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13165             values = a[0];
13166             name = 0;
13167             reset = a[1];
13168         }
13169         if(reset){
13170             this.reset();
13171         }
13172         for(var i = 0, len = values.length; i < len; i++){
13173             this.add(name, values[i]);
13174         }
13175         return this;
13176     },
13177
13178     /**
13179      * Resets the template for reuse
13180      * @return {MasterTemplate} this
13181      */
13182      reset : function(){
13183         var s = this.subs;
13184         for(var i = 0; i < this.subCount; i++){
13185             s[i].buffer = [];
13186         }
13187         return this;
13188     },
13189
13190     applyTemplate : function(values){
13191         var s = this.subs;
13192         var replaceIndex = -1;
13193         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13194             return s[++replaceIndex].buffer.join("");
13195         });
13196         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13197     },
13198
13199     apply : function(){
13200         return this.applyTemplate.apply(this, arguments);
13201     },
13202
13203     compile : function(){return this;}
13204 });
13205
13206 /**
13207  * Alias for fill().
13208  * @method
13209  */
13210 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13211  /**
13212  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13213  * var tpl = Roo.MasterTemplate.from('element-id');
13214  * @param {String/HTMLElement} el
13215  * @param {Object} config
13216  * @static
13217  */
13218 Roo.MasterTemplate.from = function(el, config){
13219     el = Roo.getDom(el);
13220     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13221 };/*
13222  * Based on:
13223  * Ext JS Library 1.1.1
13224  * Copyright(c) 2006-2007, Ext JS, LLC.
13225  *
13226  * Originally Released Under LGPL - original licence link has changed is not relivant.
13227  *
13228  * Fork - LGPL
13229  * <script type="text/javascript">
13230  */
13231
13232  
13233 /**
13234  * @class Roo.util.CSS
13235  * Utility class for manipulating CSS rules
13236  * @singleton
13237  */
13238 Roo.util.CSS = function(){
13239         var rules = null;
13240         var doc = document;
13241
13242     var camelRe = /(-[a-z])/gi;
13243     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13244
13245    return {
13246    /**
13247     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13248     * tag and appended to the HEAD of the document.
13249     * @param {String|Object} cssText The text containing the css rules
13250     * @param {String} id An id to add to the stylesheet for later removal
13251     * @return {StyleSheet}
13252     */
13253     createStyleSheet : function(cssText, id){
13254         var ss;
13255         var head = doc.getElementsByTagName("head")[0];
13256         var nrules = doc.createElement("style");
13257         nrules.setAttribute("type", "text/css");
13258         if(id){
13259             nrules.setAttribute("id", id);
13260         }
13261         if (typeof(cssText) != 'string') {
13262             // support object maps..
13263             // not sure if this a good idea.. 
13264             // perhaps it should be merged with the general css handling
13265             // and handle js style props.
13266             var cssTextNew = [];
13267             for(var n in cssText) {
13268                 var citems = [];
13269                 for(var k in cssText[n]) {
13270                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13271                 }
13272                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13273                 
13274             }
13275             cssText = cssTextNew.join("\n");
13276             
13277         }
13278        
13279        
13280        if(Roo.isIE){
13281            head.appendChild(nrules);
13282            ss = nrules.styleSheet;
13283            ss.cssText = cssText;
13284        }else{
13285            try{
13286                 nrules.appendChild(doc.createTextNode(cssText));
13287            }catch(e){
13288                nrules.cssText = cssText; 
13289            }
13290            head.appendChild(nrules);
13291            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13292        }
13293        this.cacheStyleSheet(ss);
13294        return ss;
13295    },
13296
13297    /**
13298     * Removes a style or link tag by id
13299     * @param {String} id The id of the tag
13300     */
13301    removeStyleSheet : function(id){
13302        var existing = doc.getElementById(id);
13303        if(existing){
13304            existing.parentNode.removeChild(existing);
13305        }
13306    },
13307
13308    /**
13309     * Dynamically swaps an existing stylesheet reference for a new one
13310     * @param {String} id The id of an existing link tag to remove
13311     * @param {String} url The href of the new stylesheet to include
13312     */
13313    swapStyleSheet : function(id, url){
13314        this.removeStyleSheet(id);
13315        var ss = doc.createElement("link");
13316        ss.setAttribute("rel", "stylesheet");
13317        ss.setAttribute("type", "text/css");
13318        ss.setAttribute("id", id);
13319        ss.setAttribute("href", url);
13320        doc.getElementsByTagName("head")[0].appendChild(ss);
13321    },
13322    
13323    /**
13324     * Refresh the rule cache if you have dynamically added stylesheets
13325     * @return {Object} An object (hash) of rules indexed by selector
13326     */
13327    refreshCache : function(){
13328        return this.getRules(true);
13329    },
13330
13331    // private
13332    cacheStyleSheet : function(stylesheet){
13333        if(!rules){
13334            rules = {};
13335        }
13336        try{// try catch for cross domain access issue
13337            var ssRules = stylesheet.cssRules || stylesheet.rules;
13338            for(var j = ssRules.length-1; j >= 0; --j){
13339                rules[ssRules[j].selectorText] = ssRules[j];
13340            }
13341        }catch(e){}
13342    },
13343    
13344    /**
13345     * Gets all css rules for the document
13346     * @param {Boolean} refreshCache true to refresh the internal cache
13347     * @return {Object} An object (hash) of rules indexed by selector
13348     */
13349    getRules : function(refreshCache){
13350                 if(rules == null || refreshCache){
13351                         rules = {};
13352                         var ds = doc.styleSheets;
13353                         for(var i =0, len = ds.length; i < len; i++){
13354                             try{
13355                         this.cacheStyleSheet(ds[i]);
13356                     }catch(e){} 
13357                 }
13358                 }
13359                 return rules;
13360         },
13361         
13362         /**
13363     * Gets an an individual CSS rule by selector(s)
13364     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13365     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13366     * @return {CSSRule} The CSS rule or null if one is not found
13367     */
13368    getRule : function(selector, refreshCache){
13369                 var rs = this.getRules(refreshCache);
13370                 if(!(selector instanceof Array)){
13371                     return rs[selector];
13372                 }
13373                 for(var i = 0; i < selector.length; i++){
13374                         if(rs[selector[i]]){
13375                                 return rs[selector[i]];
13376                         }
13377                 }
13378                 return null;
13379         },
13380         
13381         
13382         /**
13383     * Updates a rule property
13384     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13385     * @param {String} property The css property
13386     * @param {String} value The new value for the property
13387     * @return {Boolean} true If a rule was found and updated
13388     */
13389    updateRule : function(selector, property, value){
13390                 if(!(selector instanceof Array)){
13391                         var rule = this.getRule(selector);
13392                         if(rule){
13393                                 rule.style[property.replace(camelRe, camelFn)] = value;
13394                                 return true;
13395                         }
13396                 }else{
13397                         for(var i = 0; i < selector.length; i++){
13398                                 if(this.updateRule(selector[i], property, value)){
13399                                         return true;
13400                                 }
13401                         }
13402                 }
13403                 return false;
13404         }
13405    };   
13406 }();/*
13407  * Based on:
13408  * Ext JS Library 1.1.1
13409  * Copyright(c) 2006-2007, Ext JS, LLC.
13410  *
13411  * Originally Released Under LGPL - original licence link has changed is not relivant.
13412  *
13413  * Fork - LGPL
13414  * <script type="text/javascript">
13415  */
13416
13417  
13418
13419 /**
13420  * @class Roo.util.ClickRepeater
13421  * @extends Roo.util.Observable
13422  * 
13423  * A wrapper class which can be applied to any element. Fires a "click" event while the
13424  * mouse is pressed. The interval between firings may be specified in the config but
13425  * defaults to 10 milliseconds.
13426  * 
13427  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13428  * 
13429  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13430  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13431  * Similar to an autorepeat key delay.
13432  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13433  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13434  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13435  *           "interval" and "delay" are ignored. "immediate" is honored.
13436  * @cfg {Boolean} preventDefault True to prevent the default click event
13437  * @cfg {Boolean} stopDefault True to stop the default click event
13438  * 
13439  * @history
13440  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13441  *     2007-02-02 jvs Renamed to ClickRepeater
13442  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13443  *
13444  *  @constructor
13445  * @param {String/HTMLElement/Element} el The element to listen on
13446  * @param {Object} config
13447  **/
13448 Roo.util.ClickRepeater = function(el, config)
13449 {
13450     this.el = Roo.get(el);
13451     this.el.unselectable();
13452
13453     Roo.apply(this, config);
13454
13455     this.addEvents({
13456     /**
13457      * @event mousedown
13458      * Fires when the mouse button is depressed.
13459      * @param {Roo.util.ClickRepeater} this
13460      */
13461         "mousedown" : true,
13462     /**
13463      * @event click
13464      * Fires on a specified interval during the time the element is pressed.
13465      * @param {Roo.util.ClickRepeater} this
13466      */
13467         "click" : true,
13468     /**
13469      * @event mouseup
13470      * Fires when the mouse key is released.
13471      * @param {Roo.util.ClickRepeater} this
13472      */
13473         "mouseup" : true
13474     });
13475
13476     this.el.on("mousedown", this.handleMouseDown, this);
13477     if(this.preventDefault || this.stopDefault){
13478         this.el.on("click", function(e){
13479             if(this.preventDefault){
13480                 e.preventDefault();
13481             }
13482             if(this.stopDefault){
13483                 e.stopEvent();
13484             }
13485         }, this);
13486     }
13487
13488     // allow inline handler
13489     if(this.handler){
13490         this.on("click", this.handler,  this.scope || this);
13491     }
13492
13493     Roo.util.ClickRepeater.superclass.constructor.call(this);
13494 };
13495
13496 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13497     interval : 20,
13498     delay: 250,
13499     preventDefault : true,
13500     stopDefault : false,
13501     timer : 0,
13502
13503     // private
13504     handleMouseDown : function(){
13505         clearTimeout(this.timer);
13506         this.el.blur();
13507         if(this.pressClass){
13508             this.el.addClass(this.pressClass);
13509         }
13510         this.mousedownTime = new Date();
13511
13512         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13513         this.el.on("mouseout", this.handleMouseOut, this);
13514
13515         this.fireEvent("mousedown", this);
13516         this.fireEvent("click", this);
13517         
13518         this.timer = this.click.defer(this.delay || this.interval, this);
13519     },
13520
13521     // private
13522     click : function(){
13523         this.fireEvent("click", this);
13524         this.timer = this.click.defer(this.getInterval(), this);
13525     },
13526
13527     // private
13528     getInterval: function(){
13529         if(!this.accelerate){
13530             return this.interval;
13531         }
13532         var pressTime = this.mousedownTime.getElapsed();
13533         if(pressTime < 500){
13534             return 400;
13535         }else if(pressTime < 1700){
13536             return 320;
13537         }else if(pressTime < 2600){
13538             return 250;
13539         }else if(pressTime < 3500){
13540             return 180;
13541         }else if(pressTime < 4400){
13542             return 140;
13543         }else if(pressTime < 5300){
13544             return 80;
13545         }else if(pressTime < 6200){
13546             return 50;
13547         }else{
13548             return 10;
13549         }
13550     },
13551
13552     // private
13553     handleMouseOut : function(){
13554         clearTimeout(this.timer);
13555         if(this.pressClass){
13556             this.el.removeClass(this.pressClass);
13557         }
13558         this.el.on("mouseover", this.handleMouseReturn, this);
13559     },
13560
13561     // private
13562     handleMouseReturn : function(){
13563         this.el.un("mouseover", this.handleMouseReturn);
13564         if(this.pressClass){
13565             this.el.addClass(this.pressClass);
13566         }
13567         this.click();
13568     },
13569
13570     // private
13571     handleMouseUp : function(){
13572         clearTimeout(this.timer);
13573         this.el.un("mouseover", this.handleMouseReturn);
13574         this.el.un("mouseout", this.handleMouseOut);
13575         Roo.get(document).un("mouseup", this.handleMouseUp);
13576         this.el.removeClass(this.pressClass);
13577         this.fireEvent("mouseup", this);
13578     }
13579 });/*
13580  * Based on:
13581  * Ext JS Library 1.1.1
13582  * Copyright(c) 2006-2007, Ext JS, LLC.
13583  *
13584  * Originally Released Under LGPL - original licence link has changed is not relivant.
13585  *
13586  * Fork - LGPL
13587  * <script type="text/javascript">
13588  */
13589
13590  
13591 /**
13592  * @class Roo.KeyNav
13593  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13594  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13595  * way to implement custom navigation schemes for any UI component.</p>
13596  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13597  * pageUp, pageDown, del, home, end.  Usage:</p>
13598  <pre><code>
13599 var nav = new Roo.KeyNav("my-element", {
13600     "left" : function(e){
13601         this.moveLeft(e.ctrlKey);
13602     },
13603     "right" : function(e){
13604         this.moveRight(e.ctrlKey);
13605     },
13606     "enter" : function(e){
13607         this.save();
13608     },
13609     scope : this
13610 });
13611 </code></pre>
13612  * @constructor
13613  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13614  * @param {Object} config The config
13615  */
13616 Roo.KeyNav = function(el, config){
13617     this.el = Roo.get(el);
13618     Roo.apply(this, config);
13619     if(!this.disabled){
13620         this.disabled = true;
13621         this.enable();
13622     }
13623 };
13624
13625 Roo.KeyNav.prototype = {
13626     /**
13627      * @cfg {Boolean} disabled
13628      * True to disable this KeyNav instance (defaults to false)
13629      */
13630     disabled : false,
13631     /**
13632      * @cfg {String} defaultEventAction
13633      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13634      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13635      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13636      */
13637     defaultEventAction: "stopEvent",
13638     /**
13639      * @cfg {Boolean} forceKeyDown
13640      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13641      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13642      * handle keydown instead of keypress.
13643      */
13644     forceKeyDown : false,
13645
13646     // private
13647     prepareEvent : function(e){
13648         var k = e.getKey();
13649         var h = this.keyToHandler[k];
13650         //if(h && this[h]){
13651         //    e.stopPropagation();
13652         //}
13653         if(Roo.isSafari && h && k >= 37 && k <= 40){
13654             e.stopEvent();
13655         }
13656     },
13657
13658     // private
13659     relay : function(e){
13660         var k = e.getKey();
13661         var h = this.keyToHandler[k];
13662         if(h && this[h]){
13663             if(this.doRelay(e, this[h], h) !== true){
13664                 e[this.defaultEventAction]();
13665             }
13666         }
13667     },
13668
13669     // private
13670     doRelay : function(e, h, hname){
13671         return h.call(this.scope || this, e);
13672     },
13673
13674     // possible handlers
13675     enter : false,
13676     left : false,
13677     right : false,
13678     up : false,
13679     down : false,
13680     tab : false,
13681     esc : false,
13682     pageUp : false,
13683     pageDown : false,
13684     del : false,
13685     home : false,
13686     end : false,
13687
13688     // quick lookup hash
13689     keyToHandler : {
13690         37 : "left",
13691         39 : "right",
13692         38 : "up",
13693         40 : "down",
13694         33 : "pageUp",
13695         34 : "pageDown",
13696         46 : "del",
13697         36 : "home",
13698         35 : "end",
13699         13 : "enter",
13700         27 : "esc",
13701         9  : "tab"
13702     },
13703
13704         /**
13705          * Enable this KeyNav
13706          */
13707         enable: function(){
13708                 if(this.disabled){
13709             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13710             // the EventObject will normalize Safari automatically
13711             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13712                 this.el.on("keydown", this.relay,  this);
13713             }else{
13714                 this.el.on("keydown", this.prepareEvent,  this);
13715                 this.el.on("keypress", this.relay,  this);
13716             }
13717                     this.disabled = false;
13718                 }
13719         },
13720
13721         /**
13722          * Disable this KeyNav
13723          */
13724         disable: function(){
13725                 if(!this.disabled){
13726                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13727                 this.el.un("keydown", this.relay);
13728             }else{
13729                 this.el.un("keydown", this.prepareEvent);
13730                 this.el.un("keypress", this.relay);
13731             }
13732                     this.disabled = true;
13733                 }
13734         }
13735 };/*
13736  * Based on:
13737  * Ext JS Library 1.1.1
13738  * Copyright(c) 2006-2007, Ext JS, LLC.
13739  *
13740  * Originally Released Under LGPL - original licence link has changed is not relivant.
13741  *
13742  * Fork - LGPL
13743  * <script type="text/javascript">
13744  */
13745
13746  
13747 /**
13748  * @class Roo.KeyMap
13749  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13750  * The constructor accepts the same config object as defined by {@link #addBinding}.
13751  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13752  * combination it will call the function with this signature (if the match is a multi-key
13753  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13754  * A KeyMap can also handle a string representation of keys.<br />
13755  * Usage:
13756  <pre><code>
13757 // map one key by key code
13758 var map = new Roo.KeyMap("my-element", {
13759     key: 13, // or Roo.EventObject.ENTER
13760     fn: myHandler,
13761     scope: myObject
13762 });
13763
13764 // map multiple keys to one action by string
13765 var map = new Roo.KeyMap("my-element", {
13766     key: "a\r\n\t",
13767     fn: myHandler,
13768     scope: myObject
13769 });
13770
13771 // map multiple keys to multiple actions by strings and array of codes
13772 var map = new Roo.KeyMap("my-element", [
13773     {
13774         key: [10,13],
13775         fn: function(){ alert("Return was pressed"); }
13776     }, {
13777         key: "abc",
13778         fn: function(){ alert('a, b or c was pressed'); }
13779     }, {
13780         key: "\t",
13781         ctrl:true,
13782         shift:true,
13783         fn: function(){ alert('Control + shift + tab was pressed.'); }
13784     }
13785 ]);
13786 </code></pre>
13787  * <b>Note: A KeyMap starts enabled</b>
13788  * @constructor
13789  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13790  * @param {Object} config The config (see {@link #addBinding})
13791  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13792  */
13793 Roo.KeyMap = function(el, config, eventName){
13794     this.el  = Roo.get(el);
13795     this.eventName = eventName || "keydown";
13796     this.bindings = [];
13797     if(config){
13798         this.addBinding(config);
13799     }
13800     this.enable();
13801 };
13802
13803 Roo.KeyMap.prototype = {
13804     /**
13805      * True to stop the event from bubbling and prevent the default browser action if the
13806      * key was handled by the KeyMap (defaults to false)
13807      * @type Boolean
13808      */
13809     stopEvent : false,
13810
13811     /**
13812      * Add a new binding to this KeyMap. The following config object properties are supported:
13813      * <pre>
13814 Property    Type             Description
13815 ----------  ---------------  ----------------------------------------------------------------------
13816 key         String/Array     A single keycode or an array of keycodes to handle
13817 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13818 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13819 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13820 fn          Function         The function to call when KeyMap finds the expected key combination
13821 scope       Object           The scope of the callback function
13822 </pre>
13823      *
13824      * Usage:
13825      * <pre><code>
13826 // Create a KeyMap
13827 var map = new Roo.KeyMap(document, {
13828     key: Roo.EventObject.ENTER,
13829     fn: handleKey,
13830     scope: this
13831 });
13832
13833 //Add a new binding to the existing KeyMap later
13834 map.addBinding({
13835     key: 'abc',
13836     shift: true,
13837     fn: handleKey,
13838     scope: this
13839 });
13840 </code></pre>
13841      * @param {Object/Array} config A single KeyMap config or an array of configs
13842      */
13843         addBinding : function(config){
13844         if(config instanceof Array){
13845             for(var i = 0, len = config.length; i < len; i++){
13846                 this.addBinding(config[i]);
13847             }
13848             return;
13849         }
13850         var keyCode = config.key,
13851             shift = config.shift, 
13852             ctrl = config.ctrl, 
13853             alt = config.alt,
13854             fn = config.fn,
13855             scope = config.scope;
13856         if(typeof keyCode == "string"){
13857             var ks = [];
13858             var keyString = keyCode.toUpperCase();
13859             for(var j = 0, len = keyString.length; j < len; j++){
13860                 ks.push(keyString.charCodeAt(j));
13861             }
13862             keyCode = ks;
13863         }
13864         var keyArray = keyCode instanceof Array;
13865         var handler = function(e){
13866             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13867                 var k = e.getKey();
13868                 if(keyArray){
13869                     for(var i = 0, len = keyCode.length; i < len; i++){
13870                         if(keyCode[i] == k){
13871                           if(this.stopEvent){
13872                               e.stopEvent();
13873                           }
13874                           fn.call(scope || window, k, e);
13875                           return;
13876                         }
13877                     }
13878                 }else{
13879                     if(k == keyCode){
13880                         if(this.stopEvent){
13881                            e.stopEvent();
13882                         }
13883                         fn.call(scope || window, k, e);
13884                     }
13885                 }
13886             }
13887         };
13888         this.bindings.push(handler);  
13889         },
13890
13891     /**
13892      * Shorthand for adding a single key listener
13893      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13894      * following options:
13895      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13896      * @param {Function} fn The function to call
13897      * @param {Object} scope (optional) The scope of the function
13898      */
13899     on : function(key, fn, scope){
13900         var keyCode, shift, ctrl, alt;
13901         if(typeof key == "object" && !(key instanceof Array)){
13902             keyCode = key.key;
13903             shift = key.shift;
13904             ctrl = key.ctrl;
13905             alt = key.alt;
13906         }else{
13907             keyCode = key;
13908         }
13909         this.addBinding({
13910             key: keyCode,
13911             shift: shift,
13912             ctrl: ctrl,
13913             alt: alt,
13914             fn: fn,
13915             scope: scope
13916         })
13917     },
13918
13919     // private
13920     handleKeyDown : function(e){
13921             if(this.enabled){ //just in case
13922             var b = this.bindings;
13923             for(var i = 0, len = b.length; i < len; i++){
13924                 b[i].call(this, e);
13925             }
13926             }
13927         },
13928         
13929         /**
13930          * Returns true if this KeyMap is enabled
13931          * @return {Boolean} 
13932          */
13933         isEnabled : function(){
13934             return this.enabled;  
13935         },
13936         
13937         /**
13938          * Enables this KeyMap
13939          */
13940         enable: function(){
13941                 if(!this.enabled){
13942                     this.el.on(this.eventName, this.handleKeyDown, this);
13943                     this.enabled = true;
13944                 }
13945         },
13946
13947         /**
13948          * Disable this KeyMap
13949          */
13950         disable: function(){
13951                 if(this.enabled){
13952                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
13953                     this.enabled = false;
13954                 }
13955         }
13956 };/*
13957  * Based on:
13958  * Ext JS Library 1.1.1
13959  * Copyright(c) 2006-2007, Ext JS, LLC.
13960  *
13961  * Originally Released Under LGPL - original licence link has changed is not relivant.
13962  *
13963  * Fork - LGPL
13964  * <script type="text/javascript">
13965  */
13966
13967  
13968 /**
13969  * @class Roo.util.TextMetrics
13970  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13971  * wide, in pixels, a given block of text will be.
13972  * @singleton
13973  */
13974 Roo.util.TextMetrics = function(){
13975     var shared;
13976     return {
13977         /**
13978          * Measures the size of the specified text
13979          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13980          * that can affect the size of the rendered text
13981          * @param {String} text The text to measure
13982          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13983          * in order to accurately measure the text height
13984          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13985          */
13986         measure : function(el, text, fixedWidth){
13987             if(!shared){
13988                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13989             }
13990             shared.bind(el);
13991             shared.setFixedWidth(fixedWidth || 'auto');
13992             return shared.getSize(text);
13993         },
13994
13995         /**
13996          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
13997          * the overhead of multiple calls to initialize the style properties on each measurement.
13998          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13999          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14000          * in order to accurately measure the text height
14001          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14002          */
14003         createInstance : function(el, fixedWidth){
14004             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14005         }
14006     };
14007 }();
14008
14009  
14010
14011 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14012     var ml = new Roo.Element(document.createElement('div'));
14013     document.body.appendChild(ml.dom);
14014     ml.position('absolute');
14015     ml.setLeftTop(-1000, -1000);
14016     ml.hide();
14017
14018     if(fixedWidth){
14019         ml.setWidth(fixedWidth);
14020     }
14021      
14022     var instance = {
14023         /**
14024          * Returns the size of the specified text based on the internal element's style and width properties
14025          * @memberOf Roo.util.TextMetrics.Instance#
14026          * @param {String} text The text to measure
14027          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14028          */
14029         getSize : function(text){
14030             ml.update(text);
14031             var s = ml.getSize();
14032             ml.update('');
14033             return s;
14034         },
14035
14036         /**
14037          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14038          * that can affect the size of the rendered text
14039          * @memberOf Roo.util.TextMetrics.Instance#
14040          * @param {String/HTMLElement} el The element, dom node or id
14041          */
14042         bind : function(el){
14043             ml.setStyle(
14044                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14045             );
14046         },
14047
14048         /**
14049          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14050          * to set a fixed width in order to accurately measure the text height.
14051          * @memberOf Roo.util.TextMetrics.Instance#
14052          * @param {Number} width The width to set on the element
14053          */
14054         setFixedWidth : function(width){
14055             ml.setWidth(width);
14056         },
14057
14058         /**
14059          * Returns the measured width of the specified text
14060          * @memberOf Roo.util.TextMetrics.Instance#
14061          * @param {String} text The text to measure
14062          * @return {Number} width The width in pixels
14063          */
14064         getWidth : function(text){
14065             ml.dom.style.width = 'auto';
14066             return this.getSize(text).width;
14067         },
14068
14069         /**
14070          * Returns the measured height of the specified text.  For multiline text, be sure to call
14071          * {@link #setFixedWidth} if necessary.
14072          * @memberOf Roo.util.TextMetrics.Instance#
14073          * @param {String} text The text to measure
14074          * @return {Number} height The height in pixels
14075          */
14076         getHeight : function(text){
14077             return this.getSize(text).height;
14078         }
14079     };
14080
14081     instance.bind(bindTo);
14082
14083     return instance;
14084 };
14085
14086 // backwards compat
14087 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14088  * Based on:
14089  * Ext JS Library 1.1.1
14090  * Copyright(c) 2006-2007, Ext JS, LLC.
14091  *
14092  * Originally Released Under LGPL - original licence link has changed is not relivant.
14093  *
14094  * Fork - LGPL
14095  * <script type="text/javascript">
14096  */
14097
14098 /**
14099  * @class Roo.state.Provider
14100  * Abstract base class for state provider implementations. This class provides methods
14101  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14102  * Provider interface.
14103  */
14104 Roo.state.Provider = function(){
14105     /**
14106      * @event statechange
14107      * Fires when a state change occurs.
14108      * @param {Provider} this This state provider
14109      * @param {String} key The state key which was changed
14110      * @param {String} value The encoded value for the state
14111      */
14112     this.addEvents({
14113         "statechange": true
14114     });
14115     this.state = {};
14116     Roo.state.Provider.superclass.constructor.call(this);
14117 };
14118 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14119     /**
14120      * Returns the current value for a key
14121      * @param {String} name The key name
14122      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14123      * @return {Mixed} The state data
14124      */
14125     get : function(name, defaultValue){
14126         return typeof this.state[name] == "undefined" ?
14127             defaultValue : this.state[name];
14128     },
14129     
14130     /**
14131      * Clears a value from the state
14132      * @param {String} name The key name
14133      */
14134     clear : function(name){
14135         delete this.state[name];
14136         this.fireEvent("statechange", this, name, null);
14137     },
14138     
14139     /**
14140      * Sets the value for a key
14141      * @param {String} name The key name
14142      * @param {Mixed} value The value to set
14143      */
14144     set : function(name, value){
14145         this.state[name] = value;
14146         this.fireEvent("statechange", this, name, value);
14147     },
14148     
14149     /**
14150      * Decodes a string previously encoded with {@link #encodeValue}.
14151      * @param {String} value The value to decode
14152      * @return {Mixed} The decoded value
14153      */
14154     decodeValue : function(cookie){
14155         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14156         var matches = re.exec(unescape(cookie));
14157         if(!matches || !matches[1]) return; // non state cookie
14158         var type = matches[1];
14159         var v = matches[2];
14160         switch(type){
14161             case "n":
14162                 return parseFloat(v);
14163             case "d":
14164                 return new Date(Date.parse(v));
14165             case "b":
14166                 return (v == "1");
14167             case "a":
14168                 var all = [];
14169                 var values = v.split("^");
14170                 for(var i = 0, len = values.length; i < len; i++){
14171                     all.push(this.decodeValue(values[i]));
14172                 }
14173                 return all;
14174            case "o":
14175                 var all = {};
14176                 var values = v.split("^");
14177                 for(var i = 0, len = values.length; i < len; i++){
14178                     var kv = values[i].split("=");
14179                     all[kv[0]] = this.decodeValue(kv[1]);
14180                 }
14181                 return all;
14182            default:
14183                 return v;
14184         }
14185     },
14186     
14187     /**
14188      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14189      * @param {Mixed} value The value to encode
14190      * @return {String} The encoded value
14191      */
14192     encodeValue : function(v){
14193         var enc;
14194         if(typeof v == "number"){
14195             enc = "n:" + v;
14196         }else if(typeof v == "boolean"){
14197             enc = "b:" + (v ? "1" : "0");
14198         }else if(v instanceof Date){
14199             enc = "d:" + v.toGMTString();
14200         }else if(v instanceof Array){
14201             var flat = "";
14202             for(var i = 0, len = v.length; i < len; i++){
14203                 flat += this.encodeValue(v[i]);
14204                 if(i != len-1) flat += "^";
14205             }
14206             enc = "a:" + flat;
14207         }else if(typeof v == "object"){
14208             var flat = "";
14209             for(var key in v){
14210                 if(typeof v[key] != "function"){
14211                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14212                 }
14213             }
14214             enc = "o:" + flat.substring(0, flat.length-1);
14215         }else{
14216             enc = "s:" + v;
14217         }
14218         return escape(enc);        
14219     }
14220 });
14221
14222 /*
14223  * Based on:
14224  * Ext JS Library 1.1.1
14225  * Copyright(c) 2006-2007, Ext JS, LLC.
14226  *
14227  * Originally Released Under LGPL - original licence link has changed is not relivant.
14228  *
14229  * Fork - LGPL
14230  * <script type="text/javascript">
14231  */
14232 /**
14233  * @class Roo.state.Manager
14234  * This is the global state manager. By default all components that are "state aware" check this class
14235  * for state information if you don't pass them a custom state provider. In order for this class
14236  * to be useful, it must be initialized with a provider when your application initializes.
14237  <pre><code>
14238 // in your initialization function
14239 init : function(){
14240    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14241    ...
14242    // supposed you have a {@link Roo.BorderLayout}
14243    var layout = new Roo.BorderLayout(...);
14244    layout.restoreState();
14245    // or a {Roo.BasicDialog}
14246    var dialog = new Roo.BasicDialog(...);
14247    dialog.restoreState();
14248  </code></pre>
14249  * @singleton
14250  */
14251 Roo.state.Manager = function(){
14252     var provider = new Roo.state.Provider();
14253     
14254     return {
14255         /**
14256          * Configures the default state provider for your application
14257          * @param {Provider} stateProvider The state provider to set
14258          */
14259         setProvider : function(stateProvider){
14260             provider = stateProvider;
14261         },
14262         
14263         /**
14264          * Returns the current value for a key
14265          * @param {String} name The key name
14266          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14267          * @return {Mixed} The state data
14268          */
14269         get : function(key, defaultValue){
14270             return provider.get(key, defaultValue);
14271         },
14272         
14273         /**
14274          * Sets the value for a key
14275          * @param {String} name The key name
14276          * @param {Mixed} value The state data
14277          */
14278          set : function(key, value){
14279             provider.set(key, value);
14280         },
14281         
14282         /**
14283          * Clears a value from the state
14284          * @param {String} name The key name
14285          */
14286         clear : function(key){
14287             provider.clear(key);
14288         },
14289         
14290         /**
14291          * Gets the currently configured state provider
14292          * @return {Provider} The state provider
14293          */
14294         getProvider : function(){
14295             return provider;
14296         }
14297     };
14298 }();
14299 /*
14300  * Based on:
14301  * Ext JS Library 1.1.1
14302  * Copyright(c) 2006-2007, Ext JS, LLC.
14303  *
14304  * Originally Released Under LGPL - original licence link has changed is not relivant.
14305  *
14306  * Fork - LGPL
14307  * <script type="text/javascript">
14308  */
14309 /**
14310  * @class Roo.state.CookieProvider
14311  * @extends Roo.state.Provider
14312  * The default Provider implementation which saves state via cookies.
14313  * <br />Usage:
14314  <pre><code>
14315    var cp = new Roo.state.CookieProvider({
14316        path: "/cgi-bin/",
14317        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14318        domain: "roojs.com"
14319    })
14320    Roo.state.Manager.setProvider(cp);
14321  </code></pre>
14322  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14323  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14324  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14325  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14326  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14327  * domain the page is running on including the 'www' like 'www.roojs.com')
14328  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14329  * @constructor
14330  * Create a new CookieProvider
14331  * @param {Object} config The configuration object
14332  */
14333 Roo.state.CookieProvider = function(config){
14334     Roo.state.CookieProvider.superclass.constructor.call(this);
14335     this.path = "/";
14336     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14337     this.domain = null;
14338     this.secure = false;
14339     Roo.apply(this, config);
14340     this.state = this.readCookies();
14341 };
14342
14343 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14344     // private
14345     set : function(name, value){
14346         if(typeof value == "undefined" || value === null){
14347             this.clear(name);
14348             return;
14349         }
14350         this.setCookie(name, value);
14351         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14352     },
14353
14354     // private
14355     clear : function(name){
14356         this.clearCookie(name);
14357         Roo.state.CookieProvider.superclass.clear.call(this, name);
14358     },
14359
14360     // private
14361     readCookies : function(){
14362         var cookies = {};
14363         var c = document.cookie + ";";
14364         var re = /\s?(.*?)=(.*?);/g;
14365         var matches;
14366         while((matches = re.exec(c)) != null){
14367             var name = matches[1];
14368             var value = matches[2];
14369             if(name && name.substring(0,3) == "ys-"){
14370                 cookies[name.substr(3)] = this.decodeValue(value);
14371             }
14372         }
14373         return cookies;
14374     },
14375
14376     // private
14377     setCookie : function(name, value){
14378         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14379            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14380            ((this.path == null) ? "" : ("; path=" + this.path)) +
14381            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14382            ((this.secure == true) ? "; secure" : "");
14383     },
14384
14385     // private
14386     clearCookie : function(name){
14387         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14388            ((this.path == null) ? "" : ("; path=" + this.path)) +
14389            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14390            ((this.secure == true) ? "; secure" : "");
14391     }
14392 });