colorbrewer/colorbrewer-bg.css
[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 = Roo.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, "=", Roo.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, "=", Roo.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          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * 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]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618
619         /**
620          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621          * you may want to set this to true.
622          * @type Boolean
623          */
624         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
625         
626         
627                 
628         /**
629          * Selects a single element as a Roo Element
630          * This is about as close as you can get to jQuery's $('do crazy stuff')
631          * @param {String} selector The selector/xpath query
632          * @param {Node} root (optional) The start of the query (defaults to document).
633          * @return {Roo.Element}
634          */
635         selectNode : function(selector, root) 
636         {
637             var node = Roo.DomQuery.selectNode(selector,root);
638             return node ? Roo.get(node) : new Roo.Element(false);
639         }
640         
641     });
642
643
644 })();
645
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
648 /*
649  * Based on:
650  * Ext JS Library 1.1.1
651  * Copyright(c) 2006-2007, Ext JS, LLC.
652  *
653  * Originally Released Under LGPL - original licence link has changed is not relivant.
654  *
655  * Fork - LGPL
656  * <script type="text/javascript">
657  */
658
659 (function() {    
660     // wrappedn so fnCleanup is not in global scope...
661     if(Roo.isIE) {
662         function fnCleanUp() {
663             var p = Function.prototype;
664             delete p.createSequence;
665             delete p.defer;
666             delete p.createDelegate;
667             delete p.createCallback;
668             delete p.createInterceptor;
669
670             window.detachEvent("onunload", fnCleanUp);
671         }
672         window.attachEvent("onunload", fnCleanUp);
673     }
674 })();
675
676
677 /**
678  * @class Function
679  * These functions are available on every Function object (any JavaScript function).
680  */
681 Roo.apply(Function.prototype, {
682      /**
683      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685      * Will create a function that is bound to those 2 args.
686      * @return {Function} The new function
687     */
688     createCallback : function(/*args...*/){
689         // make args available, in function below
690         var args = arguments;
691         var method = this;
692         return function() {
693             return method.apply(window, args);
694         };
695     },
696
697     /**
698      * Creates a delegate (callback) that sets the scope to obj.
699      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700      * Will create a function that is automatically scoped to this.
701      * @param {Object} obj (optional) The object for which the scope is set
702      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704      *                                             if a number the args are inserted at the specified position
705      * @return {Function} The new function
706      */
707     createDelegate : function(obj, args, appendArgs){
708         var method = this;
709         return function() {
710             var callArgs = args || arguments;
711             if(appendArgs === true){
712                 callArgs = Array.prototype.slice.call(arguments, 0);
713                 callArgs = callArgs.concat(args);
714             }else if(typeof appendArgs == "number"){
715                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
718             }
719             return method.apply(obj || window, callArgs);
720         };
721     },
722
723     /**
724      * Calls this function after the number of millseconds specified.
725      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726      * @param {Object} obj (optional) The object for which the scope is set
727      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729      *                                             if a number the args are inserted at the specified position
730      * @return {Number} The timeout id that can be used with clearTimeout
731      */
732     defer : function(millis, obj, args, appendArgs){
733         var fn = this.createDelegate(obj, args, appendArgs);
734         if(millis){
735             return setTimeout(fn, millis);
736         }
737         fn();
738         return 0;
739     },
740     /**
741      * Create a combined function call sequence of the original function + the passed function.
742      * The resulting function returns the results of the original function.
743      * The passed fcn is called with the parameters of the original function
744      * @param {Function} fcn The function to sequence
745      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746      * @return {Function} The new function
747      */
748     createSequence : function(fcn, scope){
749         if(typeof fcn != "function"){
750             return this;
751         }
752         var method = this;
753         return function() {
754             var retval = method.apply(this || window, arguments);
755             fcn.apply(scope || this || window, arguments);
756             return retval;
757         };
758     },
759
760     /**
761      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762      * The resulting function returns the results of the original function.
763      * The passed fcn is called with the parameters of the original function.
764      * @addon
765      * @param {Function} fcn The function to call before the original
766      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767      * @return {Function} The new function
768      */
769     createInterceptor : function(fcn, scope){
770         if(typeof fcn != "function"){
771             return this;
772         }
773         var method = this;
774         return function() {
775             fcn.target = this;
776             fcn.method = method;
777             if(fcn.apply(scope || this || window, arguments) === false){
778                 return;
779             }
780             return method.apply(this || window, arguments);
781         };
782     }
783 });
784 /*
785  * Based on:
786  * Ext JS Library 1.1.1
787  * Copyright(c) 2006-2007, Ext JS, LLC.
788  *
789  * Originally Released Under LGPL - original licence link has changed is not relivant.
790  *
791  * Fork - LGPL
792  * <script type="text/javascript">
793  */
794
795 Roo.applyIf(String, {
796     
797     /** @scope String */
798     
799     /**
800      * Escapes the passed string for ' and \
801      * @param {String} string The string to escape
802      * @return {String} The escaped string
803      * @static
804      */
805     escape : function(string) {
806         return string.replace(/('|\\)/g, "\\$1");
807     },
808
809     /**
810      * Pads the left side of a string with a specified character.  This is especially useful
811      * for normalizing number and date strings.  Example usage:
812      * <pre><code>
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
815 </code></pre>
816      * @param {String} string The original string
817      * @param {Number} size The total length of the output string
818      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819      * @return {String} The padded string
820      * @static
821      */
822     leftPad : function (val, size, ch) {
823         var result = new String(val);
824         if(ch === null || ch === undefined || ch === '') {
825             ch = " ";
826         }
827         while (result.length < size) {
828             result = ch + result;
829         }
830         return result;
831     },
832
833     /**
834      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
835      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
836      * <pre><code>
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
840 </code></pre>
841      * @param {String} string The tokenized string to be formatted
842      * @param {String} value1 The value to replace token {0}
843      * @param {String} value2 Etc...
844      * @return {String} The formatted string
845      * @static
846      */
847     format : function(format){
848         var args = Array.prototype.slice.call(arguments, 1);
849         return format.replace(/\{(\d+)\}/g, function(m, i){
850             return Roo.util.Format.htmlEncode(args[i]);
851         });
852     }
853 });
854
855 /**
856  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
857  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
858  * they are already different, the first value passed in is returned.  Note that this method returns the new value
859  * but does not change the current string.
860  * <pre><code>
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
863
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
866 </code></pre>
867  * @param {String} value The value to compare to the current string
868  * @param {String} other The new value to use if the string already equals the first value passed in
869  * @return {String} The new value
870  */
871  
872 String.prototype.toggle = function(value, other){
873     return this == value ? other : value;
874 };/*
875  * Based on:
876  * Ext JS Library 1.1.1
877  * Copyright(c) 2006-2007, Ext JS, LLC.
878  *
879  * Originally Released Under LGPL - original licence link has changed is not relivant.
880  *
881  * Fork - LGPL
882  * <script type="text/javascript">
883  */
884
885  /**
886  * @class Number
887  */
888 Roo.applyIf(Number.prototype, {
889     /**
890      * Checks whether or not the current number is within a desired range.  If the number is already within the
891      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892      * exceeded.  Note that this method returns the constrained value but does not change the current number.
893      * @param {Number} min The minimum number in the range
894      * @param {Number} max The maximum number in the range
895      * @return {Number} The constrained value if outside the range, otherwise the current value
896      */
897     constrain : function(min, max){
898         return Math.min(Math.max(this, min), max);
899     }
900 });/*
901  * Based on:
902  * Ext JS Library 1.1.1
903  * Copyright(c) 2006-2007, Ext JS, LLC.
904  *
905  * Originally Released Under LGPL - original licence link has changed is not relivant.
906  *
907  * Fork - LGPL
908  * <script type="text/javascript">
909  */
910  /**
911  * @class Array
912  */
913 Roo.applyIf(Array.prototype, {
914     /**
915      * Checks whether or not the specified object exists in the array.
916      * @param {Object} o The object to check for
917      * @return {Number} The index of o in the array (or -1 if it is not found)
918      */
919     indexOf : function(o){
920        for (var i = 0, len = this.length; i < len; i++){
921               if(this[i] == o) return i;
922        }
923            return -1;
924     },
925
926     /**
927      * Removes the specified object from the array.  If the object is not found nothing happens.
928      * @param {Object} o The object to remove
929      */
930     remove : function(o){
931        var index = this.indexOf(o);
932        if(index != -1){
933            this.splice(index, 1);
934        }
935     },
936     /**
937      * Map (JS 1.6 compatibility)
938      * @param {Function} function  to call
939      */
940     map : function(fun )
941     {
942         var len = this.length >>> 0;
943         if (typeof fun != "function")
944             throw new TypeError();
945
946         var res = new Array(len);
947         var thisp = arguments[1];
948         for (var i = 0; i < len; i++)
949         {
950             if (i in this)
951                 res[i] = fun.call(thisp, this[i], i, this);
952         }
953
954         return res;
955     }
956     
957 });
958
959
960  /*
961  * Based on:
962  * Ext JS Library 1.1.1
963  * Copyright(c) 2006-2007, Ext JS, LLC.
964  *
965  * Originally Released Under LGPL - original licence link has changed is not relivant.
966  *
967  * Fork - LGPL
968  * <script type="text/javascript">
969  */
970
971 /**
972  * @class Date
973  *
974  * The date parsing and format syntax is a subset of
975  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976  * supported will provide results equivalent to their PHP versions.
977  *
978  * Following is the list of all currently supported formats:
979  *<pre>
980 Sample date:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
982
983 Format  Output      Description
984 ------  ----------  --------------------------------------------------------------
985   d      10         Day of the month, 2 digits with leading zeros
986   D      Wed        A textual representation of a day, three letters
987   j      10         Day of the month without leading zeros
988   l      Wednesday  A full textual representation of the day of the week
989   S      th         English ordinal day of month suffix, 2 chars (use with j)
990   w      3          Numeric representation of the day of the week
991   z      9          The julian date, or day of the year (0-365)
992   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993   F      January    A full textual representation of the month
994   m      01         Numeric representation of a month, with leading zeros
995   M      Jan        Month name abbreviation, three letters
996   n      1          Numeric representation of a month, without leading zeros
997   t      31         Number of days in the given month
998   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
999   Y      2007       A full numeric representation of a year, 4 digits
1000   y      07         A two digit representation of a year
1001   a      pm         Lowercase Ante meridiem and Post meridiem
1002   A      PM         Uppercase Ante meridiem and Post meridiem
1003   g      3          12-hour format of an hour without leading zeros
1004   G      15         24-hour format of an hour without leading zeros
1005   h      03         12-hour format of an hour with leading zeros
1006   H      15         24-hour format of an hour with leading zeros
1007   i      05         Minutes with leading zeros
1008   s      01         Seconds, with leading zeros
1009   O      -0600      Difference to Greenwich time (GMT) in hours
1010   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1011   T      CST        Timezone setting of the machine running the code
1012   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1013 </pre>
1014  *
1015  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1016  * <pre><code>
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d'));                         //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1020 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
1021  </code></pre>
1022  *
1023  * Here are some standard date/time patterns that you might find helpful.  They
1024  * are not part of the source of Date.js, but to use them you can simply copy this
1025  * block of code into any script that is included after Date.js and they will also become
1026  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1027  * <pre><code>
1028 Date.patterns = {
1029     ISO8601Long:"Y-m-d H:i:s",
1030     ISO8601Short:"Y-m-d",
1031     ShortDate: "n/j/Y",
1032     LongDate: "l, F d, Y",
1033     FullDateTime: "l, F d, Y g:i:s A",
1034     MonthDay: "F d",
1035     ShortTime: "g:i A",
1036     LongTime: "g:i:s A",
1037     SortableDateTime: "Y-m-d\\TH:i:s",
1038     UniversalSortableDateTime: "Y-m-d H:i:sO",
1039     YearMonth: "F, Y"
1040 };
1041 </code></pre>
1042  *
1043  * Example usage:
1044  * <pre><code>
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1047  </code></pre>
1048  */
1049
1050 /*
1051  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052  * They generate precompiled functions from date formats instead of parsing and
1053  * processing the pattern every time you format a date.  These functions are available
1054  * on every Date object (any javascript function).
1055  *
1056  * The original article and download are here:
1057  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1058  *
1059  */
1060  
1061  
1062  // was in core
1063 /**
1064  Returns the number of milliseconds between this date and date
1065  @param {Date} date (optional) Defaults to now
1066  @return {Number} The diff in milliseconds
1067  @member Date getElapsed
1068  */
1069 Date.prototype.getElapsed = function(date) {
1070         return Math.abs((date || new Date()).getTime()-this.getTime());
1071 };
1072 // was in date file..
1073
1074
1075 // private
1076 Date.parseFunctions = {count:0};
1077 // private
1078 Date.parseRegexes = [];
1079 // private
1080 Date.formatFunctions = {count:0};
1081
1082 // private
1083 Date.prototype.dateFormat = function(format) {
1084     if (Date.formatFunctions[format] == null) {
1085         Date.createNewFormat(format);
1086     }
1087     var func = Date.formatFunctions[format];
1088     return this[func]();
1089 };
1090
1091
1092 /**
1093  * Formats a date given the supplied format string
1094  * @param {String} format The format string
1095  * @return {String} The formatted date
1096  * @method
1097  */
1098 Date.prototype.format = Date.prototype.dateFormat;
1099
1100 // private
1101 Date.createNewFormat = function(format) {
1102     var funcName = "format" + Date.formatFunctions.count++;
1103     Date.formatFunctions[format] = funcName;
1104     var code = "Date.prototype." + funcName + " = function(){return ";
1105     var special = false;
1106     var ch = '';
1107     for (var i = 0; i < format.length; ++i) {
1108         ch = format.charAt(i);
1109         if (!special && ch == "\\") {
1110             special = true;
1111         }
1112         else if (special) {
1113             special = false;
1114             code += "'" + String.escape(ch) + "' + ";
1115         }
1116         else {
1117             code += Date.getFormatCode(ch);
1118         }
1119     }
1120     /** eval:var:zzzzzzzzzzzzz */
1121     eval(code.substring(0, code.length - 3) + ";}");
1122 };
1123
1124 // private
1125 Date.getFormatCode = function(character) {
1126     switch (character) {
1127     case "d":
1128         return "String.leftPad(this.getDate(), 2, '0') + ";
1129     case "D":
1130         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1131     case "j":
1132         return "this.getDate() + ";
1133     case "l":
1134         return "Date.dayNames[this.getDay()] + ";
1135     case "S":
1136         return "this.getSuffix() + ";
1137     case "w":
1138         return "this.getDay() + ";
1139     case "z":
1140         return "this.getDayOfYear() + ";
1141     case "W":
1142         return "this.getWeekOfYear() + ";
1143     case "F":
1144         return "Date.monthNames[this.getMonth()] + ";
1145     case "m":
1146         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1147     case "M":
1148         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1149     case "n":
1150         return "(this.getMonth() + 1) + ";
1151     case "t":
1152         return "this.getDaysInMonth() + ";
1153     case "L":
1154         return "(this.isLeapYear() ? 1 : 0) + ";
1155     case "Y":
1156         return "this.getFullYear() + ";
1157     case "y":
1158         return "('' + this.getFullYear()).substring(2, 4) + ";
1159     case "a":
1160         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1161     case "A":
1162         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1163     case "g":
1164         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1165     case "G":
1166         return "this.getHours() + ";
1167     case "h":
1168         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1169     case "H":
1170         return "String.leftPad(this.getHours(), 2, '0') + ";
1171     case "i":
1172         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1173     case "s":
1174         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1175     case "O":
1176         return "this.getGMTOffset() + ";
1177     case "P":
1178         return "this.getGMTColonOffset() + ";
1179     case "T":
1180         return "this.getTimezone() + ";
1181     case "Z":
1182         return "(this.getTimezoneOffset() * -60) + ";
1183     default:
1184         return "'" + String.escape(character) + "' + ";
1185     }
1186 };
1187
1188 /**
1189  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1191  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1192  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1193  * string or the parse operation will fail.
1194  * Example Usage:
1195 <pre><code>
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1198
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1201
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1204
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1207 </code></pre>
1208  * @param {String} input The unparsed date as a string
1209  * @param {String} format The format the date is in
1210  * @return {Date} The parsed date
1211  * @static
1212  */
1213 Date.parseDate = function(input, format) {
1214     if (Date.parseFunctions[format] == null) {
1215         Date.createParser(format);
1216     }
1217     var func = Date.parseFunctions[format];
1218     return Date[func](input);
1219 };
1220 /**
1221  * @private
1222  */
1223 Date.createParser = function(format) {
1224     var funcName = "parse" + Date.parseFunctions.count++;
1225     var regexNum = Date.parseRegexes.length;
1226     var currentGroup = 1;
1227     Date.parseFunctions[format] = funcName;
1228
1229     var code = "Date." + funcName + " = function(input){\n"
1230         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231         + "var d = new Date();\n"
1232         + "y = d.getFullYear();\n"
1233         + "m = d.getMonth();\n"
1234         + "d = d.getDate();\n"
1235         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236         + "if (results && results.length > 0) {";
1237     var regex = "";
1238
1239     var special = false;
1240     var ch = '';
1241     for (var i = 0; i < format.length; ++i) {
1242         ch = format.charAt(i);
1243         if (!special && ch == "\\") {
1244             special = true;
1245         }
1246         else if (special) {
1247             special = false;
1248             regex += String.escape(ch);
1249         }
1250         else {
1251             var obj = Date.formatCodeToRegex(ch, currentGroup);
1252             currentGroup += obj.g;
1253             regex += obj.s;
1254             if (obj.g && obj.c) {
1255                 code += obj.c;
1256             }
1257         }
1258     }
1259
1260     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261         + "{v = new Date(y, m, d, h, i, s);}\n"
1262         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265         + "{v = new Date(y, m, d, h);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267         + "{v = new Date(y, m, d);}\n"
1268         + "else if (y >= 0 && m >= 0)\n"
1269         + "{v = new Date(y, m);}\n"
1270         + "else if (y >= 0)\n"
1271         + "{v = new Date(y);}\n"
1272         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1275         + ";}";
1276
1277     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278     /** eval:var:zzzzzzzzzzzzz */
1279     eval(code);
1280 };
1281
1282 // private
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284     switch (character) {
1285     case "D":
1286         return {g:0,
1287         c:null,
1288         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1289     case "j":
1290         return {g:1,
1291             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292             s:"(\\d{1,2})"}; // day of month without leading zeroes
1293     case "d":
1294         return {g:1,
1295             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296             s:"(\\d{2})"}; // day of month with leading zeroes
1297     case "l":
1298         return {g:0,
1299             c:null,
1300             s:"(?:" + Date.dayNames.join("|") + ")"};
1301     case "S":
1302         return {g:0,
1303             c:null,
1304             s:"(?:st|nd|rd|th)"};
1305     case "w":
1306         return {g:0,
1307             c:null,
1308             s:"\\d"};
1309     case "z":
1310         return {g:0,
1311             c:null,
1312             s:"(?:\\d{1,3})"};
1313     case "W":
1314         return {g:0,
1315             c:null,
1316             s:"(?:\\d{2})"};
1317     case "F":
1318         return {g:1,
1319             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320             s:"(" + Date.monthNames.join("|") + ")"};
1321     case "M":
1322         return {g:1,
1323             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1325     case "n":
1326         return {g:1,
1327             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1329     case "m":
1330         return {g:1,
1331             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1333     case "t":
1334         return {g:0,
1335             c:null,
1336             s:"\\d{1,2}"};
1337     case "L":
1338         return {g:0,
1339             c:null,
1340             s:"(?:1|0)"};
1341     case "Y":
1342         return {g:1,
1343             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1344             s:"(\\d{4})"};
1345     case "y":
1346         return {g:1,
1347             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1349             s:"(\\d{1,2})"};
1350     case "a":
1351         return {g:1,
1352             c:"if (results[" + currentGroup + "] == 'am') {\n"
1353                 + "if (h == 12) { h = 0; }\n"
1354                 + "} else { if (h < 12) { h += 12; }}",
1355             s:"(am|pm)"};
1356     case "A":
1357         return {g:1,
1358             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359                 + "if (h == 12) { h = 0; }\n"
1360                 + "} else { if (h < 12) { h += 12; }}",
1361             s:"(AM|PM)"};
1362     case "g":
1363     case "G":
1364         return {g:1,
1365             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1367     case "h":
1368     case "H":
1369         return {g:1,
1370             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1372     case "i":
1373         return {g:1,
1374             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1375             s:"(\\d{2})"};
1376     case "s":
1377         return {g:1,
1378             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1379             s:"(\\d{2})"};
1380     case "O":
1381         return {g:1,
1382             c:[
1383                 "o = results[", currentGroup, "];\n",
1384                 "var sn = o.substring(0,1);\n", // get + / - sign
1385                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1389             ].join(""),
1390             s:"([+\-]\\d{4})"};
1391     case "P":
1392         return {g:1,
1393                 c:[
1394                    "o = results[", currentGroup, "];\n",
1395                    "var sn = o.substring(0,1);\n",
1396                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1397                    "var mn = o.substring(4,6) % 60;\n",
1398                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1399                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1400             ].join(""),
1401             s:"([+\-]\\d{4})"};
1402     case "T":
1403         return {g:0,
1404             c:null,
1405             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1406     case "Z":
1407         return {g:1,
1408             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1409                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1410             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1411     default:
1412         return {g:0,
1413             c:null,
1414             s:String.escape(character)};
1415     }
1416 };
1417
1418 /**
1419  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1420  * @return {String} The abbreviated timezone name (e.g. 'CST')
1421  */
1422 Date.prototype.getTimezone = function() {
1423     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1424 };
1425
1426 /**
1427  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1428  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1429  */
1430 Date.prototype.getGMTOffset = function() {
1431     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1432         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1433         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1434 };
1435
1436 /**
1437  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1438  * @return {String} 2-characters representing hours and 2-characters representing minutes
1439  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1440  */
1441 Date.prototype.getGMTColonOffset = function() {
1442         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1443                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1444                 + ":"
1445                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1446 }
1447
1448 /**
1449  * Get the numeric day number of the year, adjusted for leap year.
1450  * @return {Number} 0 through 364 (365 in leap years)
1451  */
1452 Date.prototype.getDayOfYear = function() {
1453     var num = 0;
1454     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1455     for (var i = 0; i < this.getMonth(); ++i) {
1456         num += Date.daysInMonth[i];
1457     }
1458     return num + this.getDate() - 1;
1459 };
1460
1461 /**
1462  * Get the string representation of the numeric week number of the year
1463  * (equivalent to the format specifier 'W').
1464  * @return {String} '00' through '52'
1465  */
1466 Date.prototype.getWeekOfYear = function() {
1467     // Skip to Thursday of this week
1468     var now = this.getDayOfYear() + (4 - this.getDay());
1469     // Find the first Thursday of the year
1470     var jan1 = new Date(this.getFullYear(), 0, 1);
1471     var then = (7 - jan1.getDay() + 4);
1472     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1473 };
1474
1475 /**
1476  * Whether or not the current date is in a leap year.
1477  * @return {Boolean} True if the current date is in a leap year, else false
1478  */
1479 Date.prototype.isLeapYear = function() {
1480     var year = this.getFullYear();
1481     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1482 };
1483
1484 /**
1485  * Get the first day of the current month, adjusted for leap year.  The returned value
1486  * is the numeric day index within the week (0-6) which can be used in conjunction with
1487  * the {@link #monthNames} array to retrieve the textual day name.
1488  * Example:
1489  *<pre><code>
1490 var dt = new Date('1/10/2007');
1491 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1492 </code></pre>
1493  * @return {Number} The day number (0-6)
1494  */
1495 Date.prototype.getFirstDayOfMonth = function() {
1496     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1497     return (day < 0) ? (day + 7) : day;
1498 };
1499
1500 /**
1501  * Get the last day of the current month, adjusted for leap year.  The returned value
1502  * is the numeric day index within the week (0-6) which can be used in conjunction with
1503  * the {@link #monthNames} array to retrieve the textual day name.
1504  * Example:
1505  *<pre><code>
1506 var dt = new Date('1/10/2007');
1507 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1508 </code></pre>
1509  * @return {Number} The day number (0-6)
1510  */
1511 Date.prototype.getLastDayOfMonth = function() {
1512     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1513     return (day < 0) ? (day + 7) : day;
1514 };
1515
1516
1517 /**
1518  * Get the first date of this date's month
1519  * @return {Date}
1520  */
1521 Date.prototype.getFirstDateOfMonth = function() {
1522     return new Date(this.getFullYear(), this.getMonth(), 1);
1523 };
1524
1525 /**
1526  * Get the last date of this date's month
1527  * @return {Date}
1528  */
1529 Date.prototype.getLastDateOfMonth = function() {
1530     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1531 };
1532 /**
1533  * Get the number of days in the current month, adjusted for leap year.
1534  * @return {Number} The number of days in the month
1535  */
1536 Date.prototype.getDaysInMonth = function() {
1537     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1538     return Date.daysInMonth[this.getMonth()];
1539 };
1540
1541 /**
1542  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1543  * @return {String} 'st, 'nd', 'rd' or 'th'
1544  */
1545 Date.prototype.getSuffix = function() {
1546     switch (this.getDate()) {
1547         case 1:
1548         case 21:
1549         case 31:
1550             return "st";
1551         case 2:
1552         case 22:
1553             return "nd";
1554         case 3:
1555         case 23:
1556             return "rd";
1557         default:
1558             return "th";
1559     }
1560 };
1561
1562 // private
1563 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1564
1565 /**
1566  * An array of textual month names.
1567  * Override these values for international dates, for example...
1568  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1569  * @type Array
1570  * @static
1571  */
1572 Date.monthNames =
1573    ["January",
1574     "February",
1575     "March",
1576     "April",
1577     "May",
1578     "June",
1579     "July",
1580     "August",
1581     "September",
1582     "October",
1583     "November",
1584     "December"];
1585
1586 /**
1587  * An array of textual day names.
1588  * Override these values for international dates, for example...
1589  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1590  * @type Array
1591  * @static
1592  */
1593 Date.dayNames =
1594    ["Sunday",
1595     "Monday",
1596     "Tuesday",
1597     "Wednesday",
1598     "Thursday",
1599     "Friday",
1600     "Saturday"];
1601
1602 // private
1603 Date.y2kYear = 50;
1604 // private
1605 Date.monthNumbers = {
1606     Jan:0,
1607     Feb:1,
1608     Mar:2,
1609     Apr:3,
1610     May:4,
1611     Jun:5,
1612     Jul:6,
1613     Aug:7,
1614     Sep:8,
1615     Oct:9,
1616     Nov:10,
1617     Dec:11};
1618
1619 /**
1620  * Creates and returns a new Date instance with the exact same date value as the called instance.
1621  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1622  * variable will also be changed.  When the intention is to create a new variable that will not
1623  * modify the original instance, you should create a clone.
1624  *
1625  * Example of correctly cloning a date:
1626  * <pre><code>
1627 //wrong way:
1628 var orig = new Date('10/1/2006');
1629 var copy = orig;
1630 copy.setDate(5);
1631 document.write(orig);  //returns 'Thu Oct 05 2006'!
1632
1633 //correct way:
1634 var orig = new Date('10/1/2006');
1635 var copy = orig.clone();
1636 copy.setDate(5);
1637 document.write(orig);  //returns 'Thu Oct 01 2006'
1638 </code></pre>
1639  * @return {Date} The new Date instance
1640  */
1641 Date.prototype.clone = function() {
1642         return new Date(this.getTime());
1643 };
1644
1645 /**
1646  * Clears any time information from this date
1647  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1648  @return {Date} this or the clone
1649  */
1650 Date.prototype.clearTime = function(clone){
1651     if(clone){
1652         return this.clone().clearTime();
1653     }
1654     this.setHours(0);
1655     this.setMinutes(0);
1656     this.setSeconds(0);
1657     this.setMilliseconds(0);
1658     return this;
1659 };
1660
1661 // private
1662 // safari setMonth is broken
1663 if(Roo.isSafari){
1664     Date.brokenSetMonth = Date.prototype.setMonth;
1665         Date.prototype.setMonth = function(num){
1666                 if(num <= -1){
1667                         var n = Math.ceil(-num);
1668                         var back_year = Math.ceil(n/12);
1669                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1670                         this.setFullYear(this.getFullYear() - back_year);
1671                         return Date.brokenSetMonth.call(this, month);
1672                 } else {
1673                         return Date.brokenSetMonth.apply(this, arguments);
1674                 }
1675         };
1676 }
1677
1678 /** Date interval constant 
1679 * @static 
1680 * @type String */
1681 Date.MILLI = "ms";
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.SECOND = "s";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.MINUTE = "mi";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.HOUR = "h";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.DAY = "d";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.MONTH = "mo";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.YEAR = "y";
1706
1707 /**
1708  * Provides a convenient method of performing basic date arithmetic.  This method
1709  * does not modify the Date instance being called - it creates and returns
1710  * a new Date instance containing the resulting date value.
1711  *
1712  * Examples:
1713  * <pre><code>
1714 //Basic usage:
1715 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1716 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1717
1718 //Negative values will subtract correctly:
1719 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1720 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1721
1722 //You can even chain several calls together in one line!
1723 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1724 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1725  </code></pre>
1726  *
1727  * @param {String} interval   A valid date interval enum value
1728  * @param {Number} value      The amount to add to the current date
1729  * @return {Date} The new Date instance
1730  */
1731 Date.prototype.add = function(interval, value){
1732   var d = this.clone();
1733   if (!interval || value === 0) return d;
1734   switch(interval.toLowerCase()){
1735     case Date.MILLI:
1736       d.setMilliseconds(this.getMilliseconds() + value);
1737       break;
1738     case Date.SECOND:
1739       d.setSeconds(this.getSeconds() + value);
1740       break;
1741     case Date.MINUTE:
1742       d.setMinutes(this.getMinutes() + value);
1743       break;
1744     case Date.HOUR:
1745       d.setHours(this.getHours() + value);
1746       break;
1747     case Date.DAY:
1748       d.setDate(this.getDate() + value);
1749       break;
1750     case Date.MONTH:
1751       var day = this.getDate();
1752       if(day > 28){
1753           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1754       }
1755       d.setDate(day);
1756       d.setMonth(this.getMonth() + value);
1757       break;
1758     case Date.YEAR:
1759       d.setFullYear(this.getFullYear() + value);
1760       break;
1761   }
1762   return d;
1763 };
1764 /*
1765  * Based on:
1766  * Ext JS Library 1.1.1
1767  * Copyright(c) 2006-2007, Ext JS, LLC.
1768  *
1769  * Originally Released Under LGPL - original licence link has changed is not relivant.
1770  *
1771  * Fork - LGPL
1772  * <script type="text/javascript">
1773  */
1774
1775 Roo.lib.Dom = {
1776     getViewWidth : function(full) {
1777         return full ? this.getDocumentWidth() : this.getViewportWidth();
1778     },
1779
1780     getViewHeight : function(full) {
1781         return full ? this.getDocumentHeight() : this.getViewportHeight();
1782     },
1783
1784     getDocumentHeight: function() {
1785         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1786         return Math.max(scrollHeight, this.getViewportHeight());
1787     },
1788
1789     getDocumentWidth: function() {
1790         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1791         return Math.max(scrollWidth, this.getViewportWidth());
1792     },
1793
1794     getViewportHeight: function() {
1795         var height = self.innerHeight;
1796         var mode = document.compatMode;
1797
1798         if ((mode || Roo.isIE) && !Roo.isOpera) {
1799             height = (mode == "CSS1Compat") ?
1800                      document.documentElement.clientHeight :
1801                      document.body.clientHeight;
1802         }
1803
1804         return height;
1805     },
1806
1807     getViewportWidth: function() {
1808         var width = self.innerWidth;
1809         var mode = document.compatMode;
1810
1811         if (mode || Roo.isIE) {
1812             width = (mode == "CSS1Compat") ?
1813                     document.documentElement.clientWidth :
1814                     document.body.clientWidth;
1815         }
1816         return width;
1817     },
1818
1819     isAncestor : function(p, c) {
1820         p = Roo.getDom(p);
1821         c = Roo.getDom(c);
1822         if (!p || !c) {
1823             return false;
1824         }
1825
1826         if (p.contains && !Roo.isSafari) {
1827             return p.contains(c);
1828         } else if (p.compareDocumentPosition) {
1829             return !!(p.compareDocumentPosition(c) & 16);
1830         } else {
1831             var parent = c.parentNode;
1832             while (parent) {
1833                 if (parent == p) {
1834                     return true;
1835                 }
1836                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1837                     return false;
1838                 }
1839                 parent = parent.parentNode;
1840             }
1841             return false;
1842         }
1843     },
1844
1845     getRegion : function(el) {
1846         return Roo.lib.Region.getRegion(el);
1847     },
1848
1849     getY : function(el) {
1850         return this.getXY(el)[1];
1851     },
1852
1853     getX : function(el) {
1854         return this.getXY(el)[0];
1855     },
1856
1857     getXY : function(el) {
1858         var p, pe, b, scroll, bd = document.body;
1859         el = Roo.getDom(el);
1860         var fly = Roo.lib.AnimBase.fly;
1861         if (el.getBoundingClientRect) {
1862             b = el.getBoundingClientRect();
1863             scroll = fly(document).getScroll();
1864             return [b.left + scroll.left, b.top + scroll.top];
1865         }
1866         var x = 0, y = 0;
1867
1868         p = el;
1869
1870         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1871
1872         while (p) {
1873
1874             x += p.offsetLeft;
1875             y += p.offsetTop;
1876
1877             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1878                 hasAbsolute = true;
1879             }
1880
1881             if (Roo.isGecko) {
1882                 pe = fly(p);
1883
1884                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1885                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1886
1887
1888                 x += bl;
1889                 y += bt;
1890
1891
1892                 if (p != el && pe.getStyle('overflow') != 'visible') {
1893                     x += bl;
1894                     y += bt;
1895                 }
1896             }
1897             p = p.offsetParent;
1898         }
1899
1900         if (Roo.isSafari && hasAbsolute) {
1901             x -= bd.offsetLeft;
1902             y -= bd.offsetTop;
1903         }
1904
1905         if (Roo.isGecko && !hasAbsolute) {
1906             var dbd = fly(bd);
1907             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1908             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1909         }
1910
1911         p = el.parentNode;
1912         while (p && p != bd) {
1913             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1914                 x -= p.scrollLeft;
1915                 y -= p.scrollTop;
1916             }
1917             p = p.parentNode;
1918         }
1919         return [x, y];
1920     },
1921  
1922   
1923
1924
1925     setXY : function(el, xy) {
1926         el = Roo.fly(el, '_setXY');
1927         el.position();
1928         var pts = el.translatePoints(xy);
1929         if (xy[0] !== false) {
1930             el.dom.style.left = pts.left + "px";
1931         }
1932         if (xy[1] !== false) {
1933             el.dom.style.top = pts.top + "px";
1934         }
1935     },
1936
1937     setX : function(el, x) {
1938         this.setXY(el, [x, false]);
1939     },
1940
1941     setY : function(el, y) {
1942         this.setXY(el, [false, y]);
1943     }
1944 };
1945 /*
1946  * Portions of this file are based on pieces of Yahoo User Interface Library
1947  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1948  * YUI licensed under the BSD License:
1949  * http://developer.yahoo.net/yui/license.txt
1950  * <script type="text/javascript">
1951  *
1952  */
1953
1954 Roo.lib.Event = function() {
1955     var loadComplete = false;
1956     var listeners = [];
1957     var unloadListeners = [];
1958     var retryCount = 0;
1959     var onAvailStack = [];
1960     var counter = 0;
1961     var lastError = null;
1962
1963     return {
1964         POLL_RETRYS: 200,
1965         POLL_INTERVAL: 20,
1966         EL: 0,
1967         TYPE: 1,
1968         FN: 2,
1969         WFN: 3,
1970         OBJ: 3,
1971         ADJ_SCOPE: 4,
1972         _interval: null,
1973
1974         startInterval: function() {
1975             if (!this._interval) {
1976                 var self = this;
1977                 var callback = function() {
1978                     self._tryPreloadAttach();
1979                 };
1980                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1981
1982             }
1983         },
1984
1985         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1986             onAvailStack.push({ id:         p_id,
1987                 fn:         p_fn,
1988                 obj:        p_obj,
1989                 override:   p_override,
1990                 checkReady: false    });
1991
1992             retryCount = this.POLL_RETRYS;
1993             this.startInterval();
1994         },
1995
1996
1997         addListener: function(el, eventName, fn) {
1998             el = Roo.getDom(el);
1999             if (!el || !fn) {
2000                 return false;
2001             }
2002
2003             if ("unload" == eventName) {
2004                 unloadListeners[unloadListeners.length] =
2005                 [el, eventName, fn];
2006                 return true;
2007             }
2008
2009             var wrappedFn = function(e) {
2010                 return fn(Roo.lib.Event.getEvent(e));
2011             };
2012
2013             var li = [el, eventName, fn, wrappedFn];
2014
2015             var index = listeners.length;
2016             listeners[index] = li;
2017
2018             this.doAdd(el, eventName, wrappedFn, false);
2019             return true;
2020
2021         },
2022
2023
2024         removeListener: function(el, eventName, fn) {
2025             var i, len;
2026
2027             el = Roo.getDom(el);
2028
2029             if(!fn) {
2030                 return this.purgeElement(el, false, eventName);
2031             }
2032
2033
2034             if ("unload" == eventName) {
2035
2036                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2037                     var li = unloadListeners[i];
2038                     if (li &&
2039                         li[0] == el &&
2040                         li[1] == eventName &&
2041                         li[2] == fn) {
2042                         unloadListeners.splice(i, 1);
2043                         return true;
2044                     }
2045                 }
2046
2047                 return false;
2048             }
2049
2050             var cacheItem = null;
2051
2052
2053             var index = arguments[3];
2054
2055             if ("undefined" == typeof index) {
2056                 index = this._getCacheIndex(el, eventName, fn);
2057             }
2058
2059             if (index >= 0) {
2060                 cacheItem = listeners[index];
2061             }
2062
2063             if (!el || !cacheItem) {
2064                 return false;
2065             }
2066
2067             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2068
2069             delete listeners[index][this.WFN];
2070             delete listeners[index][this.FN];
2071             listeners.splice(index, 1);
2072
2073             return true;
2074
2075         },
2076
2077
2078         getTarget: function(ev, resolveTextNode) {
2079             ev = ev.browserEvent || ev;
2080             var t = ev.target || ev.srcElement;
2081             return this.resolveTextNode(t);
2082         },
2083
2084
2085         resolveTextNode: function(node) {
2086             if (Roo.isSafari && node && 3 == node.nodeType) {
2087                 return node.parentNode;
2088             } else {
2089                 return node;
2090             }
2091         },
2092
2093
2094         getPageX: function(ev) {
2095             ev = ev.browserEvent || ev;
2096             var x = ev.pageX;
2097             if (!x && 0 !== x) {
2098                 x = ev.clientX || 0;
2099
2100                 if (Roo.isIE) {
2101                     x += this.getScroll()[1];
2102                 }
2103             }
2104
2105             return x;
2106         },
2107
2108
2109         getPageY: function(ev) {
2110             ev = ev.browserEvent || ev;
2111             var y = ev.pageY;
2112             if (!y && 0 !== y) {
2113                 y = ev.clientY || 0;
2114
2115                 if (Roo.isIE) {
2116                     y += this.getScroll()[0];
2117                 }
2118             }
2119
2120
2121             return y;
2122         },
2123
2124
2125         getXY: function(ev) {
2126             ev = ev.browserEvent || ev;
2127             return [this.getPageX(ev), this.getPageY(ev)];
2128         },
2129
2130
2131         getRelatedTarget: function(ev) {
2132             ev = ev.browserEvent || ev;
2133             var t = ev.relatedTarget;
2134             if (!t) {
2135                 if (ev.type == "mouseout") {
2136                     t = ev.toElement;
2137                 } else if (ev.type == "mouseover") {
2138                     t = ev.fromElement;
2139                 }
2140             }
2141
2142             return this.resolveTextNode(t);
2143         },
2144
2145
2146         getTime: function(ev) {
2147             ev = ev.browserEvent || ev;
2148             if (!ev.time) {
2149                 var t = new Date().getTime();
2150                 try {
2151                     ev.time = t;
2152                 } catch(ex) {
2153                     this.lastError = ex;
2154                     return t;
2155                 }
2156             }
2157
2158             return ev.time;
2159         },
2160
2161
2162         stopEvent: function(ev) {
2163             this.stopPropagation(ev);
2164             this.preventDefault(ev);
2165         },
2166
2167
2168         stopPropagation: function(ev) {
2169             ev = ev.browserEvent || ev;
2170             if (ev.stopPropagation) {
2171                 ev.stopPropagation();
2172             } else {
2173                 ev.cancelBubble = true;
2174             }
2175         },
2176
2177
2178         preventDefault: function(ev) {
2179             ev = ev.browserEvent || ev;
2180             if(ev.preventDefault) {
2181                 ev.preventDefault();
2182             } else {
2183                 ev.returnValue = false;
2184             }
2185         },
2186
2187
2188         getEvent: function(e) {
2189             var ev = e || window.event;
2190             if (!ev) {
2191                 var c = this.getEvent.caller;
2192                 while (c) {
2193                     ev = c.arguments[0];
2194                     if (ev && Event == ev.constructor) {
2195                         break;
2196                     }
2197                     c = c.caller;
2198                 }
2199             }
2200             return ev;
2201         },
2202
2203
2204         getCharCode: function(ev) {
2205             ev = ev.browserEvent || ev;
2206             return ev.charCode || ev.keyCode || 0;
2207         },
2208
2209
2210         _getCacheIndex: function(el, eventName, fn) {
2211             for (var i = 0,len = listeners.length; i < len; ++i) {
2212                 var li = listeners[i];
2213                 if (li &&
2214                     li[this.FN] == fn &&
2215                     li[this.EL] == el &&
2216                     li[this.TYPE] == eventName) {
2217                     return i;
2218                 }
2219             }
2220
2221             return -1;
2222         },
2223
2224
2225         elCache: {},
2226
2227
2228         getEl: function(id) {
2229             return document.getElementById(id);
2230         },
2231
2232
2233         clearCache: function() {
2234         },
2235
2236
2237         _load: function(e) {
2238             loadComplete = true;
2239             var EU = Roo.lib.Event;
2240
2241
2242             if (Roo.isIE) {
2243                 EU.doRemove(window, "load", EU._load);
2244             }
2245         },
2246
2247
2248         _tryPreloadAttach: function() {
2249
2250             if (this.locked) {
2251                 return false;
2252             }
2253
2254             this.locked = true;
2255
2256
2257             var tryAgain = !loadComplete;
2258             if (!tryAgain) {
2259                 tryAgain = (retryCount > 0);
2260             }
2261
2262
2263             var notAvail = [];
2264             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2265                 var item = onAvailStack[i];
2266                 if (item) {
2267                     var el = this.getEl(item.id);
2268
2269                     if (el) {
2270                         if (!item.checkReady ||
2271                             loadComplete ||
2272                             el.nextSibling ||
2273                             (document && document.body)) {
2274
2275                             var scope = el;
2276                             if (item.override) {
2277                                 if (item.override === true) {
2278                                     scope = item.obj;
2279                                 } else {
2280                                     scope = item.override;
2281                                 }
2282                             }
2283                             item.fn.call(scope, item.obj);
2284                             onAvailStack[i] = null;
2285                         }
2286                     } else {
2287                         notAvail.push(item);
2288                     }
2289                 }
2290             }
2291
2292             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2293
2294             if (tryAgain) {
2295
2296                 this.startInterval();
2297             } else {
2298                 clearInterval(this._interval);
2299                 this._interval = null;
2300             }
2301
2302             this.locked = false;
2303
2304             return true;
2305
2306         },
2307
2308
2309         purgeElement: function(el, recurse, eventName) {
2310             var elListeners = this.getListeners(el, eventName);
2311             if (elListeners) {
2312                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2313                     var l = elListeners[i];
2314                     this.removeListener(el, l.type, l.fn);
2315                 }
2316             }
2317
2318             if (recurse && el && el.childNodes) {
2319                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2320                     this.purgeElement(el.childNodes[i], recurse, eventName);
2321                 }
2322             }
2323         },
2324
2325
2326         getListeners: function(el, eventName) {
2327             var results = [], searchLists;
2328             if (!eventName) {
2329                 searchLists = [listeners, unloadListeners];
2330             } else if (eventName == "unload") {
2331                 searchLists = [unloadListeners];
2332             } else {
2333                 searchLists = [listeners];
2334             }
2335
2336             for (var j = 0; j < searchLists.length; ++j) {
2337                 var searchList = searchLists[j];
2338                 if (searchList && searchList.length > 0) {
2339                     for (var i = 0,len = searchList.length; i < len; ++i) {
2340                         var l = searchList[i];
2341                         if (l && l[this.EL] === el &&
2342                             (!eventName || eventName === l[this.TYPE])) {
2343                             results.push({
2344                                 type:   l[this.TYPE],
2345                                 fn:     l[this.FN],
2346                                 obj:    l[this.OBJ],
2347                                 adjust: l[this.ADJ_SCOPE],
2348                                 index:  i
2349                             });
2350                         }
2351                     }
2352                 }
2353             }
2354
2355             return (results.length) ? results : null;
2356         },
2357
2358
2359         _unload: function(e) {
2360
2361             var EU = Roo.lib.Event, i, j, l, len, index;
2362
2363             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2364                 l = unloadListeners[i];
2365                 if (l) {
2366                     var scope = window;
2367                     if (l[EU.ADJ_SCOPE]) {
2368                         if (l[EU.ADJ_SCOPE] === true) {
2369                             scope = l[EU.OBJ];
2370                         } else {
2371                             scope = l[EU.ADJ_SCOPE];
2372                         }
2373                     }
2374                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2375                     unloadListeners[i] = null;
2376                     l = null;
2377                     scope = null;
2378                 }
2379             }
2380
2381             unloadListeners = null;
2382
2383             if (listeners && listeners.length > 0) {
2384                 j = listeners.length;
2385                 while (j) {
2386                     index = j - 1;
2387                     l = listeners[index];
2388                     if (l) {
2389                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2390                                 l[EU.FN], index);
2391                     }
2392                     j = j - 1;
2393                 }
2394                 l = null;
2395
2396                 EU.clearCache();
2397             }
2398
2399             EU.doRemove(window, "unload", EU._unload);
2400
2401         },
2402
2403
2404         getScroll: function() {
2405             var dd = document.documentElement, db = document.body;
2406             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2407                 return [dd.scrollTop, dd.scrollLeft];
2408             } else if (db) {
2409                 return [db.scrollTop, db.scrollLeft];
2410             } else {
2411                 return [0, 0];
2412             }
2413         },
2414
2415
2416         doAdd: function () {
2417             if (window.addEventListener) {
2418                 return function(el, eventName, fn, capture) {
2419                     el.addEventListener(eventName, fn, (capture));
2420                 };
2421             } else if (window.attachEvent) {
2422                 return function(el, eventName, fn, capture) {
2423                     el.attachEvent("on" + eventName, fn);
2424                 };
2425             } else {
2426                 return function() {
2427                 };
2428             }
2429         }(),
2430
2431
2432         doRemove: function() {
2433             if (window.removeEventListener) {
2434                 return function (el, eventName, fn, capture) {
2435                     el.removeEventListener(eventName, fn, (capture));
2436                 };
2437             } else if (window.detachEvent) {
2438                 return function (el, eventName, fn) {
2439                     el.detachEvent("on" + eventName, fn);
2440                 };
2441             } else {
2442                 return function() {
2443                 };
2444             }
2445         }()
2446     };
2447     
2448 }();
2449 (function() {     
2450    
2451     var E = Roo.lib.Event;
2452     E.on = E.addListener;
2453     E.un = E.removeListener;
2454
2455     if (document && document.body) {
2456         E._load();
2457     } else {
2458         E.doAdd(window, "load", E._load);
2459     }
2460     E.doAdd(window, "unload", E._unload);
2461     E._tryPreloadAttach();
2462 })();
2463
2464 /*
2465  * Portions of this file are based on pieces of Yahoo User Interface Library
2466  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2467  * YUI licensed under the BSD License:
2468  * http://developer.yahoo.net/yui/license.txt
2469  * <script type="text/javascript">
2470  *
2471  */
2472
2473 (function() {
2474     /**
2475      * @class Roo.lib.Ajax
2476      *
2477      */
2478     Roo.lib.Ajax = {
2479         /**
2480          * @static 
2481          */
2482         request : function(method, uri, cb, data, options) {
2483             if(options){
2484                 var hs = options.headers;
2485                 if(hs){
2486                     for(var h in hs){
2487                         if(hs.hasOwnProperty(h)){
2488                             this.initHeader(h, hs[h], false);
2489                         }
2490                     }
2491                 }
2492                 if(options.xmlData){
2493                     this.initHeader('Content-Type', 'text/xml', false);
2494                     method = 'POST';
2495                     data = options.xmlData;
2496                 }
2497             }
2498
2499             return this.asyncRequest(method, uri, cb, data);
2500         },
2501
2502         serializeForm : function(form) {
2503             if(typeof form == 'string') {
2504                 form = (document.getElementById(form) || document.forms[form]);
2505             }
2506
2507             var el, name, val, disabled, data = '', hasSubmit = false;
2508             for (var i = 0; i < form.elements.length; i++) {
2509                 el = form.elements[i];
2510                 disabled = form.elements[i].disabled;
2511                 name = form.elements[i].name;
2512                 val = form.elements[i].value;
2513
2514                 if (!disabled && name){
2515                     switch (el.type)
2516                             {
2517                         case 'select-one':
2518                         case 'select-multiple':
2519                             for (var j = 0; j < el.options.length; j++) {
2520                                 if (el.options[j].selected) {
2521                                     if (Roo.isIE) {
2522                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2523                                     }
2524                                     else {
2525                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2526                                     }
2527                                 }
2528                             }
2529                             break;
2530                         case 'radio':
2531                         case 'checkbox':
2532                             if (el.checked) {
2533                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2534                             }
2535                             break;
2536                         case 'file':
2537
2538                         case undefined:
2539
2540                         case 'reset':
2541
2542                         case 'button':
2543
2544                             break;
2545                         case 'submit':
2546                             if(hasSubmit == false) {
2547                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2548                                 hasSubmit = true;
2549                             }
2550                             break;
2551                         default:
2552                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2553                             break;
2554                     }
2555                 }
2556             }
2557             data = data.substr(0, data.length - 1);
2558             return data;
2559         },
2560
2561         headers:{},
2562
2563         hasHeaders:false,
2564
2565         useDefaultHeader:true,
2566
2567         defaultPostHeader:'application/x-www-form-urlencoded',
2568
2569         useDefaultXhrHeader:true,
2570
2571         defaultXhrHeader:'XMLHttpRequest',
2572
2573         hasDefaultHeaders:true,
2574
2575         defaultHeaders:{},
2576
2577         poll:{},
2578
2579         timeout:{},
2580
2581         pollInterval:50,
2582
2583         transactionId:0,
2584
2585         setProgId:function(id)
2586         {
2587             this.activeX.unshift(id);
2588         },
2589
2590         setDefaultPostHeader:function(b)
2591         {
2592             this.useDefaultHeader = b;
2593         },
2594
2595         setDefaultXhrHeader:function(b)
2596         {
2597             this.useDefaultXhrHeader = b;
2598         },
2599
2600         setPollingInterval:function(i)
2601         {
2602             if (typeof i == 'number' && isFinite(i)) {
2603                 this.pollInterval = i;
2604             }
2605         },
2606
2607         createXhrObject:function(transactionId)
2608         {
2609             var obj,http;
2610             try
2611             {
2612
2613                 http = new XMLHttpRequest();
2614
2615                 obj = { conn:http, tId:transactionId };
2616             }
2617             catch(e)
2618             {
2619                 for (var i = 0; i < this.activeX.length; ++i) {
2620                     try
2621                     {
2622
2623                         http = new ActiveXObject(this.activeX[i]);
2624
2625                         obj = { conn:http, tId:transactionId };
2626                         break;
2627                     }
2628                     catch(e) {
2629                     }
2630                 }
2631             }
2632             finally
2633             {
2634                 return obj;
2635             }
2636         },
2637
2638         getConnectionObject:function()
2639         {
2640             var o;
2641             var tId = this.transactionId;
2642
2643             try
2644             {
2645                 o = this.createXhrObject(tId);
2646                 if (o) {
2647                     this.transactionId++;
2648                 }
2649             }
2650             catch(e) {
2651             }
2652             finally
2653             {
2654                 return o;
2655             }
2656         },
2657
2658         asyncRequest:function(method, uri, callback, postData)
2659         {
2660             var o = this.getConnectionObject();
2661
2662             if (!o) {
2663                 return null;
2664             }
2665             else {
2666                 o.conn.open(method, uri, true);
2667
2668                 if (this.useDefaultXhrHeader) {
2669                     if (!this.defaultHeaders['X-Requested-With']) {
2670                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2671                     }
2672                 }
2673
2674                 if(postData && this.useDefaultHeader){
2675                     this.initHeader('Content-Type', this.defaultPostHeader);
2676                 }
2677
2678                  if (this.hasDefaultHeaders || this.hasHeaders) {
2679                     this.setHeader(o);
2680                 }
2681
2682                 this.handleReadyState(o, callback);
2683                 o.conn.send(postData || null);
2684
2685                 return o;
2686             }
2687         },
2688
2689         handleReadyState:function(o, callback)
2690         {
2691             var oConn = this;
2692
2693             if (callback && callback.timeout) {
2694                 this.timeout[o.tId] = window.setTimeout(function() {
2695                     oConn.abort(o, callback, true);
2696                 }, callback.timeout);
2697             }
2698
2699             this.poll[o.tId] = window.setInterval(
2700                     function() {
2701                         if (o.conn && o.conn.readyState == 4) {
2702                             window.clearInterval(oConn.poll[o.tId]);
2703                             delete oConn.poll[o.tId];
2704
2705                             if(callback && callback.timeout) {
2706                                 window.clearTimeout(oConn.timeout[o.tId]);
2707                                 delete oConn.timeout[o.tId];
2708                             }
2709
2710                             oConn.handleTransactionResponse(o, callback);
2711                         }
2712                     }
2713                     , this.pollInterval);
2714         },
2715
2716         handleTransactionResponse:function(o, callback, isAbort)
2717         {
2718
2719             if (!callback) {
2720                 this.releaseObject(o);
2721                 return;
2722             }
2723
2724             var httpStatus, responseObject;
2725
2726             try
2727             {
2728                 if (o.conn.status !== undefined && o.conn.status != 0) {
2729                     httpStatus = o.conn.status;
2730                 }
2731                 else {
2732                     httpStatus = 13030;
2733                 }
2734             }
2735             catch(e) {
2736
2737
2738                 httpStatus = 13030;
2739             }
2740
2741             if (httpStatus >= 200 && httpStatus < 300) {
2742                 responseObject = this.createResponseObject(o, callback.argument);
2743                 if (callback.success) {
2744                     if (!callback.scope) {
2745                         callback.success(responseObject);
2746                     }
2747                     else {
2748
2749
2750                         callback.success.apply(callback.scope, [responseObject]);
2751                     }
2752                 }
2753             }
2754             else {
2755                 switch (httpStatus) {
2756
2757                     case 12002:
2758                     case 12029:
2759                     case 12030:
2760                     case 12031:
2761                     case 12152:
2762                     case 13030:
2763                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2764                         if (callback.failure) {
2765                             if (!callback.scope) {
2766                                 callback.failure(responseObject);
2767                             }
2768                             else {
2769                                 callback.failure.apply(callback.scope, [responseObject]);
2770                             }
2771                         }
2772                         break;
2773                     default:
2774                         responseObject = this.createResponseObject(o, callback.argument);
2775                         if (callback.failure) {
2776                             if (!callback.scope) {
2777                                 callback.failure(responseObject);
2778                             }
2779                             else {
2780                                 callback.failure.apply(callback.scope, [responseObject]);
2781                             }
2782                         }
2783                 }
2784             }
2785
2786             this.releaseObject(o);
2787             responseObject = null;
2788         },
2789
2790         createResponseObject:function(o, callbackArg)
2791         {
2792             var obj = {};
2793             var headerObj = {};
2794
2795             try
2796             {
2797                 var headerStr = o.conn.getAllResponseHeaders();
2798                 var header = headerStr.split('\n');
2799                 for (var i = 0; i < header.length; i++) {
2800                     var delimitPos = header[i].indexOf(':');
2801                     if (delimitPos != -1) {
2802                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2803                     }
2804                 }
2805             }
2806             catch(e) {
2807             }
2808
2809             obj.tId = o.tId;
2810             obj.status = o.conn.status;
2811             obj.statusText = o.conn.statusText;
2812             obj.getResponseHeader = headerObj;
2813             obj.getAllResponseHeaders = headerStr;
2814             obj.responseText = o.conn.responseText;
2815             obj.responseXML = o.conn.responseXML;
2816
2817             if (typeof callbackArg !== undefined) {
2818                 obj.argument = callbackArg;
2819             }
2820
2821             return obj;
2822         },
2823
2824         createExceptionObject:function(tId, callbackArg, isAbort)
2825         {
2826             var COMM_CODE = 0;
2827             var COMM_ERROR = 'communication failure';
2828             var ABORT_CODE = -1;
2829             var ABORT_ERROR = 'transaction aborted';
2830
2831             var obj = {};
2832
2833             obj.tId = tId;
2834             if (isAbort) {
2835                 obj.status = ABORT_CODE;
2836                 obj.statusText = ABORT_ERROR;
2837             }
2838             else {
2839                 obj.status = COMM_CODE;
2840                 obj.statusText = COMM_ERROR;
2841             }
2842
2843             if (callbackArg) {
2844                 obj.argument = callbackArg;
2845             }
2846
2847             return obj;
2848         },
2849
2850         initHeader:function(label, value, isDefault)
2851         {
2852             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2853
2854             if (headerObj[label] === undefined) {
2855                 headerObj[label] = value;
2856             }
2857             else {
2858
2859
2860                 headerObj[label] = value + "," + headerObj[label];
2861             }
2862
2863             if (isDefault) {
2864                 this.hasDefaultHeaders = true;
2865             }
2866             else {
2867                 this.hasHeaders = true;
2868             }
2869         },
2870
2871
2872         setHeader:function(o)
2873         {
2874             if (this.hasDefaultHeaders) {
2875                 for (var prop in this.defaultHeaders) {
2876                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2877                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2878                     }
2879                 }
2880             }
2881
2882             if (this.hasHeaders) {
2883                 for (var prop in this.headers) {
2884                     if (this.headers.hasOwnProperty(prop)) {
2885                         o.conn.setRequestHeader(prop, this.headers[prop]);
2886                     }
2887                 }
2888                 this.headers = {};
2889                 this.hasHeaders = false;
2890             }
2891         },
2892
2893         resetDefaultHeaders:function() {
2894             delete this.defaultHeaders;
2895             this.defaultHeaders = {};
2896             this.hasDefaultHeaders = false;
2897         },
2898
2899         abort:function(o, callback, isTimeout)
2900         {
2901             if(this.isCallInProgress(o)) {
2902                 o.conn.abort();
2903                 window.clearInterval(this.poll[o.tId]);
2904                 delete this.poll[o.tId];
2905                 if (isTimeout) {
2906                     delete this.timeout[o.tId];
2907                 }
2908
2909                 this.handleTransactionResponse(o, callback, true);
2910
2911                 return true;
2912             }
2913             else {
2914                 return false;
2915             }
2916         },
2917
2918
2919         isCallInProgress:function(o)
2920         {
2921             if (o && o.conn) {
2922                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2923             }
2924             else {
2925
2926                 return false;
2927             }
2928         },
2929
2930
2931         releaseObject:function(o)
2932         {
2933
2934             o.conn = null;
2935
2936             o = null;
2937         },
2938
2939         activeX:[
2940         'MSXML2.XMLHTTP.3.0',
2941         'MSXML2.XMLHTTP',
2942         'Microsoft.XMLHTTP'
2943         ]
2944
2945
2946     };
2947 })();/*
2948  * Portions of this file are based on pieces of Yahoo User Interface Library
2949  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2950  * YUI licensed under the BSD License:
2951  * http://developer.yahoo.net/yui/license.txt
2952  * <script type="text/javascript">
2953  *
2954  */
2955
2956 Roo.lib.Region = function(t, r, b, l) {
2957     this.top = t;
2958     this[1] = t;
2959     this.right = r;
2960     this.bottom = b;
2961     this.left = l;
2962     this[0] = l;
2963 };
2964
2965
2966 Roo.lib.Region.prototype = {
2967     contains : function(region) {
2968         return ( region.left >= this.left &&
2969                  region.right <= this.right &&
2970                  region.top >= this.top &&
2971                  region.bottom <= this.bottom    );
2972
2973     },
2974
2975     getArea : function() {
2976         return ( (this.bottom - this.top) * (this.right - this.left) );
2977     },
2978
2979     intersect : function(region) {
2980         var t = Math.max(this.top, region.top);
2981         var r = Math.min(this.right, region.right);
2982         var b = Math.min(this.bottom, region.bottom);
2983         var l = Math.max(this.left, region.left);
2984
2985         if (b >= t && r >= l) {
2986             return new Roo.lib.Region(t, r, b, l);
2987         } else {
2988             return null;
2989         }
2990     },
2991     union : function(region) {
2992         var t = Math.min(this.top, region.top);
2993         var r = Math.max(this.right, region.right);
2994         var b = Math.max(this.bottom, region.bottom);
2995         var l = Math.min(this.left, region.left);
2996
2997         return new Roo.lib.Region(t, r, b, l);
2998     },
2999
3000     adjust : function(t, l, b, r) {
3001         this.top += t;
3002         this.left += l;
3003         this.right += r;
3004         this.bottom += b;
3005         return this;
3006     }
3007 };
3008
3009 Roo.lib.Region.getRegion = function(el) {
3010     var p = Roo.lib.Dom.getXY(el);
3011
3012     var t = p[1];
3013     var r = p[0] + el.offsetWidth;
3014     var b = p[1] + el.offsetHeight;
3015     var l = p[0];
3016
3017     return new Roo.lib.Region(t, r, b, l);
3018 };
3019 /*
3020  * Portions of this file are based on pieces of Yahoo User Interface Library
3021  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3022  * YUI licensed under the BSD License:
3023  * http://developer.yahoo.net/yui/license.txt
3024  * <script type="text/javascript">
3025  *
3026  */
3027 //@@dep Roo.lib.Region
3028
3029
3030 Roo.lib.Point = function(x, y) {
3031     if (x instanceof Array) {
3032         y = x[1];
3033         x = x[0];
3034     }
3035     this.x = this.right = this.left = this[0] = x;
3036     this.y = this.top = this.bottom = this[1] = y;
3037 };
3038
3039 Roo.lib.Point.prototype = new Roo.lib.Region();
3040 /*
3041  * Portions of this file are based on pieces of Yahoo User Interface Library
3042  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3043  * YUI licensed under the BSD License:
3044  * http://developer.yahoo.net/yui/license.txt
3045  * <script type="text/javascript">
3046  *
3047  */
3048  
3049 (function() {   
3050
3051     Roo.lib.Anim = {
3052         scroll : function(el, args, duration, easing, cb, scope) {
3053             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3054         },
3055
3056         motion : function(el, args, duration, easing, cb, scope) {
3057             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3058         },
3059
3060         color : function(el, args, duration, easing, cb, scope) {
3061             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3062         },
3063
3064         run : function(el, args, duration, easing, cb, scope, type) {
3065             type = type || Roo.lib.AnimBase;
3066             if (typeof easing == "string") {
3067                 easing = Roo.lib.Easing[easing];
3068             }
3069             var anim = new type(el, args, duration, easing);
3070             anim.animateX(function() {
3071                 Roo.callback(cb, scope);
3072             });
3073             return anim;
3074         }
3075     };
3076 })();/*
3077  * Portions of this file are based on pieces of Yahoo User Interface Library
3078  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3079  * YUI licensed under the BSD License:
3080  * http://developer.yahoo.net/yui/license.txt
3081  * <script type="text/javascript">
3082  *
3083  */
3084
3085 (function() {    
3086     var libFlyweight;
3087     
3088     function fly(el) {
3089         if (!libFlyweight) {
3090             libFlyweight = new Roo.Element.Flyweight();
3091         }
3092         libFlyweight.dom = el;
3093         return libFlyweight;
3094     }
3095
3096     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3097     
3098    
3099     
3100     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3101         if (el) {
3102             this.init(el, attributes, duration, method);
3103         }
3104     };
3105
3106     Roo.lib.AnimBase.fly = fly;
3107     
3108     
3109     
3110     Roo.lib.AnimBase.prototype = {
3111
3112         toString: function() {
3113             var el = this.getEl();
3114             var id = el.id || el.tagName;
3115             return ("Anim " + id);
3116         },
3117
3118         patterns: {
3119             noNegatives:        /width|height|opacity|padding/i,
3120             offsetAttribute:  /^((width|height)|(top|left))$/,
3121             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3122             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3123         },
3124
3125
3126         doMethod: function(attr, start, end) {
3127             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3128         },
3129
3130
3131         setAttribute: function(attr, val, unit) {
3132             if (this.patterns.noNegatives.test(attr)) {
3133                 val = (val > 0) ? val : 0;
3134             }
3135
3136             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3137         },
3138
3139
3140         getAttribute: function(attr) {
3141             var el = this.getEl();
3142             var val = fly(el).getStyle(attr);
3143
3144             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3145                 return parseFloat(val);
3146             }
3147
3148             var a = this.patterns.offsetAttribute.exec(attr) || [];
3149             var pos = !!( a[3] );
3150             var box = !!( a[2] );
3151
3152
3153             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3154                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3155             } else {
3156                 val = 0;
3157             }
3158
3159             return val;
3160         },
3161
3162
3163         getDefaultUnit: function(attr) {
3164             if (this.patterns.defaultUnit.test(attr)) {
3165                 return 'px';
3166             }
3167
3168             return '';
3169         },
3170
3171         animateX : function(callback, scope) {
3172             var f = function() {
3173                 this.onComplete.removeListener(f);
3174                 if (typeof callback == "function") {
3175                     callback.call(scope || this, this);
3176                 }
3177             };
3178             this.onComplete.addListener(f, this);
3179             this.animate();
3180         },
3181
3182
3183         setRuntimeAttribute: function(attr) {
3184             var start;
3185             var end;
3186             var attributes = this.attributes;
3187
3188             this.runtimeAttributes[attr] = {};
3189
3190             var isset = function(prop) {
3191                 return (typeof prop !== 'undefined');
3192             };
3193
3194             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3195                 return false;
3196             }
3197
3198             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3199
3200
3201             if (isset(attributes[attr]['to'])) {
3202                 end = attributes[attr]['to'];
3203             } else if (isset(attributes[attr]['by'])) {
3204                 if (start.constructor == Array) {
3205                     end = [];
3206                     for (var i = 0, len = start.length; i < len; ++i) {
3207                         end[i] = start[i] + attributes[attr]['by'][i];
3208                     }
3209                 } else {
3210                     end = start + attributes[attr]['by'];
3211                 }
3212             }
3213
3214             this.runtimeAttributes[attr].start = start;
3215             this.runtimeAttributes[attr].end = end;
3216
3217
3218             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3219         },
3220
3221
3222         init: function(el, attributes, duration, method) {
3223
3224             var isAnimated = false;
3225
3226
3227             var startTime = null;
3228
3229
3230             var actualFrames = 0;
3231
3232
3233             el = Roo.getDom(el);
3234
3235
3236             this.attributes = attributes || {};
3237
3238
3239             this.duration = duration || 1;
3240
3241
3242             this.method = method || Roo.lib.Easing.easeNone;
3243
3244
3245             this.useSeconds = true;
3246
3247
3248             this.currentFrame = 0;
3249
3250
3251             this.totalFrames = Roo.lib.AnimMgr.fps;
3252
3253
3254             this.getEl = function() {
3255                 return el;
3256             };
3257
3258
3259             this.isAnimated = function() {
3260                 return isAnimated;
3261             };
3262
3263
3264             this.getStartTime = function() {
3265                 return startTime;
3266             };
3267
3268             this.runtimeAttributes = {};
3269
3270
3271             this.animate = function() {
3272                 if (this.isAnimated()) {
3273                     return false;
3274                 }
3275
3276                 this.currentFrame = 0;
3277
3278                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3279
3280                 Roo.lib.AnimMgr.registerElement(this);
3281             };
3282
3283
3284             this.stop = function(finish) {
3285                 if (finish) {
3286                     this.currentFrame = this.totalFrames;
3287                     this._onTween.fire();
3288                 }
3289                 Roo.lib.AnimMgr.stop(this);
3290             };
3291
3292             var onStart = function() {
3293                 this.onStart.fire();
3294
3295                 this.runtimeAttributes = {};
3296                 for (var attr in this.attributes) {
3297                     this.setRuntimeAttribute(attr);
3298                 }
3299
3300                 isAnimated = true;
3301                 actualFrames = 0;
3302                 startTime = new Date();
3303             };
3304
3305
3306             var onTween = function() {
3307                 var data = {
3308                     duration: new Date() - this.getStartTime(),
3309                     currentFrame: this.currentFrame
3310                 };
3311
3312                 data.toString = function() {
3313                     return (
3314                             'duration: ' + data.duration +
3315                             ', currentFrame: ' + data.currentFrame
3316                             );
3317                 };
3318
3319                 this.onTween.fire(data);
3320
3321                 var runtimeAttributes = this.runtimeAttributes;
3322
3323                 for (var attr in runtimeAttributes) {
3324                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3325                 }
3326
3327                 actualFrames += 1;
3328             };
3329
3330             var onComplete = function() {
3331                 var actual_duration = (new Date() - startTime) / 1000 ;
3332
3333                 var data = {
3334                     duration: actual_duration,
3335                     frames: actualFrames,
3336                     fps: actualFrames / actual_duration
3337                 };
3338
3339                 data.toString = function() {
3340                     return (
3341                             'duration: ' + data.duration +
3342                             ', frames: ' + data.frames +
3343                             ', fps: ' + data.fps
3344                             );
3345                 };
3346
3347                 isAnimated = false;
3348                 actualFrames = 0;
3349                 this.onComplete.fire(data);
3350             };
3351
3352
3353             this._onStart = new Roo.util.Event(this);
3354             this.onStart = new Roo.util.Event(this);
3355             this.onTween = new Roo.util.Event(this);
3356             this._onTween = new Roo.util.Event(this);
3357             this.onComplete = new Roo.util.Event(this);
3358             this._onComplete = new Roo.util.Event(this);
3359             this._onStart.addListener(onStart);
3360             this._onTween.addListener(onTween);
3361             this._onComplete.addListener(onComplete);
3362         }
3363     };
3364 })();
3365 /*
3366  * Portions of this file are based on pieces of Yahoo User Interface Library
3367  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3368  * YUI licensed under the BSD License:
3369  * http://developer.yahoo.net/yui/license.txt
3370  * <script type="text/javascript">
3371  *
3372  */
3373
3374 Roo.lib.AnimMgr = new function() {
3375
3376         var thread = null;
3377
3378
3379         var queue = [];
3380
3381
3382         var tweenCount = 0;
3383
3384
3385         this.fps = 1000;
3386
3387
3388         this.delay = 1;
3389
3390
3391         this.registerElement = function(tween) {
3392             queue[queue.length] = tween;
3393             tweenCount += 1;
3394             tween._onStart.fire();
3395             this.start();
3396         };
3397
3398
3399         this.unRegister = function(tween, index) {
3400             tween._onComplete.fire();
3401             index = index || getIndex(tween);
3402             if (index != -1) {
3403                 queue.splice(index, 1);
3404             }
3405
3406             tweenCount -= 1;
3407             if (tweenCount <= 0) {
3408                 this.stop();
3409             }
3410         };
3411
3412
3413         this.start = function() {
3414             if (thread === null) {
3415                 thread = setInterval(this.run, this.delay);
3416             }
3417         };
3418
3419
3420         this.stop = function(tween) {
3421             if (!tween) {
3422                 clearInterval(thread);
3423
3424                 for (var i = 0, len = queue.length; i < len; ++i) {
3425                     if (queue[0].isAnimated()) {
3426                         this.unRegister(queue[0], 0);
3427                     }
3428                 }
3429
3430                 queue = [];
3431                 thread = null;
3432                 tweenCount = 0;
3433             }
3434             else {
3435                 this.unRegister(tween);
3436             }
3437         };
3438
3439
3440         this.run = function() {
3441             for (var i = 0, len = queue.length; i < len; ++i) {
3442                 var tween = queue[i];
3443                 if (!tween || !tween.isAnimated()) {
3444                     continue;
3445                 }
3446
3447                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3448                 {
3449                     tween.currentFrame += 1;
3450
3451                     if (tween.useSeconds) {
3452                         correctFrame(tween);
3453                     }
3454                     tween._onTween.fire();
3455                 }
3456                 else {
3457                     Roo.lib.AnimMgr.stop(tween, i);
3458                 }
3459             }
3460         };
3461
3462         var getIndex = function(anim) {
3463             for (var i = 0, len = queue.length; i < len; ++i) {
3464                 if (queue[i] == anim) {
3465                     return i;
3466                 }
3467             }
3468             return -1;
3469         };
3470
3471
3472         var correctFrame = function(tween) {
3473             var frames = tween.totalFrames;
3474             var frame = tween.currentFrame;
3475             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3476             var elapsed = (new Date() - tween.getStartTime());
3477             var tweak = 0;
3478
3479             if (elapsed < tween.duration * 1000) {
3480                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3481             } else {
3482                 tweak = frames - (frame + 1);
3483             }
3484             if (tweak > 0 && isFinite(tweak)) {
3485                 if (tween.currentFrame + tweak >= frames) {
3486                     tweak = frames - (frame + 1);
3487                 }
3488
3489                 tween.currentFrame += tweak;
3490             }
3491         };
3492     };/*
3493  * Portions of this file are based on pieces of Yahoo User Interface Library
3494  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3495  * YUI licensed under the BSD License:
3496  * http://developer.yahoo.net/yui/license.txt
3497  * <script type="text/javascript">
3498  *
3499  */
3500 Roo.lib.Bezier = new function() {
3501
3502         this.getPosition = function(points, t) {
3503             var n = points.length;
3504             var tmp = [];
3505
3506             for (var i = 0; i < n; ++i) {
3507                 tmp[i] = [points[i][0], points[i][1]];
3508             }
3509
3510             for (var j = 1; j < n; ++j) {
3511                 for (i = 0; i < n - j; ++i) {
3512                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3513                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3514                 }
3515             }
3516
3517             return [ tmp[0][0], tmp[0][1] ];
3518
3519         };
3520     };/*
3521  * Portions of this file are based on pieces of Yahoo User Interface Library
3522  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3523  * YUI licensed under the BSD License:
3524  * http://developer.yahoo.net/yui/license.txt
3525  * <script type="text/javascript">
3526  *
3527  */
3528 (function() {
3529
3530     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3531         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3532     };
3533
3534     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3535
3536     var fly = Roo.lib.AnimBase.fly;
3537     var Y = Roo.lib;
3538     var superclass = Y.ColorAnim.superclass;
3539     var proto = Y.ColorAnim.prototype;
3540
3541     proto.toString = function() {
3542         var el = this.getEl();
3543         var id = el.id || el.tagName;
3544         return ("ColorAnim " + id);
3545     };
3546
3547     proto.patterns.color = /color$/i;
3548     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3549     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3550     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3551     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3552
3553
3554     proto.parseColor = function(s) {
3555         if (s.length == 3) {
3556             return s;
3557         }
3558
3559         var c = this.patterns.hex.exec(s);
3560         if (c && c.length == 4) {
3561             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3562         }
3563
3564         c = this.patterns.rgb.exec(s);
3565         if (c && c.length == 4) {
3566             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3567         }
3568
3569         c = this.patterns.hex3.exec(s);
3570         if (c && c.length == 4) {
3571             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3572         }
3573
3574         return null;
3575     };
3576     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3577     proto.getAttribute = function(attr) {
3578         var el = this.getEl();
3579         if (this.patterns.color.test(attr)) {
3580             var val = fly(el).getStyle(attr);
3581
3582             if (this.patterns.transparent.test(val)) {
3583                 var parent = el.parentNode;
3584                 val = fly(parent).getStyle(attr);
3585
3586                 while (parent && this.patterns.transparent.test(val)) {
3587                     parent = parent.parentNode;
3588                     val = fly(parent).getStyle(attr);
3589                     if (parent.tagName.toUpperCase() == 'HTML') {
3590                         val = '#fff';
3591                     }
3592                 }
3593             }
3594         } else {
3595             val = superclass.getAttribute.call(this, attr);
3596         }
3597
3598         return val;
3599     };
3600     proto.getAttribute = function(attr) {
3601         var el = this.getEl();
3602         if (this.patterns.color.test(attr)) {
3603             var val = fly(el).getStyle(attr);
3604
3605             if (this.patterns.transparent.test(val)) {
3606                 var parent = el.parentNode;
3607                 val = fly(parent).getStyle(attr);
3608
3609                 while (parent && this.patterns.transparent.test(val)) {
3610                     parent = parent.parentNode;
3611                     val = fly(parent).getStyle(attr);
3612                     if (parent.tagName.toUpperCase() == 'HTML') {
3613                         val = '#fff';
3614                     }
3615                 }
3616             }
3617         } else {
3618             val = superclass.getAttribute.call(this, attr);
3619         }
3620
3621         return val;
3622     };
3623
3624     proto.doMethod = function(attr, start, end) {
3625         var val;
3626
3627         if (this.patterns.color.test(attr)) {
3628             val = [];
3629             for (var i = 0, len = start.length; i < len; ++i) {
3630                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3631             }
3632
3633             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3634         }
3635         else {
3636             val = superclass.doMethod.call(this, attr, start, end);
3637         }
3638
3639         return val;
3640     };
3641
3642     proto.setRuntimeAttribute = function(attr) {
3643         superclass.setRuntimeAttribute.call(this, attr);
3644
3645         if (this.patterns.color.test(attr)) {
3646             var attributes = this.attributes;
3647             var start = this.parseColor(this.runtimeAttributes[attr].start);
3648             var end = this.parseColor(this.runtimeAttributes[attr].end);
3649
3650             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3651                 end = this.parseColor(attributes[attr].by);
3652
3653                 for (var i = 0, len = start.length; i < len; ++i) {
3654                     end[i] = start[i] + end[i];
3655                 }
3656             }
3657
3658             this.runtimeAttributes[attr].start = start;
3659             this.runtimeAttributes[attr].end = end;
3660         }
3661     };
3662 })();
3663
3664 /*
3665  * Portions of this file are based on pieces of Yahoo User Interface Library
3666  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3667  * YUI licensed under the BSD License:
3668  * http://developer.yahoo.net/yui/license.txt
3669  * <script type="text/javascript">
3670  *
3671  */
3672 Roo.lib.Easing = {
3673
3674
3675     easeNone: function (t, b, c, d) {
3676         return c * t / d + b;
3677     },
3678
3679
3680     easeIn: function (t, b, c, d) {
3681         return c * (t /= d) * t + b;
3682     },
3683
3684
3685     easeOut: function (t, b, c, d) {
3686         return -c * (t /= d) * (t - 2) + b;
3687     },
3688
3689
3690     easeBoth: function (t, b, c, d) {
3691         if ((t /= d / 2) < 1) {
3692             return c / 2 * t * t + b;
3693         }
3694
3695         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3696     },
3697
3698
3699     easeInStrong: function (t, b, c, d) {
3700         return c * (t /= d) * t * t * t + b;
3701     },
3702
3703
3704     easeOutStrong: function (t, b, c, d) {
3705         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3706     },
3707
3708
3709     easeBothStrong: function (t, b, c, d) {
3710         if ((t /= d / 2) < 1) {
3711             return c / 2 * t * t * t * t + b;
3712         }
3713
3714         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3715     },
3716
3717
3718
3719     elasticIn: function (t, b, c, d, a, p) {
3720         if (t == 0) {
3721             return b;
3722         }
3723         if ((t /= d) == 1) {
3724             return b + c;
3725         }
3726         if (!p) {
3727             p = d * .3;
3728         }
3729
3730         if (!a || a < Math.abs(c)) {
3731             a = c;
3732             var s = p / 4;
3733         }
3734         else {
3735             var s = p / (2 * Math.PI) * Math.asin(c / a);
3736         }
3737
3738         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3739     },
3740
3741
3742     elasticOut: function (t, b, c, d, a, p) {
3743         if (t == 0) {
3744             return b;
3745         }
3746         if ((t /= d) == 1) {
3747             return b + c;
3748         }
3749         if (!p) {
3750             p = d * .3;
3751         }
3752
3753         if (!a || a < Math.abs(c)) {
3754             a = c;
3755             var s = p / 4;
3756         }
3757         else {
3758             var s = p / (2 * Math.PI) * Math.asin(c / a);
3759         }
3760
3761         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3762     },
3763
3764
3765     elasticBoth: function (t, b, c, d, a, p) {
3766         if (t == 0) {
3767             return b;
3768         }
3769
3770         if ((t /= d / 2) == 2) {
3771             return b + c;
3772         }
3773
3774         if (!p) {
3775             p = d * (.3 * 1.5);
3776         }
3777
3778         if (!a || a < Math.abs(c)) {
3779             a = c;
3780             var s = p / 4;
3781         }
3782         else {
3783             var s = p / (2 * Math.PI) * Math.asin(c / a);
3784         }
3785
3786         if (t < 1) {
3787             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3788                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3789         }
3790         return a * Math.pow(2, -10 * (t -= 1)) *
3791                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3792     },
3793
3794
3795
3796     backIn: function (t, b, c, d, s) {
3797         if (typeof s == 'undefined') {
3798             s = 1.70158;
3799         }
3800         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3801     },
3802
3803
3804     backOut: function (t, b, c, d, s) {
3805         if (typeof s == 'undefined') {
3806             s = 1.70158;
3807         }
3808         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3809     },
3810
3811
3812     backBoth: function (t, b, c, d, s) {
3813         if (typeof s == 'undefined') {
3814             s = 1.70158;
3815         }
3816
3817         if ((t /= d / 2 ) < 1) {
3818             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3819         }
3820         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3821     },
3822
3823
3824     bounceIn: function (t, b, c, d) {
3825         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3826     },
3827
3828
3829     bounceOut: function (t, b, c, d) {
3830         if ((t /= d) < (1 / 2.75)) {
3831             return c * (7.5625 * t * t) + b;
3832         } else if (t < (2 / 2.75)) {
3833             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3834         } else if (t < (2.5 / 2.75)) {
3835             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3836         }
3837         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3838     },
3839
3840
3841     bounceBoth: function (t, b, c, d) {
3842         if (t < d / 2) {
3843             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3844         }
3845         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3846     }
3847 };/*
3848  * Portions of this file are based on pieces of Yahoo User Interface Library
3849  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3850  * YUI licensed under the BSD License:
3851  * http://developer.yahoo.net/yui/license.txt
3852  * <script type="text/javascript">
3853  *
3854  */
3855     (function() {
3856         Roo.lib.Motion = function(el, attributes, duration, method) {
3857             if (el) {
3858                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3859             }
3860         };
3861
3862         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3863
3864
3865         var Y = Roo.lib;
3866         var superclass = Y.Motion.superclass;
3867         var proto = Y.Motion.prototype;
3868
3869         proto.toString = function() {
3870             var el = this.getEl();
3871             var id = el.id || el.tagName;
3872             return ("Motion " + id);
3873         };
3874
3875         proto.patterns.points = /^points$/i;
3876
3877         proto.setAttribute = function(attr, val, unit) {
3878             if (this.patterns.points.test(attr)) {
3879                 unit = unit || 'px';
3880                 superclass.setAttribute.call(this, 'left', val[0], unit);
3881                 superclass.setAttribute.call(this, 'top', val[1], unit);
3882             } else {
3883                 superclass.setAttribute.call(this, attr, val, unit);
3884             }
3885         };
3886
3887         proto.getAttribute = function(attr) {
3888             if (this.patterns.points.test(attr)) {
3889                 var val = [
3890                         superclass.getAttribute.call(this, 'left'),
3891                         superclass.getAttribute.call(this, 'top')
3892                         ];
3893             } else {
3894                 val = superclass.getAttribute.call(this, attr);
3895             }
3896
3897             return val;
3898         };
3899
3900         proto.doMethod = function(attr, start, end) {
3901             var val = null;
3902
3903             if (this.patterns.points.test(attr)) {
3904                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3905                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3906             } else {
3907                 val = superclass.doMethod.call(this, attr, start, end);
3908             }
3909             return val;
3910         };
3911
3912         proto.setRuntimeAttribute = function(attr) {
3913             if (this.patterns.points.test(attr)) {
3914                 var el = this.getEl();
3915                 var attributes = this.attributes;
3916                 var start;
3917                 var control = attributes['points']['control'] || [];
3918                 var end;
3919                 var i, len;
3920
3921                 if (control.length > 0 && !(control[0] instanceof Array)) {
3922                     control = [control];
3923                 } else {
3924                     var tmp = [];
3925                     for (i = 0,len = control.length; i < len; ++i) {
3926                         tmp[i] = control[i];
3927                     }
3928                     control = tmp;
3929                 }
3930
3931                 Roo.fly(el).position();
3932
3933                 if (isset(attributes['points']['from'])) {
3934                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3935                 }
3936                 else {
3937                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3938                 }
3939
3940                 start = this.getAttribute('points');
3941
3942
3943                 if (isset(attributes['points']['to'])) {
3944                     end = translateValues.call(this, attributes['points']['to'], start);
3945
3946                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3947                     for (i = 0,len = control.length; i < len; ++i) {
3948                         control[i] = translateValues.call(this, control[i], start);
3949                     }
3950
3951
3952                 } else if (isset(attributes['points']['by'])) {
3953                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3954
3955                     for (i = 0,len = control.length; i < len; ++i) {
3956                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3957                     }
3958                 }
3959
3960                 this.runtimeAttributes[attr] = [start];
3961
3962                 if (control.length > 0) {
3963                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3964                 }
3965
3966                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3967             }
3968             else {
3969                 superclass.setRuntimeAttribute.call(this, attr);
3970             }
3971         };
3972
3973         var translateValues = function(val, start) {
3974             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3975             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3976
3977             return val;
3978         };
3979
3980         var isset = function(prop) {
3981             return (typeof prop !== 'undefined');
3982         };
3983     })();
3984 /*
3985  * Portions of this file are based on pieces of Yahoo User Interface Library
3986  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3987  * YUI licensed under the BSD License:
3988  * http://developer.yahoo.net/yui/license.txt
3989  * <script type="text/javascript">
3990  *
3991  */
3992     (function() {
3993         Roo.lib.Scroll = function(el, attributes, duration, method) {
3994             if (el) {
3995                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3996             }
3997         };
3998
3999         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4000
4001
4002         var Y = Roo.lib;
4003         var superclass = Y.Scroll.superclass;
4004         var proto = Y.Scroll.prototype;
4005
4006         proto.toString = function() {
4007             var el = this.getEl();
4008             var id = el.id || el.tagName;
4009             return ("Scroll " + id);
4010         };
4011
4012         proto.doMethod = function(attr, start, end) {
4013             var val = null;
4014
4015             if (attr == 'scroll') {
4016                 val = [
4017                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4018                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4019                         ];
4020
4021             } else {
4022                 val = superclass.doMethod.call(this, attr, start, end);
4023             }
4024             return val;
4025         };
4026
4027         proto.getAttribute = function(attr) {
4028             var val = null;
4029             var el = this.getEl();
4030
4031             if (attr == 'scroll') {
4032                 val = [ el.scrollLeft, el.scrollTop ];
4033             } else {
4034                 val = superclass.getAttribute.call(this, attr);
4035             }
4036
4037             return val;
4038         };
4039
4040         proto.setAttribute = function(attr, val, unit) {
4041             var el = this.getEl();
4042
4043             if (attr == 'scroll') {
4044                 el.scrollLeft = val[0];
4045                 el.scrollTop = val[1];
4046             } else {
4047                 superclass.setAttribute.call(this, attr, val, unit);
4048             }
4049         };
4050     })();
4051 /*
4052  * Based on:
4053  * Ext JS Library 1.1.1
4054  * Copyright(c) 2006-2007, Ext JS, LLC.
4055  *
4056  * Originally Released Under LGPL - original licence link has changed is not relivant.
4057  *
4058  * Fork - LGPL
4059  * <script type="text/javascript">
4060  */
4061
4062
4063 // nasty IE9 hack - what a pile of crap that is..
4064
4065  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4066     Range.prototype.createContextualFragment = function (html) {
4067         var doc = window.document;
4068         var container = doc.createElement("div");
4069         container.innerHTML = html;
4070         var frag = doc.createDocumentFragment(), n;
4071         while ((n = container.firstChild)) {
4072             frag.appendChild(n);
4073         }
4074         return frag;
4075     };
4076 }
4077
4078 /**
4079  * @class Roo.DomHelper
4080  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4081  * 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>.
4082  * @singleton
4083  */
4084 Roo.DomHelper = function(){
4085     var tempTableEl = null;
4086     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4087     var tableRe = /^table|tbody|tr|td$/i;
4088     var xmlns = {};
4089     // build as innerHTML where available
4090     /** @ignore */
4091     var createHtml = function(o){
4092         if(typeof o == 'string'){
4093             return o;
4094         }
4095         var b = "";
4096         if(!o.tag){
4097             o.tag = "div";
4098         }
4099         b += "<" + o.tag;
4100         for(var attr in o){
4101             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4102             if(attr == "style"){
4103                 var s = o["style"];
4104                 if(typeof s == "function"){
4105                     s = s.call();
4106                 }
4107                 if(typeof s == "string"){
4108                     b += ' style="' + s + '"';
4109                 }else if(typeof s == "object"){
4110                     b += ' style="';
4111                     for(var key in s){
4112                         if(typeof s[key] != "function"){
4113                             b += key + ":" + s[key] + ";";
4114                         }
4115                     }
4116                     b += '"';
4117                 }
4118             }else{
4119                 if(attr == "cls"){
4120                     b += ' class="' + o["cls"] + '"';
4121                 }else if(attr == "htmlFor"){
4122                     b += ' for="' + o["htmlFor"] + '"';
4123                 }else{
4124                     b += " " + attr + '="' + o[attr] + '"';
4125                 }
4126             }
4127         }
4128         if(emptyTags.test(o.tag)){
4129             b += "/>";
4130         }else{
4131             b += ">";
4132             var cn = o.children || o.cn;
4133             if(cn){
4134                 //http://bugs.kde.org/show_bug.cgi?id=71506
4135                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4136                     for(var i = 0, len = cn.length; i < len; i++) {
4137                         b += createHtml(cn[i], b);
4138                     }
4139                 }else{
4140                     b += createHtml(cn, b);
4141                 }
4142             }
4143             if(o.html){
4144                 b += o.html;
4145             }
4146             b += "</" + o.tag + ">";
4147         }
4148         return b;
4149     };
4150
4151     // build as dom
4152     /** @ignore */
4153     var createDom = function(o, parentNode){
4154          
4155         // defininition craeted..
4156         var ns = false;
4157         if (o.ns && o.ns != 'html') {
4158                
4159             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4160                 xmlns[o.ns] = o.xmlns;
4161                 ns = o.xmlns;
4162             }
4163             if (typeof(xmlns[o.ns]) == 'undefined') {
4164                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4165             }
4166             ns = xmlns[o.ns];
4167         }
4168         
4169         
4170         if (typeof(o) == 'string') {
4171             return parentNode.appendChild(document.createTextNode(o));
4172         }
4173         o.tag = o.tag || div;
4174         if (o.ns && Roo.isIE) {
4175             ns = false;
4176             o.tag = o.ns + ':' + o.tag;
4177             
4178         }
4179         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4180         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4181         for(var attr in o){
4182             
4183             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4184                     attr == "style" || typeof o[attr] == "function") continue;
4185                     
4186             if(attr=="cls" && Roo.isIE){
4187                 el.className = o["cls"];
4188             }else{
4189                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4190                 else el[attr] = o[attr];
4191             }
4192         }
4193         Roo.DomHelper.applyStyles(el, o.style);
4194         var cn = o.children || o.cn;
4195         if(cn){
4196             //http://bugs.kde.org/show_bug.cgi?id=71506
4197              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198                 for(var i = 0, len = cn.length; i < len; i++) {
4199                     createDom(cn[i], el);
4200                 }
4201             }else{
4202                 createDom(cn, el);
4203             }
4204         }
4205         if(o.html){
4206             el.innerHTML = o.html;
4207         }
4208         if(parentNode){
4209            parentNode.appendChild(el);
4210         }
4211         return el;
4212     };
4213
4214     var ieTable = function(depth, s, h, e){
4215         tempTableEl.innerHTML = [s, h, e].join('');
4216         var i = -1, el = tempTableEl;
4217         while(++i < depth){
4218             el = el.firstChild;
4219         }
4220         return el;
4221     };
4222
4223     // kill repeat to save bytes
4224     var ts = '<table>',
4225         te = '</table>',
4226         tbs = ts+'<tbody>',
4227         tbe = '</tbody>'+te,
4228         trs = tbs + '<tr>',
4229         tre = '</tr>'+tbe;
4230
4231     /**
4232      * @ignore
4233      * Nasty code for IE's broken table implementation
4234      */
4235     var insertIntoTable = function(tag, where, el, html){
4236         if(!tempTableEl){
4237             tempTableEl = document.createElement('div');
4238         }
4239         var node;
4240         var before = null;
4241         if(tag == 'td'){
4242             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4243                 return;
4244             }
4245             if(where == 'beforebegin'){
4246                 before = el;
4247                 el = el.parentNode;
4248             } else{
4249                 before = el.nextSibling;
4250                 el = el.parentNode;
4251             }
4252             node = ieTable(4, trs, html, tre);
4253         }
4254         else if(tag == 'tr'){
4255             if(where == 'beforebegin'){
4256                 before = el;
4257                 el = el.parentNode;
4258                 node = ieTable(3, tbs, html, tbe);
4259             } else if(where == 'afterend'){
4260                 before = el.nextSibling;
4261                 el = el.parentNode;
4262                 node = ieTable(3, tbs, html, tbe);
4263             } else{ // INTO a TR
4264                 if(where == 'afterbegin'){
4265                     before = el.firstChild;
4266                 }
4267                 node = ieTable(4, trs, html, tre);
4268             }
4269         } else if(tag == 'tbody'){
4270             if(where == 'beforebegin'){
4271                 before = el;
4272                 el = el.parentNode;
4273                 node = ieTable(2, ts, html, te);
4274             } else if(where == 'afterend'){
4275                 before = el.nextSibling;
4276                 el = el.parentNode;
4277                 node = ieTable(2, ts, html, te);
4278             } else{
4279                 if(where == 'afterbegin'){
4280                     before = el.firstChild;
4281                 }
4282                 node = ieTable(3, tbs, html, tbe);
4283             }
4284         } else{ // TABLE
4285             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4286                 return;
4287             }
4288             if(where == 'afterbegin'){
4289                 before = el.firstChild;
4290             }
4291             node = ieTable(2, ts, html, te);
4292         }
4293         el.insertBefore(node, before);
4294         return node;
4295     };
4296
4297     return {
4298     /** True to force the use of DOM instead of html fragments @type Boolean */
4299     useDom : false,
4300
4301     /**
4302      * Returns the markup for the passed Element(s) config
4303      * @param {Object} o The Dom object spec (and children)
4304      * @return {String}
4305      */
4306     markup : function(o){
4307         return createHtml(o);
4308     },
4309
4310     /**
4311      * Applies a style specification to an element
4312      * @param {String/HTMLElement} el The element to apply styles to
4313      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4314      * a function which returns such a specification.
4315      */
4316     applyStyles : function(el, styles){
4317         if(styles){
4318            el = Roo.fly(el);
4319            if(typeof styles == "string"){
4320                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4321                var matches;
4322                while ((matches = re.exec(styles)) != null){
4323                    el.setStyle(matches[1], matches[2]);
4324                }
4325            }else if (typeof styles == "object"){
4326                for (var style in styles){
4327                   el.setStyle(style, styles[style]);
4328                }
4329            }else if (typeof styles == "function"){
4330                 Roo.DomHelper.applyStyles(el, styles.call());
4331            }
4332         }
4333     },
4334
4335     /**
4336      * Inserts an HTML fragment into the Dom
4337      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4338      * @param {HTMLElement} el The context element
4339      * @param {String} html The HTML fragmenet
4340      * @return {HTMLElement} The new node
4341      */
4342     insertHtml : function(where, el, html){
4343         where = where.toLowerCase();
4344         if(el.insertAdjacentHTML){
4345             if(tableRe.test(el.tagName)){
4346                 var rs;
4347                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4348                     return rs;
4349                 }
4350             }
4351             switch(where){
4352                 case "beforebegin":
4353                     el.insertAdjacentHTML('BeforeBegin', html);
4354                     return el.previousSibling;
4355                 case "afterbegin":
4356                     el.insertAdjacentHTML('AfterBegin', html);
4357                     return el.firstChild;
4358                 case "beforeend":
4359                     el.insertAdjacentHTML('BeforeEnd', html);
4360                     return el.lastChild;
4361                 case "afterend":
4362                     el.insertAdjacentHTML('AfterEnd', html);
4363                     return el.nextSibling;
4364             }
4365             throw 'Illegal insertion point -> "' + where + '"';
4366         }
4367         var range = el.ownerDocument.createRange();
4368         var frag;
4369         switch(where){
4370              case "beforebegin":
4371                 range.setStartBefore(el);
4372                 frag = range.createContextualFragment(html);
4373                 el.parentNode.insertBefore(frag, el);
4374                 return el.previousSibling;
4375              case "afterbegin":
4376                 if(el.firstChild){
4377                     range.setStartBefore(el.firstChild);
4378                     frag = range.createContextualFragment(html);
4379                     el.insertBefore(frag, el.firstChild);
4380                     return el.firstChild;
4381                 }else{
4382                     el.innerHTML = html;
4383                     return el.firstChild;
4384                 }
4385             case "beforeend":
4386                 if(el.lastChild){
4387                     range.setStartAfter(el.lastChild);
4388                     frag = range.createContextualFragment(html);
4389                     el.appendChild(frag);
4390                     return el.lastChild;
4391                 }else{
4392                     el.innerHTML = html;
4393                     return el.lastChild;
4394                 }
4395             case "afterend":
4396                 range.setStartAfter(el);
4397                 frag = range.createContextualFragment(html);
4398                 el.parentNode.insertBefore(frag, el.nextSibling);
4399                 return el.nextSibling;
4400             }
4401             throw 'Illegal insertion point -> "' + where + '"';
4402     },
4403
4404     /**
4405      * Creates new Dom element(s) and inserts them before el
4406      * @param {String/HTMLElement/Element} el The context element
4407      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4408      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4409      * @return {HTMLElement/Roo.Element} The new node
4410      */
4411     insertBefore : function(el, o, returnElement){
4412         return this.doInsert(el, o, returnElement, "beforeBegin");
4413     },
4414
4415     /**
4416      * Creates new Dom element(s) and inserts them after el
4417      * @param {String/HTMLElement/Element} el The context element
4418      * @param {Object} o The Dom object spec (and children)
4419      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4420      * @return {HTMLElement/Roo.Element} The new node
4421      */
4422     insertAfter : function(el, o, returnElement){
4423         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4424     },
4425
4426     /**
4427      * Creates new Dom element(s) and inserts them as the first child of el
4428      * @param {String/HTMLElement/Element} el The context element
4429      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4430      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4431      * @return {HTMLElement/Roo.Element} The new node
4432      */
4433     insertFirst : function(el, o, returnElement){
4434         return this.doInsert(el, o, returnElement, "afterBegin");
4435     },
4436
4437     // private
4438     doInsert : function(el, o, returnElement, pos, sibling){
4439         el = Roo.getDom(el);
4440         var newNode;
4441         if(this.useDom || o.ns){
4442             newNode = createDom(o, null);
4443             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4444         }else{
4445             var html = createHtml(o);
4446             newNode = this.insertHtml(pos, el, html);
4447         }
4448         return returnElement ? Roo.get(newNode, true) : newNode;
4449     },
4450
4451     /**
4452      * Creates new Dom element(s) and appends them to el
4453      * @param {String/HTMLElement/Element} el The context element
4454      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4455      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4456      * @return {HTMLElement/Roo.Element} The new node
4457      */
4458     append : function(el, o, returnElement){
4459         el = Roo.getDom(el);
4460         var newNode;
4461         if(this.useDom || o.ns){
4462             newNode = createDom(o, null);
4463             el.appendChild(newNode);
4464         }else{
4465             var html = createHtml(o);
4466             newNode = this.insertHtml("beforeEnd", el, html);
4467         }
4468         return returnElement ? Roo.get(newNode, true) : newNode;
4469     },
4470
4471     /**
4472      * Creates new Dom element(s) and overwrites the contents of el with them
4473      * @param {String/HTMLElement/Element} el The context element
4474      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476      * @return {HTMLElement/Roo.Element} The new node
4477      */
4478     overwrite : function(el, o, returnElement){
4479         el = Roo.getDom(el);
4480         if (o.ns) {
4481           
4482             while (el.childNodes.length) {
4483                 el.removeChild(el.firstChild);
4484             }
4485             createDom(o, el);
4486         } else {
4487             el.innerHTML = createHtml(o);   
4488         }
4489         
4490         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4491     },
4492
4493     /**
4494      * Creates a new Roo.DomHelper.Template from the Dom object spec
4495      * @param {Object} o The Dom object spec (and children)
4496      * @return {Roo.DomHelper.Template} The new template
4497      */
4498     createTemplate : function(o){
4499         var html = createHtml(o);
4500         return new Roo.Template(html);
4501     }
4502     };
4503 }();
4504 /*
4505  * Based on:
4506  * Ext JS Library 1.1.1
4507  * Copyright(c) 2006-2007, Ext JS, LLC.
4508  *
4509  * Originally Released Under LGPL - original licence link has changed is not relivant.
4510  *
4511  * Fork - LGPL
4512  * <script type="text/javascript">
4513  */
4514  
4515 /**
4516 * @class Roo.Template
4517 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4518 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4519 * Usage:
4520 <pre><code>
4521 var t = new Roo.Template({
4522     html :  '&lt;div name="{id}"&gt;' + 
4523         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4524         '&lt;/div&gt;',
4525     myformat: function (value, allValues) {
4526         return 'XX' + value;
4527     }
4528 });
4529 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4530 </code></pre>
4531 * 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>. 
4532 * @constructor
4533 * @param {Object} cfg - Configuration object.
4534 */
4535 Roo.Template = function(cfg){
4536     // BC!
4537     if(cfg instanceof Array){
4538         cfg = cfg.join("");
4539     }else if(arguments.length > 1){
4540         cfg = Array.prototype.join.call(arguments, "");
4541     }
4542     
4543     
4544     if (typeof(cfg) == 'object') {
4545         Roo.apply(this,cfg)
4546     } else {
4547         // bc
4548         this.html = cfg;
4549     }
4550     
4551     
4552 };
4553 Roo.Template.prototype = {
4554     
4555     /**
4556      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4557      */
4558     html : '',
4559     /**
4560      * Returns an HTML fragment of this template with the specified values applied.
4561      * @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'})
4562      * @return {String} The HTML fragment
4563      */
4564     applyTemplate : function(values){
4565         try {
4566             
4567             if(this.compiled){
4568                 return this.compiled(values);
4569             }
4570             var useF = this.disableFormats !== true;
4571             var fm = Roo.util.Format, tpl = this;
4572             var fn = function(m, name, format, args){
4573                 if(format && useF){
4574                     if(format.substr(0, 5) == "this."){
4575                         return tpl.call(format.substr(5), values[name], values);
4576                     }else{
4577                         if(args){
4578                             // quoted values are required for strings in compiled templates, 
4579                             // but for non compiled we need to strip them
4580                             // quoted reversed for jsmin
4581                             var re = /^\s*['"](.*)["']\s*$/;
4582                             args = args.split(',');
4583                             for(var i = 0, len = args.length; i < len; i++){
4584                                 args[i] = args[i].replace(re, "$1");
4585                             }
4586                             args = [values[name]].concat(args);
4587                         }else{
4588                             args = [values[name]];
4589                         }
4590                         return fm[format].apply(fm, args);
4591                     }
4592                 }else{
4593                     return values[name] !== undefined ? values[name] : "";
4594                 }
4595             };
4596             return this.html.replace(this.re, fn);
4597         } catch (e) {
4598             Roo.log(e);
4599             throw e;
4600         }
4601          
4602     },
4603     
4604     /**
4605      * Sets the HTML used as the template and optionally compiles it.
4606      * @param {String} html
4607      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4608      * @return {Roo.Template} this
4609      */
4610     set : function(html, compile){
4611         this.html = html;
4612         this.compiled = null;
4613         if(compile){
4614             this.compile();
4615         }
4616         return this;
4617     },
4618     
4619     /**
4620      * True to disable format functions (defaults to false)
4621      * @type Boolean
4622      */
4623     disableFormats : false,
4624     
4625     /**
4626     * The regular expression used to match template variables 
4627     * @type RegExp
4628     * @property 
4629     */
4630     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4631     
4632     /**
4633      * Compiles the template into an internal function, eliminating the RegEx overhead.
4634      * @return {Roo.Template} this
4635      */
4636     compile : function(){
4637         var fm = Roo.util.Format;
4638         var useF = this.disableFormats !== true;
4639         var sep = Roo.isGecko ? "+" : ",";
4640         var fn = function(m, name, format, args){
4641             if(format && useF){
4642                 args = args ? ',' + args : "";
4643                 if(format.substr(0, 5) != "this."){
4644                     format = "fm." + format + '(';
4645                 }else{
4646                     format = 'this.call("'+ format.substr(5) + '", ';
4647                     args = ", values";
4648                 }
4649             }else{
4650                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4651             }
4652             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4653         };
4654         var body;
4655         // branched to use + in gecko and [].join() in others
4656         if(Roo.isGecko){
4657             body = "this.compiled = function(values){ return '" +
4658                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4659                     "';};";
4660         }else{
4661             body = ["this.compiled = function(values){ return ['"];
4662             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4663             body.push("'].join('');};");
4664             body = body.join('');
4665         }
4666         /**
4667          * eval:var:values
4668          * eval:var:fm
4669          */
4670         eval(body);
4671         return this;
4672     },
4673     
4674     // private function used to call members
4675     call : function(fnName, value, allValues){
4676         return this[fnName](value, allValues);
4677     },
4678     
4679     /**
4680      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4681      * @param {String/HTMLElement/Roo.Element} el The context element
4682      * @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'})
4683      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4684      * @return {HTMLElement/Roo.Element} The new node or Element
4685      */
4686     insertFirst: function(el, values, returnElement){
4687         return this.doInsert('afterBegin', el, values, returnElement);
4688     },
4689
4690     /**
4691      * Applies the supplied values to the template and inserts the new node(s) before el.
4692      * @param {String/HTMLElement/Roo.Element} el The context element
4693      * @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'})
4694      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4695      * @return {HTMLElement/Roo.Element} The new node or Element
4696      */
4697     insertBefore: function(el, values, returnElement){
4698         return this.doInsert('beforeBegin', el, values, returnElement);
4699     },
4700
4701     /**
4702      * Applies the supplied values to the template and inserts the new node(s) after el.
4703      * @param {String/HTMLElement/Roo.Element} el The context element
4704      * @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'})
4705      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4706      * @return {HTMLElement/Roo.Element} The new node or Element
4707      */
4708     insertAfter : function(el, values, returnElement){
4709         return this.doInsert('afterEnd', el, values, returnElement);
4710     },
4711     
4712     /**
4713      * Applies the supplied values to the template and appends the new node(s) to el.
4714      * @param {String/HTMLElement/Roo.Element} el The context element
4715      * @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'})
4716      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4717      * @return {HTMLElement/Roo.Element} The new node or Element
4718      */
4719     append : function(el, values, returnElement){
4720         return this.doInsert('beforeEnd', el, values, returnElement);
4721     },
4722
4723     doInsert : function(where, el, values, returnEl){
4724         el = Roo.getDom(el);
4725         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4726         return returnEl ? Roo.get(newNode, true) : newNode;
4727     },
4728
4729     /**
4730      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4731      * @param {String/HTMLElement/Roo.Element} el The context element
4732      * @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'})
4733      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4734      * @return {HTMLElement/Roo.Element} The new node or Element
4735      */
4736     overwrite : function(el, values, returnElement){
4737         el = Roo.getDom(el);
4738         el.innerHTML = this.applyTemplate(values);
4739         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4740     }
4741 };
4742 /**
4743  * Alias for {@link #applyTemplate}
4744  * @method
4745  */
4746 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4747
4748 // backwards compat
4749 Roo.DomHelper.Template = Roo.Template;
4750
4751 /**
4752  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4753  * @param {String/HTMLElement} el A DOM element or its id
4754  * @returns {Roo.Template} The created template
4755  * @static
4756  */
4757 Roo.Template.from = function(el){
4758     el = Roo.getDom(el);
4759     return new Roo.Template(el.value || el.innerHTML);
4760 };/*
4761  * Based on:
4762  * Ext JS Library 1.1.1
4763  * Copyright(c) 2006-2007, Ext JS, LLC.
4764  *
4765  * Originally Released Under LGPL - original licence link has changed is not relivant.
4766  *
4767  * Fork - LGPL
4768  * <script type="text/javascript">
4769  */
4770  
4771
4772 /*
4773  * This is code is also distributed under MIT license for use
4774  * with jQuery and prototype JavaScript libraries.
4775  */
4776 /**
4777  * @class Roo.DomQuery
4778 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).
4779 <p>
4780 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>
4781
4782 <p>
4783 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.
4784 </p>
4785 <h4>Element Selectors:</h4>
4786 <ul class="list">
4787     <li> <b>*</b> any element</li>
4788     <li> <b>E</b> an element with the tag E</li>
4789     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4790     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4791     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4792     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4793 </ul>
4794 <h4>Attribute Selectors:</h4>
4795 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4796 <ul class="list">
4797     <li> <b>E[foo]</b> has an attribute "foo"</li>
4798     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4799     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4800     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4801     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4802     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4803     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4804 </ul>
4805 <h4>Pseudo Classes:</h4>
4806 <ul class="list">
4807     <li> <b>E:first-child</b> E is the first child of its parent</li>
4808     <li> <b>E:last-child</b> E is the last child of its parent</li>
4809     <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>
4810     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4811     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4812     <li> <b>E:only-child</b> E is the only child of its parent</li>
4813     <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>
4814     <li> <b>E:first</b> the first E in the resultset</li>
4815     <li> <b>E:last</b> the last E in the resultset</li>
4816     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4817     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4818     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4819     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4820     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4821     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4822     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4823     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4824     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4825 </ul>
4826 <h4>CSS Value Selectors:</h4>
4827 <ul class="list">
4828     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4829     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4830     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4831     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4832     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4833     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4834 </ul>
4835  * @singleton
4836  */
4837 Roo.DomQuery = function(){
4838     var cache = {}, simpleCache = {}, valueCache = {};
4839     var nonSpace = /\S/;
4840     var trimRe = /^\s+|\s+$/g;
4841     var tplRe = /\{(\d+)\}/g;
4842     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4843     var tagTokenRe = /^(#)?([\w-\*]+)/;
4844     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4845
4846     function child(p, index){
4847         var i = 0;
4848         var n = p.firstChild;
4849         while(n){
4850             if(n.nodeType == 1){
4851                if(++i == index){
4852                    return n;
4853                }
4854             }
4855             n = n.nextSibling;
4856         }
4857         return null;
4858     };
4859
4860     function next(n){
4861         while((n = n.nextSibling) && n.nodeType != 1);
4862         return n;
4863     };
4864
4865     function prev(n){
4866         while((n = n.previousSibling) && n.nodeType != 1);
4867         return n;
4868     };
4869
4870     function children(d){
4871         var n = d.firstChild, ni = -1;
4872             while(n){
4873                 var nx = n.nextSibling;
4874                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4875                     d.removeChild(n);
4876                 }else{
4877                     n.nodeIndex = ++ni;
4878                 }
4879                 n = nx;
4880             }
4881             return this;
4882         };
4883
4884     function byClassName(c, a, v){
4885         if(!v){
4886             return c;
4887         }
4888         var r = [], ri = -1, cn;
4889         for(var i = 0, ci; ci = c[i]; i++){
4890             if((' '+ci.className+' ').indexOf(v) != -1){
4891                 r[++ri] = ci;
4892             }
4893         }
4894         return r;
4895     };
4896
4897     function attrValue(n, attr){
4898         if(!n.tagName && typeof n.length != "undefined"){
4899             n = n[0];
4900         }
4901         if(!n){
4902             return null;
4903         }
4904         if(attr == "for"){
4905             return n.htmlFor;
4906         }
4907         if(attr == "class" || attr == "className"){
4908             return n.className;
4909         }
4910         return n.getAttribute(attr) || n[attr];
4911
4912     };
4913
4914     function getNodes(ns, mode, tagName){
4915         var result = [], ri = -1, cs;
4916         if(!ns){
4917             return result;
4918         }
4919         tagName = tagName || "*";
4920         if(typeof ns.getElementsByTagName != "undefined"){
4921             ns = [ns];
4922         }
4923         if(!mode){
4924             for(var i = 0, ni; ni = ns[i]; i++){
4925                 cs = ni.getElementsByTagName(tagName);
4926                 for(var j = 0, ci; ci = cs[j]; j++){
4927                     result[++ri] = ci;
4928                 }
4929             }
4930         }else if(mode == "/" || mode == ">"){
4931             var utag = tagName.toUpperCase();
4932             for(var i = 0, ni, cn; ni = ns[i]; i++){
4933                 cn = ni.children || ni.childNodes;
4934                 for(var j = 0, cj; cj = cn[j]; j++){
4935                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4936                         result[++ri] = cj;
4937                     }
4938                 }
4939             }
4940         }else if(mode == "+"){
4941             var utag = tagName.toUpperCase();
4942             for(var i = 0, n; n = ns[i]; i++){
4943                 while((n = n.nextSibling) && n.nodeType != 1);
4944                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4945                     result[++ri] = n;
4946                 }
4947             }
4948         }else if(mode == "~"){
4949             for(var i = 0, n; n = ns[i]; i++){
4950                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4951                 if(n){
4952                     result[++ri] = n;
4953                 }
4954             }
4955         }
4956         return result;
4957     };
4958
4959     function concat(a, b){
4960         if(b.slice){
4961             return a.concat(b);
4962         }
4963         for(var i = 0, l = b.length; i < l; i++){
4964             a[a.length] = b[i];
4965         }
4966         return a;
4967     }
4968
4969     function byTag(cs, tagName){
4970         if(cs.tagName || cs == document){
4971             cs = [cs];
4972         }
4973         if(!tagName){
4974             return cs;
4975         }
4976         var r = [], ri = -1;
4977         tagName = tagName.toLowerCase();
4978         for(var i = 0, ci; ci = cs[i]; i++){
4979             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4980                 r[++ri] = ci;
4981             }
4982         }
4983         return r;
4984     };
4985
4986     function byId(cs, attr, id){
4987         if(cs.tagName || cs == document){
4988             cs = [cs];
4989         }
4990         if(!id){
4991             return cs;
4992         }
4993         var r = [], ri = -1;
4994         for(var i = 0,ci; ci = cs[i]; i++){
4995             if(ci && ci.id == id){
4996                 r[++ri] = ci;
4997                 return r;
4998             }
4999         }
5000         return r;
5001     };
5002
5003     function byAttribute(cs, attr, value, op, custom){
5004         var r = [], ri = -1, st = custom=="{";
5005         var f = Roo.DomQuery.operators[op];
5006         for(var i = 0, ci; ci = cs[i]; i++){
5007             var a;
5008             if(st){
5009                 a = Roo.DomQuery.getStyle(ci, attr);
5010             }
5011             else if(attr == "class" || attr == "className"){
5012                 a = ci.className;
5013             }else if(attr == "for"){
5014                 a = ci.htmlFor;
5015             }else if(attr == "href"){
5016                 a = ci.getAttribute("href", 2);
5017             }else{
5018                 a = ci.getAttribute(attr);
5019             }
5020             if((f && f(a, value)) || (!f && a)){
5021                 r[++ri] = ci;
5022             }
5023         }
5024         return r;
5025     };
5026
5027     function byPseudo(cs, name, value){
5028         return Roo.DomQuery.pseudos[name](cs, value);
5029     };
5030
5031     // This is for IE MSXML which does not support expandos.
5032     // IE runs the same speed using setAttribute, however FF slows way down
5033     // and Safari completely fails so they need to continue to use expandos.
5034     var isIE = window.ActiveXObject ? true : false;
5035
5036     // this eval is stop the compressor from
5037     // renaming the variable to something shorter
5038     
5039     /** eval:var:batch */
5040     var batch = 30803; 
5041
5042     var key = 30803;
5043
5044     function nodupIEXml(cs){
5045         var d = ++key;
5046         cs[0].setAttribute("_nodup", d);
5047         var r = [cs[0]];
5048         for(var i = 1, len = cs.length; i < len; i++){
5049             var c = cs[i];
5050             if(!c.getAttribute("_nodup") != d){
5051                 c.setAttribute("_nodup", d);
5052                 r[r.length] = c;
5053             }
5054         }
5055         for(var i = 0, len = cs.length; i < len; i++){
5056             cs[i].removeAttribute("_nodup");
5057         }
5058         return r;
5059     }
5060
5061     function nodup(cs){
5062         if(!cs){
5063             return [];
5064         }
5065         var len = cs.length, c, i, r = cs, cj, ri = -1;
5066         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5067             return cs;
5068         }
5069         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5070             return nodupIEXml(cs);
5071         }
5072         var d = ++key;
5073         cs[0]._nodup = d;
5074         for(i = 1; c = cs[i]; i++){
5075             if(c._nodup != d){
5076                 c._nodup = d;
5077             }else{
5078                 r = [];
5079                 for(var j = 0; j < i; j++){
5080                     r[++ri] = cs[j];
5081                 }
5082                 for(j = i+1; cj = cs[j]; j++){
5083                     if(cj._nodup != d){
5084                         cj._nodup = d;
5085                         r[++ri] = cj;
5086                     }
5087                 }
5088                 return r;
5089             }
5090         }
5091         return r;
5092     }
5093
5094     function quickDiffIEXml(c1, c2){
5095         var d = ++key;
5096         for(var i = 0, len = c1.length; i < len; i++){
5097             c1[i].setAttribute("_qdiff", d);
5098         }
5099         var r = [];
5100         for(var i = 0, len = c2.length; i < len; i++){
5101             if(c2[i].getAttribute("_qdiff") != d){
5102                 r[r.length] = c2[i];
5103             }
5104         }
5105         for(var i = 0, len = c1.length; i < len; i++){
5106            c1[i].removeAttribute("_qdiff");
5107         }
5108         return r;
5109     }
5110
5111     function quickDiff(c1, c2){
5112         var len1 = c1.length;
5113         if(!len1){
5114             return c2;
5115         }
5116         if(isIE && c1[0].selectSingleNode){
5117             return quickDiffIEXml(c1, c2);
5118         }
5119         var d = ++key;
5120         for(var i = 0; i < len1; i++){
5121             c1[i]._qdiff = d;
5122         }
5123         var r = [];
5124         for(var i = 0, len = c2.length; i < len; i++){
5125             if(c2[i]._qdiff != d){
5126                 r[r.length] = c2[i];
5127             }
5128         }
5129         return r;
5130     }
5131
5132     function quickId(ns, mode, root, id){
5133         if(ns == root){
5134            var d = root.ownerDocument || root;
5135            return d.getElementById(id);
5136         }
5137         ns = getNodes(ns, mode, "*");
5138         return byId(ns, null, id);
5139     }
5140
5141     return {
5142         getStyle : function(el, name){
5143             return Roo.fly(el).getStyle(name);
5144         },
5145         /**
5146          * Compiles a selector/xpath query into a reusable function. The returned function
5147          * takes one parameter "root" (optional), which is the context node from where the query should start.
5148          * @param {String} selector The selector/xpath query
5149          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5150          * @return {Function}
5151          */
5152         compile : function(path, type){
5153             type = type || "select";
5154             
5155             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5156             var q = path, mode, lq;
5157             var tk = Roo.DomQuery.matchers;
5158             var tklen = tk.length;
5159             var mm;
5160
5161             // accept leading mode switch
5162             var lmode = q.match(modeRe);
5163             if(lmode && lmode[1]){
5164                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5165                 q = q.replace(lmode[1], "");
5166             }
5167             // strip leading slashes
5168             while(path.substr(0, 1)=="/"){
5169                 path = path.substr(1);
5170             }
5171
5172             while(q && lq != q){
5173                 lq = q;
5174                 var tm = q.match(tagTokenRe);
5175                 if(type == "select"){
5176                     if(tm){
5177                         if(tm[1] == "#"){
5178                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5179                         }else{
5180                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5181                         }
5182                         q = q.replace(tm[0], "");
5183                     }else if(q.substr(0, 1) != '@'){
5184                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5185                     }
5186                 }else{
5187                     if(tm){
5188                         if(tm[1] == "#"){
5189                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5190                         }else{
5191                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5192                         }
5193                         q = q.replace(tm[0], "");
5194                     }
5195                 }
5196                 while(!(mm = q.match(modeRe))){
5197                     var matched = false;
5198                     for(var j = 0; j < tklen; j++){
5199                         var t = tk[j];
5200                         var m = q.match(t.re);
5201                         if(m){
5202                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5203                                                     return m[i];
5204                                                 });
5205                             q = q.replace(m[0], "");
5206                             matched = true;
5207                             break;
5208                         }
5209                     }
5210                     // prevent infinite loop on bad selector
5211                     if(!matched){
5212                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5213                     }
5214                 }
5215                 if(mm[1]){
5216                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5217                     q = q.replace(mm[1], "");
5218                 }
5219             }
5220             fn[fn.length] = "return nodup(n);\n}";
5221             
5222              /** 
5223               * list of variables that need from compression as they are used by eval.
5224              *  eval:var:batch 
5225              *  eval:var:nodup
5226              *  eval:var:byTag
5227              *  eval:var:ById
5228              *  eval:var:getNodes
5229              *  eval:var:quickId
5230              *  eval:var:mode
5231              *  eval:var:root
5232              *  eval:var:n
5233              *  eval:var:byClassName
5234              *  eval:var:byPseudo
5235              *  eval:var:byAttribute
5236              *  eval:var:attrValue
5237              * 
5238              **/ 
5239             eval(fn.join(""));
5240             return f;
5241         },
5242
5243         /**
5244          * Selects a group of elements.
5245          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5246          * @param {Node} root (optional) The start of the query (defaults to document).
5247          * @return {Array}
5248          */
5249         select : function(path, root, type){
5250             if(!root || root == document){
5251                 root = document;
5252             }
5253             if(typeof root == "string"){
5254                 root = document.getElementById(root);
5255             }
5256             var paths = path.split(",");
5257             var results = [];
5258             for(var i = 0, len = paths.length; i < len; i++){
5259                 var p = paths[i].replace(trimRe, "");
5260                 if(!cache[p]){
5261                     cache[p] = Roo.DomQuery.compile(p);
5262                     if(!cache[p]){
5263                         throw p + " is not a valid selector";
5264                     }
5265                 }
5266                 var result = cache[p](root);
5267                 if(result && result != document){
5268                     results = results.concat(result);
5269                 }
5270             }
5271             if(paths.length > 1){
5272                 return nodup(results);
5273             }
5274             return results;
5275         },
5276
5277         /**
5278          * Selects a single element.
5279          * @param {String} selector The selector/xpath query
5280          * @param {Node} root (optional) The start of the query (defaults to document).
5281          * @return {Element}
5282          */
5283         selectNode : function(path, root){
5284             return Roo.DomQuery.select(path, root)[0];
5285         },
5286
5287         /**
5288          * Selects the value of a node, optionally replacing null with the defaultValue.
5289          * @param {String} selector The selector/xpath query
5290          * @param {Node} root (optional) The start of the query (defaults to document).
5291          * @param {String} defaultValue
5292          */
5293         selectValue : function(path, root, defaultValue){
5294             path = path.replace(trimRe, "");
5295             if(!valueCache[path]){
5296                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5297             }
5298             var n = valueCache[path](root);
5299             n = n[0] ? n[0] : n;
5300             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5301             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5302         },
5303
5304         /**
5305          * Selects the value of a node, parsing integers and floats.
5306          * @param {String} selector The selector/xpath query
5307          * @param {Node} root (optional) The start of the query (defaults to document).
5308          * @param {Number} defaultValue
5309          * @return {Number}
5310          */
5311         selectNumber : function(path, root, defaultValue){
5312             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5313             return parseFloat(v);
5314         },
5315
5316         /**
5317          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5318          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5319          * @param {String} selector The simple selector to test
5320          * @return {Boolean}
5321          */
5322         is : function(el, ss){
5323             if(typeof el == "string"){
5324                 el = document.getElementById(el);
5325             }
5326             var isArray = (el instanceof Array);
5327             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5328             return isArray ? (result.length == el.length) : (result.length > 0);
5329         },
5330
5331         /**
5332          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5333          * @param {Array} el An array of elements to filter
5334          * @param {String} selector The simple selector to test
5335          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5336          * the selector instead of the ones that match
5337          * @return {Array}
5338          */
5339         filter : function(els, ss, nonMatches){
5340             ss = ss.replace(trimRe, "");
5341             if(!simpleCache[ss]){
5342                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5343             }
5344             var result = simpleCache[ss](els);
5345             return nonMatches ? quickDiff(result, els) : result;
5346         },
5347
5348         /**
5349          * Collection of matching regular expressions and code snippets.
5350          */
5351         matchers : [{
5352                 re: /^\.([\w-]+)/,
5353                 select: 'n = byClassName(n, null, " {1} ");'
5354             }, {
5355                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5356                 select: 'n = byPseudo(n, "{1}", "{2}");'
5357             },{
5358                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5359                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5360             }, {
5361                 re: /^#([\w-]+)/,
5362                 select: 'n = byId(n, null, "{1}");'
5363             },{
5364                 re: /^@([\w-]+)/,
5365                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5366             }
5367         ],
5368
5369         /**
5370          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5371          * 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;.
5372          */
5373         operators : {
5374             "=" : function(a, v){
5375                 return a == v;
5376             },
5377             "!=" : function(a, v){
5378                 return a != v;
5379             },
5380             "^=" : function(a, v){
5381                 return a && a.substr(0, v.length) == v;
5382             },
5383             "$=" : function(a, v){
5384                 return a && a.substr(a.length-v.length) == v;
5385             },
5386             "*=" : function(a, v){
5387                 return a && a.indexOf(v) !== -1;
5388             },
5389             "%=" : function(a, v){
5390                 return (a % v) == 0;
5391             },
5392             "|=" : function(a, v){
5393                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5394             },
5395             "~=" : function(a, v){
5396                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5397             }
5398         },
5399
5400         /**
5401          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5402          * and the argument (if any) supplied in the selector.
5403          */
5404         pseudos : {
5405             "first-child" : function(c){
5406                 var r = [], ri = -1, n;
5407                 for(var i = 0, ci; ci = n = c[i]; i++){
5408                     while((n = n.previousSibling) && n.nodeType != 1);
5409                     if(!n){
5410                         r[++ri] = ci;
5411                     }
5412                 }
5413                 return r;
5414             },
5415
5416             "last-child" : function(c){
5417                 var r = [], ri = -1, n;
5418                 for(var i = 0, ci; ci = n = c[i]; i++){
5419                     while((n = n.nextSibling) && n.nodeType != 1);
5420                     if(!n){
5421                         r[++ri] = ci;
5422                     }
5423                 }
5424                 return r;
5425             },
5426
5427             "nth-child" : function(c, a) {
5428                 var r = [], ri = -1;
5429                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5430                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5431                 for(var i = 0, n; n = c[i]; i++){
5432                     var pn = n.parentNode;
5433                     if (batch != pn._batch) {
5434                         var j = 0;
5435                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5436                             if(cn.nodeType == 1){
5437                                cn.nodeIndex = ++j;
5438                             }
5439                         }
5440                         pn._batch = batch;
5441                     }
5442                     if (f == 1) {
5443                         if (l == 0 || n.nodeIndex == l){
5444                             r[++ri] = n;
5445                         }
5446                     } else if ((n.nodeIndex + l) % f == 0){
5447                         r[++ri] = n;
5448                     }
5449                 }
5450
5451                 return r;
5452             },
5453
5454             "only-child" : function(c){
5455                 var r = [], ri = -1;;
5456                 for(var i = 0, ci; ci = c[i]; i++){
5457                     if(!prev(ci) && !next(ci)){
5458                         r[++ri] = ci;
5459                     }
5460                 }
5461                 return r;
5462             },
5463
5464             "empty" : function(c){
5465                 var r = [], ri = -1;
5466                 for(var i = 0, ci; ci = c[i]; i++){
5467                     var cns = ci.childNodes, j = 0, cn, empty = true;
5468                     while(cn = cns[j]){
5469                         ++j;
5470                         if(cn.nodeType == 1 || cn.nodeType == 3){
5471                             empty = false;
5472                             break;
5473                         }
5474                     }
5475                     if(empty){
5476                         r[++ri] = ci;
5477                     }
5478                 }
5479                 return r;
5480             },
5481
5482             "contains" : function(c, v){
5483                 var r = [], ri = -1;
5484                 for(var i = 0, ci; ci = c[i]; i++){
5485                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5486                         r[++ri] = ci;
5487                     }
5488                 }
5489                 return r;
5490             },
5491
5492             "nodeValue" : function(c, v){
5493                 var r = [], ri = -1;
5494                 for(var i = 0, ci; ci = c[i]; i++){
5495                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5496                         r[++ri] = ci;
5497                     }
5498                 }
5499                 return r;
5500             },
5501
5502             "checked" : function(c){
5503                 var r = [], ri = -1;
5504                 for(var i = 0, ci; ci = c[i]; i++){
5505                     if(ci.checked == true){
5506                         r[++ri] = ci;
5507                     }
5508                 }
5509                 return r;
5510             },
5511
5512             "not" : function(c, ss){
5513                 return Roo.DomQuery.filter(c, ss, true);
5514             },
5515
5516             "odd" : function(c){
5517                 return this["nth-child"](c, "odd");
5518             },
5519
5520             "even" : function(c){
5521                 return this["nth-child"](c, "even");
5522             },
5523
5524             "nth" : function(c, a){
5525                 return c[a-1] || [];
5526             },
5527
5528             "first" : function(c){
5529                 return c[0] || [];
5530             },
5531
5532             "last" : function(c){
5533                 return c[c.length-1] || [];
5534             },
5535
5536             "has" : function(c, ss){
5537                 var s = Roo.DomQuery.select;
5538                 var r = [], ri = -1;
5539                 for(var i = 0, ci; ci = c[i]; i++){
5540                     if(s(ss, ci).length > 0){
5541                         r[++ri] = ci;
5542                     }
5543                 }
5544                 return r;
5545             },
5546
5547             "next" : function(c, ss){
5548                 var is = Roo.DomQuery.is;
5549                 var r = [], ri = -1;
5550                 for(var i = 0, ci; ci = c[i]; i++){
5551                     var n = next(ci);
5552                     if(n && is(n, ss)){
5553                         r[++ri] = ci;
5554                     }
5555                 }
5556                 return r;
5557             },
5558
5559             "prev" : function(c, ss){
5560                 var is = Roo.DomQuery.is;
5561                 var r = [], ri = -1;
5562                 for(var i = 0, ci; ci = c[i]; i++){
5563                     var n = prev(ci);
5564                     if(n && is(n, ss)){
5565                         r[++ri] = ci;
5566                     }
5567                 }
5568                 return r;
5569             }
5570         }
5571     };
5572 }();
5573
5574 /**
5575  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5576  * @param {String} path The selector/xpath query
5577  * @param {Node} root (optional) The start of the query (defaults to document).
5578  * @return {Array}
5579  * @member Roo
5580  * @method query
5581  */
5582 Roo.query = Roo.DomQuery.select;
5583 /*
5584  * Based on:
5585  * Ext JS Library 1.1.1
5586  * Copyright(c) 2006-2007, Ext JS, LLC.
5587  *
5588  * Originally Released Under LGPL - original licence link has changed is not relivant.
5589  *
5590  * Fork - LGPL
5591  * <script type="text/javascript">
5592  */
5593
5594 /**
5595  * @class Roo.util.Observable
5596  * Base class that provides a common interface for publishing events. Subclasses are expected to
5597  * to have a property "events" with all the events defined.<br>
5598  * For example:
5599  * <pre><code>
5600  Employee = function(name){
5601     this.name = name;
5602     this.addEvents({
5603         "fired" : true,
5604         "quit" : true
5605     });
5606  }
5607  Roo.extend(Employee, Roo.util.Observable);
5608 </code></pre>
5609  * @param {Object} config properties to use (incuding events / listeners)
5610  */
5611
5612 Roo.util.Observable = function(cfg){
5613     
5614     cfg = cfg|| {};
5615     this.addEvents(cfg.events || {});
5616     if (cfg.events) {
5617         delete cfg.events; // make sure
5618     }
5619      
5620     Roo.apply(this, cfg);
5621     
5622     if(this.listeners){
5623         this.on(this.listeners);
5624         delete this.listeners;
5625     }
5626 };
5627 Roo.util.Observable.prototype = {
5628     /** 
5629  * @cfg {Object} listeners  list of events and functions to call for this object, 
5630  * For example :
5631  * <pre><code>
5632     listeners :  { 
5633        'click' : function(e) {
5634            ..... 
5635         } ,
5636         .... 
5637     } 
5638   </code></pre>
5639  */
5640     
5641     
5642     /**
5643      * Fires the specified event with the passed parameters (minus the event name).
5644      * @param {String} eventName
5645      * @param {Object...} args Variable number of parameters are passed to handlers
5646      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5647      */
5648     fireEvent : function(){
5649         var ce = this.events[arguments[0].toLowerCase()];
5650         if(typeof ce == "object"){
5651             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5652         }else{
5653             return true;
5654         }
5655     },
5656
5657     // private
5658     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5659
5660     /**
5661      * Appends an event handler to this component
5662      * @param {String}   eventName The type of event to listen for
5663      * @param {Function} handler The method the event invokes
5664      * @param {Object}   scope (optional) The scope in which to execute the handler
5665      * function. The handler function's "this" context.
5666      * @param {Object}   options (optional) An object containing handler configuration
5667      * properties. This may contain any of the following properties:<ul>
5668      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5669      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5670      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5671      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5672      * by the specified number of milliseconds. If the event fires again within that time, the original
5673      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5674      * </ul><br>
5675      * <p>
5676      * <b>Combining Options</b><br>
5677      * Using the options argument, it is possible to combine different types of listeners:<br>
5678      * <br>
5679      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5680                 <pre><code>
5681                 el.on('click', this.onClick, this, {
5682                         single: true,
5683                 delay: 100,
5684                 forumId: 4
5685                 });
5686                 </code></pre>
5687      * <p>
5688      * <b>Attaching multiple handlers in 1 call</b><br>
5689      * The method also allows for a single argument to be passed which is a config object containing properties
5690      * which specify multiple handlers.
5691      * <pre><code>
5692                 el.on({
5693                         'click': {
5694                         fn: this.onClick,
5695                         scope: this,
5696                         delay: 100
5697                 }, 
5698                 'mouseover': {
5699                         fn: this.onMouseOver,
5700                         scope: this
5701                 },
5702                 'mouseout': {
5703                         fn: this.onMouseOut,
5704                         scope: this
5705                 }
5706                 });
5707                 </code></pre>
5708      * <p>
5709      * Or a shorthand syntax which passes the same scope object to all handlers:
5710         <pre><code>
5711                 el.on({
5712                         'click': this.onClick,
5713                 'mouseover': this.onMouseOver,
5714                 'mouseout': this.onMouseOut,
5715                 scope: this
5716                 });
5717                 </code></pre>
5718      */
5719     addListener : function(eventName, fn, scope, o){
5720         if(typeof eventName == "object"){
5721             o = eventName;
5722             for(var e in o){
5723                 if(this.filterOptRe.test(e)){
5724                     continue;
5725                 }
5726                 if(typeof o[e] == "function"){
5727                     // shared options
5728                     this.addListener(e, o[e], o.scope,  o);
5729                 }else{
5730                     // individual options
5731                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5732                 }
5733             }
5734             return;
5735         }
5736         o = (!o || typeof o == "boolean") ? {} : o;
5737         eventName = eventName.toLowerCase();
5738         var ce = this.events[eventName] || true;
5739         if(typeof ce == "boolean"){
5740             ce = new Roo.util.Event(this, eventName);
5741             this.events[eventName] = ce;
5742         }
5743         ce.addListener(fn, scope, o);
5744     },
5745
5746     /**
5747      * Removes a listener
5748      * @param {String}   eventName     The type of event to listen for
5749      * @param {Function} handler        The handler to remove
5750      * @param {Object}   scope  (optional) The scope (this object) for the handler
5751      */
5752     removeListener : function(eventName, fn, scope){
5753         var ce = this.events[eventName.toLowerCase()];
5754         if(typeof ce == "object"){
5755             ce.removeListener(fn, scope);
5756         }
5757     },
5758
5759     /**
5760      * Removes all listeners for this object
5761      */
5762     purgeListeners : function(){
5763         for(var evt in this.events){
5764             if(typeof this.events[evt] == "object"){
5765                  this.events[evt].clearListeners();
5766             }
5767         }
5768     },
5769
5770     relayEvents : function(o, events){
5771         var createHandler = function(ename){
5772             return function(){
5773                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5774             };
5775         };
5776         for(var i = 0, len = events.length; i < len; i++){
5777             var ename = events[i];
5778             if(!this.events[ename]){ this.events[ename] = true; };
5779             o.on(ename, createHandler(ename), this);
5780         }
5781     },
5782
5783     /**
5784      * Used to define events on this Observable
5785      * @param {Object} object The object with the events defined
5786      */
5787     addEvents : function(o){
5788         if(!this.events){
5789             this.events = {};
5790         }
5791         Roo.applyIf(this.events, o);
5792     },
5793
5794     /**
5795      * Checks to see if this object has any listeners for a specified event
5796      * @param {String} eventName The name of the event to check for
5797      * @return {Boolean} True if the event is being listened for, else false
5798      */
5799     hasListener : function(eventName){
5800         var e = this.events[eventName];
5801         return typeof e == "object" && e.listeners.length > 0;
5802     }
5803 };
5804 /**
5805  * Appends an event handler to this element (shorthand for addListener)
5806  * @param {String}   eventName     The type of event to listen for
5807  * @param {Function} handler        The method the event invokes
5808  * @param {Object}   scope (optional) The scope in which to execute the handler
5809  * function. The handler function's "this" context.
5810  * @param {Object}   options  (optional)
5811  * @method
5812  */
5813 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5814 /**
5815  * Removes a listener (shorthand for removeListener)
5816  * @param {String}   eventName     The type of event to listen for
5817  * @param {Function} handler        The handler to remove
5818  * @param {Object}   scope  (optional) The scope (this object) for the handler
5819  * @method
5820  */
5821 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5822
5823 /**
5824  * Starts capture on the specified Observable. All events will be passed
5825  * to the supplied function with the event name + standard signature of the event
5826  * <b>before</b> the event is fired. If the supplied function returns false,
5827  * the event will not fire.
5828  * @param {Observable} o The Observable to capture
5829  * @param {Function} fn The function to call
5830  * @param {Object} scope (optional) The scope (this object) for the fn
5831  * @static
5832  */
5833 Roo.util.Observable.capture = function(o, fn, scope){
5834     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5835 };
5836
5837 /**
5838  * Removes <b>all</b> added captures from the Observable.
5839  * @param {Observable} o The Observable to release
5840  * @static
5841  */
5842 Roo.util.Observable.releaseCapture = function(o){
5843     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5844 };
5845
5846 (function(){
5847
5848     var createBuffered = function(h, o, scope){
5849         var task = new Roo.util.DelayedTask();
5850         return function(){
5851             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5852         };
5853     };
5854
5855     var createSingle = function(h, e, fn, scope){
5856         return function(){
5857             e.removeListener(fn, scope);
5858             return h.apply(scope, arguments);
5859         };
5860     };
5861
5862     var createDelayed = function(h, o, scope){
5863         return function(){
5864             var args = Array.prototype.slice.call(arguments, 0);
5865             setTimeout(function(){
5866                 h.apply(scope, args);
5867             }, o.delay || 10);
5868         };
5869     };
5870
5871     Roo.util.Event = function(obj, name){
5872         this.name = name;
5873         this.obj = obj;
5874         this.listeners = [];
5875     };
5876
5877     Roo.util.Event.prototype = {
5878         addListener : function(fn, scope, options){
5879             var o = options || {};
5880             scope = scope || this.obj;
5881             if(!this.isListening(fn, scope)){
5882                 var l = {fn: fn, scope: scope, options: o};
5883                 var h = fn;
5884                 if(o.delay){
5885                     h = createDelayed(h, o, scope);
5886                 }
5887                 if(o.single){
5888                     h = createSingle(h, this, fn, scope);
5889                 }
5890                 if(o.buffer){
5891                     h = createBuffered(h, o, scope);
5892                 }
5893                 l.fireFn = h;
5894                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5895                     this.listeners.push(l);
5896                 }else{
5897                     this.listeners = this.listeners.slice(0);
5898                     this.listeners.push(l);
5899                 }
5900             }
5901         },
5902
5903         findListener : function(fn, scope){
5904             scope = scope || this.obj;
5905             var ls = this.listeners;
5906             for(var i = 0, len = ls.length; i < len; i++){
5907                 var l = ls[i];
5908                 if(l.fn == fn && l.scope == scope){
5909                     return i;
5910                 }
5911             }
5912             return -1;
5913         },
5914
5915         isListening : function(fn, scope){
5916             return this.findListener(fn, scope) != -1;
5917         },
5918
5919         removeListener : function(fn, scope){
5920             var index;
5921             if((index = this.findListener(fn, scope)) != -1){
5922                 if(!this.firing){
5923                     this.listeners.splice(index, 1);
5924                 }else{
5925                     this.listeners = this.listeners.slice(0);
5926                     this.listeners.splice(index, 1);
5927                 }
5928                 return true;
5929             }
5930             return false;
5931         },
5932
5933         clearListeners : function(){
5934             this.listeners = [];
5935         },
5936
5937         fire : function(){
5938             var ls = this.listeners, scope, len = ls.length;
5939             if(len > 0){
5940                 this.firing = true;
5941                 var args = Array.prototype.slice.call(arguments, 0);
5942                 for(var i = 0; i < len; i++){
5943                     var l = ls[i];
5944                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5945                         this.firing = false;
5946                         return false;
5947                     }
5948                 }
5949                 this.firing = false;
5950             }
5951             return true;
5952         }
5953     };
5954 })();/*
5955  * Based on:
5956  * Ext JS Library 1.1.1
5957  * Copyright(c) 2006-2007, Ext JS, LLC.
5958  *
5959  * Originally Released Under LGPL - original licence link has changed is not relivant.
5960  *
5961  * Fork - LGPL
5962  * <script type="text/javascript">
5963  */
5964
5965 /**
5966  * @class Roo.EventManager
5967  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5968  * several useful events directly.
5969  * See {@link Roo.EventObject} for more details on normalized event objects.
5970  * @singleton
5971  */
5972 Roo.EventManager = function(){
5973     var docReadyEvent, docReadyProcId, docReadyState = false;
5974     var resizeEvent, resizeTask, textEvent, textSize;
5975     var E = Roo.lib.Event;
5976     var D = Roo.lib.Dom;
5977
5978
5979     var fireDocReady = function(){
5980         if(!docReadyState){
5981             docReadyState = true;
5982             Roo.isReady = true;
5983             if(docReadyProcId){
5984                 clearInterval(docReadyProcId);
5985             }
5986             if(Roo.isGecko || Roo.isOpera) {
5987                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5988             }
5989             if(Roo.isIE){
5990                 var defer = document.getElementById("ie-deferred-loader");
5991                 if(defer){
5992                     defer.onreadystatechange = null;
5993                     defer.parentNode.removeChild(defer);
5994                 }
5995             }
5996             if(docReadyEvent){
5997                 docReadyEvent.fire();
5998                 docReadyEvent.clearListeners();
5999             }
6000         }
6001     };
6002     
6003     var initDocReady = function(){
6004         docReadyEvent = new Roo.util.Event();
6005         if(Roo.isGecko || Roo.isOpera) {
6006             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6007         }else if(Roo.isIE){
6008             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6009             var defer = document.getElementById("ie-deferred-loader");
6010             defer.onreadystatechange = function(){
6011                 if(this.readyState == "complete"){
6012                     fireDocReady();
6013                 }
6014             };
6015         }else if(Roo.isSafari){ 
6016             docReadyProcId = setInterval(function(){
6017                 var rs = document.readyState;
6018                 if(rs == "complete") {
6019                     fireDocReady();     
6020                  }
6021             }, 10);
6022         }
6023         // no matter what, make sure it fires on load
6024         E.on(window, "load", fireDocReady);
6025     };
6026
6027     var createBuffered = function(h, o){
6028         var task = new Roo.util.DelayedTask(h);
6029         return function(e){
6030             // create new event object impl so new events don't wipe out properties
6031             e = new Roo.EventObjectImpl(e);
6032             task.delay(o.buffer, h, null, [e]);
6033         };
6034     };
6035
6036     var createSingle = function(h, el, ename, fn){
6037         return function(e){
6038             Roo.EventManager.removeListener(el, ename, fn);
6039             h(e);
6040         };
6041     };
6042
6043     var createDelayed = function(h, o){
6044         return function(e){
6045             // create new event object impl so new events don't wipe out properties
6046             e = new Roo.EventObjectImpl(e);
6047             setTimeout(function(){
6048                 h(e);
6049             }, o.delay || 10);
6050         };
6051     };
6052
6053     var listen = function(element, ename, opt, fn, scope){
6054         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6055         fn = fn || o.fn; scope = scope || o.scope;
6056         var el = Roo.getDom(element);
6057         if(!el){
6058             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6059         }
6060         var h = function(e){
6061             e = Roo.EventObject.setEvent(e);
6062             var t;
6063             if(o.delegate){
6064                 t = e.getTarget(o.delegate, el);
6065                 if(!t){
6066                     return;
6067                 }
6068             }else{
6069                 t = e.target;
6070             }
6071             if(o.stopEvent === true){
6072                 e.stopEvent();
6073             }
6074             if(o.preventDefault === true){
6075                e.preventDefault();
6076             }
6077             if(o.stopPropagation === true){
6078                 e.stopPropagation();
6079             }
6080
6081             if(o.normalized === false){
6082                 e = e.browserEvent;
6083             }
6084
6085             fn.call(scope || el, e, t, o);
6086         };
6087         if(o.delay){
6088             h = createDelayed(h, o);
6089         }
6090         if(o.single){
6091             h = createSingle(h, el, ename, fn);
6092         }
6093         if(o.buffer){
6094             h = createBuffered(h, o);
6095         }
6096         fn._handlers = fn._handlers || [];
6097         fn._handlers.push([Roo.id(el), ename, h]);
6098
6099         E.on(el, ename, h);
6100         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6101             el.addEventListener("DOMMouseScroll", h, false);
6102             E.on(window, 'unload', function(){
6103                 el.removeEventListener("DOMMouseScroll", h, false);
6104             });
6105         }
6106         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6107             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6108         }
6109         return h;
6110     };
6111
6112     var stopListening = function(el, ename, fn){
6113         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6114         if(hds){
6115             for(var i = 0, len = hds.length; i < len; i++){
6116                 var h = hds[i];
6117                 if(h[0] == id && h[1] == ename){
6118                     hd = h[2];
6119                     hds.splice(i, 1);
6120                     break;
6121                 }
6122             }
6123         }
6124         E.un(el, ename, hd);
6125         el = Roo.getDom(el);
6126         if(ename == "mousewheel" && el.addEventListener){
6127             el.removeEventListener("DOMMouseScroll", hd, false);
6128         }
6129         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6130             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6131         }
6132     };
6133
6134     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6135     
6136     var pub = {
6137         
6138         
6139         /** 
6140          * Fix for doc tools
6141          * @scope Roo.EventManager
6142          */
6143         
6144         
6145         /** 
6146          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6147          * object with a Roo.EventObject
6148          * @param {Function} fn        The method the event invokes
6149          * @param {Object}   scope    An object that becomes the scope of the handler
6150          * @param {boolean}  override If true, the obj passed in becomes
6151          *                             the execution scope of the listener
6152          * @return {Function} The wrapped function
6153          * @deprecated
6154          */
6155         wrap : function(fn, scope, override){
6156             return function(e){
6157                 Roo.EventObject.setEvent(e);
6158                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6159             };
6160         },
6161         
6162         /**
6163      * Appends an event handler to an element (shorthand for addListener)
6164      * @param {String/HTMLElement}   element        The html element or id to assign the
6165      * @param {String}   eventName The type of event to listen for
6166      * @param {Function} handler The method the event invokes
6167      * @param {Object}   scope (optional) The scope in which to execute the handler
6168      * function. The handler function's "this" context.
6169      * @param {Object}   options (optional) An object containing handler configuration
6170      * properties. This may contain any of the following properties:<ul>
6171      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6172      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6173      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6174      * <li>preventDefault {Boolean} True to prevent the default action</li>
6175      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6176      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6177      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6178      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6179      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6180      * by the specified number of milliseconds. If the event fires again within that time, the original
6181      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6182      * </ul><br>
6183      * <p>
6184      * <b>Combining Options</b><br>
6185      * Using the options argument, it is possible to combine different types of listeners:<br>
6186      * <br>
6187      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6188      * Code:<pre><code>
6189 el.on('click', this.onClick, this, {
6190     single: true,
6191     delay: 100,
6192     stopEvent : true,
6193     forumId: 4
6194 });</code></pre>
6195      * <p>
6196      * <b>Attaching multiple handlers in 1 call</b><br>
6197       * The method also allows for a single argument to be passed which is a config object containing properties
6198      * which specify multiple handlers.
6199      * <p>
6200      * Code:<pre><code>
6201 el.on({
6202     'click' : {
6203         fn: this.onClick
6204         scope: this,
6205         delay: 100
6206     },
6207     'mouseover' : {
6208         fn: this.onMouseOver
6209         scope: this
6210     },
6211     'mouseout' : {
6212         fn: this.onMouseOut
6213         scope: this
6214     }
6215 });</code></pre>
6216      * <p>
6217      * Or a shorthand syntax:<br>
6218      * Code:<pre><code>
6219 el.on({
6220     'click' : this.onClick,
6221     'mouseover' : this.onMouseOver,
6222     'mouseout' : this.onMouseOut
6223     scope: this
6224 });</code></pre>
6225      */
6226         addListener : function(element, eventName, fn, scope, options){
6227             if(typeof eventName == "object"){
6228                 var o = eventName;
6229                 for(var e in o){
6230                     if(propRe.test(e)){
6231                         continue;
6232                     }
6233                     if(typeof o[e] == "function"){
6234                         // shared options
6235                         listen(element, e, o, o[e], o.scope);
6236                     }else{
6237                         // individual options
6238                         listen(element, e, o[e]);
6239                     }
6240                 }
6241                 return;
6242             }
6243             return listen(element, eventName, options, fn, scope);
6244         },
6245         
6246         /**
6247          * Removes an event handler
6248          *
6249          * @param {String/HTMLElement}   element        The id or html element to remove the 
6250          *                             event from
6251          * @param {String}   eventName     The type of event
6252          * @param {Function} fn
6253          * @return {Boolean} True if a listener was actually removed
6254          */
6255         removeListener : function(element, eventName, fn){
6256             return stopListening(element, eventName, fn);
6257         },
6258         
6259         /**
6260          * Fires when the document is ready (before onload and before images are loaded). Can be 
6261          * accessed shorthanded Roo.onReady().
6262          * @param {Function} fn        The method the event invokes
6263          * @param {Object}   scope    An  object that becomes the scope of the handler
6264          * @param {boolean}  options
6265          */
6266         onDocumentReady : function(fn, scope, options){
6267             if(docReadyState){ // if it already fired
6268                 docReadyEvent.addListener(fn, scope, options);
6269                 docReadyEvent.fire();
6270                 docReadyEvent.clearListeners();
6271                 return;
6272             }
6273             if(!docReadyEvent){
6274                 initDocReady();
6275             }
6276             docReadyEvent.addListener(fn, scope, options);
6277         },
6278         
6279         /**
6280          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6281          * @param {Function} fn        The method the event invokes
6282          * @param {Object}   scope    An object that becomes the scope of the handler
6283          * @param {boolean}  options
6284          */
6285         onWindowResize : function(fn, scope, options){
6286             if(!resizeEvent){
6287                 resizeEvent = new Roo.util.Event();
6288                 resizeTask = new Roo.util.DelayedTask(function(){
6289                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6290                 });
6291                 E.on(window, "resize", function(){
6292                     if(Roo.isIE){
6293                         resizeTask.delay(50);
6294                     }else{
6295                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6296                     }
6297                 });
6298             }
6299             resizeEvent.addListener(fn, scope, options);
6300         },
6301
6302         /**
6303          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6304          * @param {Function} fn        The method the event invokes
6305          * @param {Object}   scope    An object that becomes the scope of the handler
6306          * @param {boolean}  options
6307          */
6308         onTextResize : function(fn, scope, options){
6309             if(!textEvent){
6310                 textEvent = new Roo.util.Event();
6311                 var textEl = new Roo.Element(document.createElement('div'));
6312                 textEl.dom.className = 'x-text-resize';
6313                 textEl.dom.innerHTML = 'X';
6314                 textEl.appendTo(document.body);
6315                 textSize = textEl.dom.offsetHeight;
6316                 setInterval(function(){
6317                     if(textEl.dom.offsetHeight != textSize){
6318                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6319                     }
6320                 }, this.textResizeInterval);
6321             }
6322             textEvent.addListener(fn, scope, options);
6323         },
6324
6325         /**
6326          * Removes the passed window resize listener.
6327          * @param {Function} fn        The method the event invokes
6328          * @param {Object}   scope    The scope of handler
6329          */
6330         removeResizeListener : function(fn, scope){
6331             if(resizeEvent){
6332                 resizeEvent.removeListener(fn, scope);
6333             }
6334         },
6335
6336         // private
6337         fireResize : function(){
6338             if(resizeEvent){
6339                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6340             }   
6341         },
6342         /**
6343          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6344          */
6345         ieDeferSrc : false,
6346         /**
6347          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6348          */
6349         textResizeInterval : 50
6350     };
6351     
6352     /**
6353      * Fix for doc tools
6354      * @scopeAlias pub=Roo.EventManager
6355      */
6356     
6357      /**
6358      * Appends an event handler to an element (shorthand for addListener)
6359      * @param {String/HTMLElement}   element        The html element or id to assign the
6360      * @param {String}   eventName The type of event to listen for
6361      * @param {Function} handler The method the event invokes
6362      * @param {Object}   scope (optional) The scope in which to execute the handler
6363      * function. The handler function's "this" context.
6364      * @param {Object}   options (optional) An object containing handler configuration
6365      * properties. This may contain any of the following properties:<ul>
6366      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6367      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6368      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6369      * <li>preventDefault {Boolean} True to prevent the default action</li>
6370      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6371      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6372      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6373      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6374      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6375      * by the specified number of milliseconds. If the event fires again within that time, the original
6376      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6377      * </ul><br>
6378      * <p>
6379      * <b>Combining Options</b><br>
6380      * Using the options argument, it is possible to combine different types of listeners:<br>
6381      * <br>
6382      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6383      * Code:<pre><code>
6384 el.on('click', this.onClick, this, {
6385     single: true,
6386     delay: 100,
6387     stopEvent : true,
6388     forumId: 4
6389 });</code></pre>
6390      * <p>
6391      * <b>Attaching multiple handlers in 1 call</b><br>
6392       * The method also allows for a single argument to be passed which is a config object containing properties
6393      * which specify multiple handlers.
6394      * <p>
6395      * Code:<pre><code>
6396 el.on({
6397     'click' : {
6398         fn: this.onClick
6399         scope: this,
6400         delay: 100
6401     },
6402     'mouseover' : {
6403         fn: this.onMouseOver
6404         scope: this
6405     },
6406     'mouseout' : {
6407         fn: this.onMouseOut
6408         scope: this
6409     }
6410 });</code></pre>
6411      * <p>
6412      * Or a shorthand syntax:<br>
6413      * Code:<pre><code>
6414 el.on({
6415     'click' : this.onClick,
6416     'mouseover' : this.onMouseOver,
6417     'mouseout' : this.onMouseOut
6418     scope: this
6419 });</code></pre>
6420      */
6421     pub.on = pub.addListener;
6422     pub.un = pub.removeListener;
6423
6424     pub.stoppedMouseDownEvent = new Roo.util.Event();
6425     return pub;
6426 }();
6427 /**
6428   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6429   * @param {Function} fn        The method the event invokes
6430   * @param {Object}   scope    An  object that becomes the scope of the handler
6431   * @param {boolean}  override If true, the obj passed in becomes
6432   *                             the execution scope of the listener
6433   * @member Roo
6434   * @method onReady
6435  */
6436 Roo.onReady = Roo.EventManager.onDocumentReady;
6437
6438 Roo.onReady(function(){
6439     var bd = Roo.get(document.body);
6440     if(!bd){ return; }
6441
6442     var cls = [
6443             Roo.isIE ? "roo-ie"
6444             : Roo.isGecko ? "roo-gecko"
6445             : Roo.isOpera ? "roo-opera"
6446             : Roo.isSafari ? "roo-safari" : ""];
6447
6448     if(Roo.isMac){
6449         cls.push("roo-mac");
6450     }
6451     if(Roo.isLinux){
6452         cls.push("roo-linux");
6453     }
6454     if(Roo.isBorderBox){
6455         cls.push('roo-border-box');
6456     }
6457     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6458         var p = bd.dom.parentNode;
6459         if(p){
6460             p.className += ' roo-strict';
6461         }
6462     }
6463     bd.addClass(cls.join(' '));
6464 });
6465
6466 /**
6467  * @class Roo.EventObject
6468  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6469  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6470  * Example:
6471  * <pre><code>
6472  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6473     e.preventDefault();
6474     var target = e.getTarget();
6475     ...
6476  }
6477  var myDiv = Roo.get("myDiv");
6478  myDiv.on("click", handleClick);
6479  //or
6480  Roo.EventManager.on("myDiv", 'click', handleClick);
6481  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6482  </code></pre>
6483  * @singleton
6484  */
6485 Roo.EventObject = function(){
6486     
6487     var E = Roo.lib.Event;
6488     
6489     // safari keypress events for special keys return bad keycodes
6490     var safariKeys = {
6491         63234 : 37, // left
6492         63235 : 39, // right
6493         63232 : 38, // up
6494         63233 : 40, // down
6495         63276 : 33, // page up
6496         63277 : 34, // page down
6497         63272 : 46, // delete
6498         63273 : 36, // home
6499         63275 : 35  // end
6500     };
6501
6502     // normalize button clicks
6503     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6504                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6505
6506     Roo.EventObjectImpl = function(e){
6507         if(e){
6508             this.setEvent(e.browserEvent || e);
6509         }
6510     };
6511     Roo.EventObjectImpl.prototype = {
6512         /**
6513          * Used to fix doc tools.
6514          * @scope Roo.EventObject.prototype
6515          */
6516             
6517
6518         
6519         
6520         /** The normal browser event */
6521         browserEvent : null,
6522         /** The button pressed in a mouse event */
6523         button : -1,
6524         /** True if the shift key was down during the event */
6525         shiftKey : false,
6526         /** True if the control key was down during the event */
6527         ctrlKey : false,
6528         /** True if the alt key was down during the event */
6529         altKey : false,
6530
6531         /** Key constant 
6532         * @type Number */
6533         BACKSPACE : 8,
6534         /** Key constant 
6535         * @type Number */
6536         TAB : 9,
6537         /** Key constant 
6538         * @type Number */
6539         RETURN : 13,
6540         /** Key constant 
6541         * @type Number */
6542         ENTER : 13,
6543         /** Key constant 
6544         * @type Number */
6545         SHIFT : 16,
6546         /** Key constant 
6547         * @type Number */
6548         CONTROL : 17,
6549         /** Key constant 
6550         * @type Number */
6551         ESC : 27,
6552         /** Key constant 
6553         * @type Number */
6554         SPACE : 32,
6555         /** Key constant 
6556         * @type Number */
6557         PAGEUP : 33,
6558         /** Key constant 
6559         * @type Number */
6560         PAGEDOWN : 34,
6561         /** Key constant 
6562         * @type Number */
6563         END : 35,
6564         /** Key constant 
6565         * @type Number */
6566         HOME : 36,
6567         /** Key constant 
6568         * @type Number */
6569         LEFT : 37,
6570         /** Key constant 
6571         * @type Number */
6572         UP : 38,
6573         /** Key constant 
6574         * @type Number */
6575         RIGHT : 39,
6576         /** Key constant 
6577         * @type Number */
6578         DOWN : 40,
6579         /** Key constant 
6580         * @type Number */
6581         DELETE : 46,
6582         /** Key constant 
6583         * @type Number */
6584         F5 : 116,
6585
6586            /** @private */
6587         setEvent : function(e){
6588             if(e == this || (e && e.browserEvent)){ // already wrapped
6589                 return e;
6590             }
6591             this.browserEvent = e;
6592             if(e){
6593                 // normalize buttons
6594                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6595                 if(e.type == 'click' && this.button == -1){
6596                     this.button = 0;
6597                 }
6598                 this.type = e.type;
6599                 this.shiftKey = e.shiftKey;
6600                 // mac metaKey behaves like ctrlKey
6601                 this.ctrlKey = e.ctrlKey || e.metaKey;
6602                 this.altKey = e.altKey;
6603                 // in getKey these will be normalized for the mac
6604                 this.keyCode = e.keyCode;
6605                 // keyup warnings on firefox.
6606                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6607                 // cache the target for the delayed and or buffered events
6608                 this.target = E.getTarget(e);
6609                 // same for XY
6610                 this.xy = E.getXY(e);
6611             }else{
6612                 this.button = -1;
6613                 this.shiftKey = false;
6614                 this.ctrlKey = false;
6615                 this.altKey = false;
6616                 this.keyCode = 0;
6617                 this.charCode =0;
6618                 this.target = null;
6619                 this.xy = [0, 0];
6620             }
6621             return this;
6622         },
6623
6624         /**
6625          * Stop the event (preventDefault and stopPropagation)
6626          */
6627         stopEvent : function(){
6628             if(this.browserEvent){
6629                 if(this.browserEvent.type == 'mousedown'){
6630                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6631                 }
6632                 E.stopEvent(this.browserEvent);
6633             }
6634         },
6635
6636         /**
6637          * Prevents the browsers default handling of the event.
6638          */
6639         preventDefault : function(){
6640             if(this.browserEvent){
6641                 E.preventDefault(this.browserEvent);
6642             }
6643         },
6644
6645         /** @private */
6646         isNavKeyPress : function(){
6647             var k = this.keyCode;
6648             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6649             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6650         },
6651
6652         isSpecialKey : function(){
6653             var k = this.keyCode;
6654             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6655             (k == 16) || (k == 17) ||
6656             (k >= 18 && k <= 20) ||
6657             (k >= 33 && k <= 35) ||
6658             (k >= 36 && k <= 39) ||
6659             (k >= 44 && k <= 45);
6660         },
6661         /**
6662          * Cancels bubbling of the event.
6663          */
6664         stopPropagation : function(){
6665             if(this.browserEvent){
6666                 if(this.type == 'mousedown'){
6667                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6668                 }
6669                 E.stopPropagation(this.browserEvent);
6670             }
6671         },
6672
6673         /**
6674          * Gets the key code for the event.
6675          * @return {Number}
6676          */
6677         getCharCode : function(){
6678             return this.charCode || this.keyCode;
6679         },
6680
6681         /**
6682          * Returns a normalized keyCode for the event.
6683          * @return {Number} The key code
6684          */
6685         getKey : function(){
6686             var k = this.keyCode || this.charCode;
6687             return Roo.isSafari ? (safariKeys[k] || k) : k;
6688         },
6689
6690         /**
6691          * Gets the x coordinate of the event.
6692          * @return {Number}
6693          */
6694         getPageX : function(){
6695             return this.xy[0];
6696         },
6697
6698         /**
6699          * Gets the y coordinate of the event.
6700          * @return {Number}
6701          */
6702         getPageY : function(){
6703             return this.xy[1];
6704         },
6705
6706         /**
6707          * Gets the time of the event.
6708          * @return {Number}
6709          */
6710         getTime : function(){
6711             if(this.browserEvent){
6712                 return E.getTime(this.browserEvent);
6713             }
6714             return null;
6715         },
6716
6717         /**
6718          * Gets the page coordinates of the event.
6719          * @return {Array} The xy values like [x, y]
6720          */
6721         getXY : function(){
6722             return this.xy;
6723         },
6724
6725         /**
6726          * Gets the target for the event.
6727          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6728          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6729                 search as a number or element (defaults to 10 || document.body)
6730          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6731          * @return {HTMLelement}
6732          */
6733         getTarget : function(selector, maxDepth, returnEl){
6734             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6735         },
6736         /**
6737          * Gets the related target.
6738          * @return {HTMLElement}
6739          */
6740         getRelatedTarget : function(){
6741             if(this.browserEvent){
6742                 return E.getRelatedTarget(this.browserEvent);
6743             }
6744             return null;
6745         },
6746
6747         /**
6748          * Normalizes mouse wheel delta across browsers
6749          * @return {Number} The delta
6750          */
6751         getWheelDelta : function(){
6752             var e = this.browserEvent;
6753             var delta = 0;
6754             if(e.wheelDelta){ /* IE/Opera. */
6755                 delta = e.wheelDelta/120;
6756             }else if(e.detail){ /* Mozilla case. */
6757                 delta = -e.detail/3;
6758             }
6759             return delta;
6760         },
6761
6762         /**
6763          * Returns true if the control, meta, shift or alt key was pressed during this event.
6764          * @return {Boolean}
6765          */
6766         hasModifier : function(){
6767             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6768         },
6769
6770         /**
6771          * Returns true if the target of this event equals el or is a child of el
6772          * @param {String/HTMLElement/Element} el
6773          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6774          * @return {Boolean}
6775          */
6776         within : function(el, related){
6777             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6778             return t && Roo.fly(el).contains(t);
6779         },
6780
6781         getPoint : function(){
6782             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6783         }
6784     };
6785
6786     return new Roo.EventObjectImpl();
6787 }();
6788             
6789     /*
6790  * Based on:
6791  * Ext JS Library 1.1.1
6792  * Copyright(c) 2006-2007, Ext JS, LLC.
6793  *
6794  * Originally Released Under LGPL - original licence link has changed is not relivant.
6795  *
6796  * Fork - LGPL
6797  * <script type="text/javascript">
6798  */
6799
6800  
6801 // was in Composite Element!??!?!
6802  
6803 (function(){
6804     var D = Roo.lib.Dom;
6805     var E = Roo.lib.Event;
6806     var A = Roo.lib.Anim;
6807
6808     // local style camelizing for speed
6809     var propCache = {};
6810     var camelRe = /(-[a-z])/gi;
6811     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6812     var view = document.defaultView;
6813
6814 /**
6815  * @class Roo.Element
6816  * Represents an Element in the DOM.<br><br>
6817  * Usage:<br>
6818 <pre><code>
6819 var el = Roo.get("my-div");
6820
6821 // or with getEl
6822 var el = getEl("my-div");
6823
6824 // or with a DOM element
6825 var el = Roo.get(myDivElement);
6826 </code></pre>
6827  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6828  * each call instead of constructing a new one.<br><br>
6829  * <b>Animations</b><br />
6830  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6831  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6832 <pre>
6833 Option    Default   Description
6834 --------- --------  ---------------------------------------------
6835 duration  .35       The duration of the animation in seconds
6836 easing    easeOut   The YUI easing method
6837 callback  none      A function to execute when the anim completes
6838 scope     this      The scope (this) of the callback function
6839 </pre>
6840 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6841 * manipulate the animation. Here's an example:
6842 <pre><code>
6843 var el = Roo.get("my-div");
6844
6845 // no animation
6846 el.setWidth(100);
6847
6848 // default animation
6849 el.setWidth(100, true);
6850
6851 // animation with some options set
6852 el.setWidth(100, {
6853     duration: 1,
6854     callback: this.foo,
6855     scope: this
6856 });
6857
6858 // using the "anim" property to get the Anim object
6859 var opt = {
6860     duration: 1,
6861     callback: this.foo,
6862     scope: this
6863 };
6864 el.setWidth(100, opt);
6865 ...
6866 if(opt.anim.isAnimated()){
6867     opt.anim.stop();
6868 }
6869 </code></pre>
6870 * <b> Composite (Collections of) Elements</b><br />
6871  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6872  * @constructor Create a new Element directly.
6873  * @param {String/HTMLElement} element
6874  * @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).
6875  */
6876     Roo.Element = function(element, forceNew){
6877         var dom = typeof element == "string" ?
6878                 document.getElementById(element) : element;
6879         if(!dom){ // invalid id/element
6880             return null;
6881         }
6882         var id = dom.id;
6883         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6884             return Roo.Element.cache[id];
6885         }
6886
6887         /**
6888          * The DOM element
6889          * @type HTMLElement
6890          */
6891         this.dom = dom;
6892
6893         /**
6894          * The DOM element ID
6895          * @type String
6896          */
6897         this.id = id || Roo.id(dom);
6898     };
6899
6900     var El = Roo.Element;
6901
6902     El.prototype = {
6903         /**
6904          * The element's default display mode  (defaults to "")
6905          * @type String
6906          */
6907         originalDisplay : "",
6908
6909         visibilityMode : 1,
6910         /**
6911          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6912          * @type String
6913          */
6914         defaultUnit : "px",
6915         /**
6916          * Sets the element's visibility mode. When setVisible() is called it
6917          * will use this to determine whether to set the visibility or the display property.
6918          * @param visMode Element.VISIBILITY or Element.DISPLAY
6919          * @return {Roo.Element} this
6920          */
6921         setVisibilityMode : function(visMode){
6922             this.visibilityMode = visMode;
6923             return this;
6924         },
6925         /**
6926          * Convenience method for setVisibilityMode(Element.DISPLAY)
6927          * @param {String} display (optional) What to set display to when visible
6928          * @return {Roo.Element} this
6929          */
6930         enableDisplayMode : function(display){
6931             this.setVisibilityMode(El.DISPLAY);
6932             if(typeof display != "undefined") this.originalDisplay = display;
6933             return this;
6934         },
6935
6936         /**
6937          * 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)
6938          * @param {String} selector The simple selector to test
6939          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6940                 search as a number or element (defaults to 10 || document.body)
6941          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6942          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6943          */
6944         findParent : function(simpleSelector, maxDepth, returnEl){
6945             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6946             maxDepth = maxDepth || 50;
6947             if(typeof maxDepth != "number"){
6948                 stopEl = Roo.getDom(maxDepth);
6949                 maxDepth = 10;
6950             }
6951             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6952                 if(dq.is(p, simpleSelector)){
6953                     return returnEl ? Roo.get(p) : p;
6954                 }
6955                 depth++;
6956                 p = p.parentNode;
6957             }
6958             return null;
6959         },
6960
6961
6962         /**
6963          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6964          * @param {String} selector The simple selector to test
6965          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6966                 search as a number or element (defaults to 10 || document.body)
6967          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6968          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6969          */
6970         findParentNode : function(simpleSelector, maxDepth, returnEl){
6971             var p = Roo.fly(this.dom.parentNode, '_internal');
6972             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6973         },
6974
6975         /**
6976          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6977          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6978          * @param {String} selector The simple selector to test
6979          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6980                 search as a number or element (defaults to 10 || document.body)
6981          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6982          */
6983         up : function(simpleSelector, maxDepth){
6984             return this.findParentNode(simpleSelector, maxDepth, true);
6985         },
6986
6987
6988
6989         /**
6990          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6991          * @param {String} selector The simple selector to test
6992          * @return {Boolean} True if this element matches the selector, else false
6993          */
6994         is : function(simpleSelector){
6995             return Roo.DomQuery.is(this.dom, simpleSelector);
6996         },
6997
6998         /**
6999          * Perform animation on this element.
7000          * @param {Object} args The YUI animation control args
7001          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7002          * @param {Function} onComplete (optional) Function to call when animation completes
7003          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7004          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7005          * @return {Roo.Element} this
7006          */
7007         animate : function(args, duration, onComplete, easing, animType){
7008             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7009             return this;
7010         },
7011
7012         /*
7013          * @private Internal animation call
7014          */
7015         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7016             animType = animType || 'run';
7017             opt = opt || {};
7018             var anim = Roo.lib.Anim[animType](
7019                 this.dom, args,
7020                 (opt.duration || defaultDur) || .35,
7021                 (opt.easing || defaultEase) || 'easeOut',
7022                 function(){
7023                     Roo.callback(cb, this);
7024                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7025                 },
7026                 this
7027             );
7028             opt.anim = anim;
7029             return anim;
7030         },
7031
7032         // private legacy anim prep
7033         preanim : function(a, i){
7034             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7035         },
7036
7037         /**
7038          * Removes worthless text nodes
7039          * @param {Boolean} forceReclean (optional) By default the element
7040          * keeps track if it has been cleaned already so
7041          * you can call this over and over. However, if you update the element and
7042          * need to force a reclean, you can pass true.
7043          */
7044         clean : function(forceReclean){
7045             if(this.isCleaned && forceReclean !== true){
7046                 return this;
7047             }
7048             var ns = /\S/;
7049             var d = this.dom, n = d.firstChild, ni = -1;
7050             while(n){
7051                 var nx = n.nextSibling;
7052                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7053                     d.removeChild(n);
7054                 }else{
7055                     n.nodeIndex = ++ni;
7056                 }
7057                 n = nx;
7058             }
7059             this.isCleaned = true;
7060             return this;
7061         },
7062
7063         // private
7064         calcOffsetsTo : function(el){
7065             el = Roo.get(el);
7066             var d = el.dom;
7067             var restorePos = false;
7068             if(el.getStyle('position') == 'static'){
7069                 el.position('relative');
7070                 restorePos = true;
7071             }
7072             var x = 0, y =0;
7073             var op = this.dom;
7074             while(op && op != d && op.tagName != 'HTML'){
7075                 x+= op.offsetLeft;
7076                 y+= op.offsetTop;
7077                 op = op.offsetParent;
7078             }
7079             if(restorePos){
7080                 el.position('static');
7081             }
7082             return [x, y];
7083         },
7084
7085         /**
7086          * Scrolls this element into view within the passed container.
7087          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7088          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7089          * @return {Roo.Element} this
7090          */
7091         scrollIntoView : function(container, hscroll){
7092             var c = Roo.getDom(container) || document.body;
7093             var el = this.dom;
7094
7095             var o = this.calcOffsetsTo(c),
7096                 l = o[0],
7097                 t = o[1],
7098                 b = t+el.offsetHeight,
7099                 r = l+el.offsetWidth;
7100
7101             var ch = c.clientHeight;
7102             var ct = parseInt(c.scrollTop, 10);
7103             var cl = parseInt(c.scrollLeft, 10);
7104             var cb = ct + ch;
7105             var cr = cl + c.clientWidth;
7106
7107             if(t < ct){
7108                 c.scrollTop = t;
7109             }else if(b > cb){
7110                 c.scrollTop = b-ch;
7111             }
7112
7113             if(hscroll !== false){
7114                 if(l < cl){
7115                     c.scrollLeft = l;
7116                 }else if(r > cr){
7117                     c.scrollLeft = r-c.clientWidth;
7118                 }
7119             }
7120             return this;
7121         },
7122
7123         // private
7124         scrollChildIntoView : function(child, hscroll){
7125             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7126         },
7127
7128         /**
7129          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7130          * the new height may not be available immediately.
7131          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7132          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7133          * @param {Function} onComplete (optional) Function to call when animation completes
7134          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7135          * @return {Roo.Element} this
7136          */
7137         autoHeight : function(animate, duration, onComplete, easing){
7138             var oldHeight = this.getHeight();
7139             this.clip();
7140             this.setHeight(1); // force clipping
7141             setTimeout(function(){
7142                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7143                 if(!animate){
7144                     this.setHeight(height);
7145                     this.unclip();
7146                     if(typeof onComplete == "function"){
7147                         onComplete();
7148                     }
7149                 }else{
7150                     this.setHeight(oldHeight); // restore original height
7151                     this.setHeight(height, animate, duration, function(){
7152                         this.unclip();
7153                         if(typeof onComplete == "function") onComplete();
7154                     }.createDelegate(this), easing);
7155                 }
7156             }.createDelegate(this), 0);
7157             return this;
7158         },
7159
7160         /**
7161          * Returns true if this element is an ancestor of the passed element
7162          * @param {HTMLElement/String} el The element to check
7163          * @return {Boolean} True if this element is an ancestor of el, else false
7164          */
7165         contains : function(el){
7166             if(!el){return false;}
7167             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7168         },
7169
7170         /**
7171          * Checks whether the element is currently visible using both visibility and display properties.
7172          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7173          * @return {Boolean} True if the element is currently visible, else false
7174          */
7175         isVisible : function(deep) {
7176             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7177             if(deep !== true || !vis){
7178                 return vis;
7179             }
7180             var p = this.dom.parentNode;
7181             while(p && p.tagName.toLowerCase() != "body"){
7182                 if(!Roo.fly(p, '_isVisible').isVisible()){
7183                     return false;
7184                 }
7185                 p = p.parentNode;
7186             }
7187             return true;
7188         },
7189
7190         /**
7191          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7192          * @param {String} selector The CSS selector
7193          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7194          * @return {CompositeElement/CompositeElementLite} The composite element
7195          */
7196         select : function(selector, unique){
7197             return El.select(selector, unique, this.dom);
7198         },
7199
7200         /**
7201          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7202          * @param {String} selector The CSS selector
7203          * @return {Array} An array of the matched nodes
7204          */
7205         query : function(selector, unique){
7206             return Roo.DomQuery.select(selector, this.dom);
7207         },
7208
7209         /**
7210          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7211          * @param {String} selector The CSS selector
7212          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7213          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7214          */
7215         child : function(selector, returnDom){
7216             var n = Roo.DomQuery.selectNode(selector, this.dom);
7217             return returnDom ? n : Roo.get(n);
7218         },
7219
7220         /**
7221          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7222          * @param {String} selector The CSS selector
7223          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7224          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7225          */
7226         down : function(selector, returnDom){
7227             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7228             return returnDom ? n : Roo.get(n);
7229         },
7230
7231         /**
7232          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7233          * @param {String} group The group the DD object is member of
7234          * @param {Object} config The DD config object
7235          * @param {Object} overrides An object containing methods to override/implement on the DD object
7236          * @return {Roo.dd.DD} The DD object
7237          */
7238         initDD : function(group, config, overrides){
7239             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7240             return Roo.apply(dd, overrides);
7241         },
7242
7243         /**
7244          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7245          * @param {String} group The group the DDProxy object is member of
7246          * @param {Object} config The DDProxy config object
7247          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7248          * @return {Roo.dd.DDProxy} The DDProxy object
7249          */
7250         initDDProxy : function(group, config, overrides){
7251             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7252             return Roo.apply(dd, overrides);
7253         },
7254
7255         /**
7256          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7257          * @param {String} group The group the DDTarget object is member of
7258          * @param {Object} config The DDTarget config object
7259          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7260          * @return {Roo.dd.DDTarget} The DDTarget object
7261          */
7262         initDDTarget : function(group, config, overrides){
7263             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7264             return Roo.apply(dd, overrides);
7265         },
7266
7267         /**
7268          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7269          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7270          * @param {Boolean} visible Whether the element is visible
7271          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7272          * @return {Roo.Element} this
7273          */
7274          setVisible : function(visible, animate){
7275             if(!animate || !A){
7276                 if(this.visibilityMode == El.DISPLAY){
7277                     this.setDisplayed(visible);
7278                 }else{
7279                     this.fixDisplay();
7280                     this.dom.style.visibility = visible ? "visible" : "hidden";
7281                 }
7282             }else{
7283                 // closure for composites
7284                 var dom = this.dom;
7285                 var visMode = this.visibilityMode;
7286                 if(visible){
7287                     this.setOpacity(.01);
7288                     this.setVisible(true);
7289                 }
7290                 this.anim({opacity: { to: (visible?1:0) }},
7291                       this.preanim(arguments, 1),
7292                       null, .35, 'easeIn', function(){
7293                          if(!visible){
7294                              if(visMode == El.DISPLAY){
7295                                  dom.style.display = "none";
7296                              }else{
7297                                  dom.style.visibility = "hidden";
7298                              }
7299                              Roo.get(dom).setOpacity(1);
7300                          }
7301                      });
7302             }
7303             return this;
7304         },
7305
7306         /**
7307          * Returns true if display is not "none"
7308          * @return {Boolean}
7309          */
7310         isDisplayed : function() {
7311             return this.getStyle("display") != "none";
7312         },
7313
7314         /**
7315          * Toggles the element's visibility or display, depending on visibility mode.
7316          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7317          * @return {Roo.Element} this
7318          */
7319         toggle : function(animate){
7320             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7321             return this;
7322         },
7323
7324         /**
7325          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7326          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7327          * @return {Roo.Element} this
7328          */
7329         setDisplayed : function(value) {
7330             if(typeof value == "boolean"){
7331                value = value ? this.originalDisplay : "none";
7332             }
7333             this.setStyle("display", value);
7334             return this;
7335         },
7336
7337         /**
7338          * Tries to focus the element. Any exceptions are caught and ignored.
7339          * @return {Roo.Element} this
7340          */
7341         focus : function() {
7342             try{
7343                 this.dom.focus();
7344             }catch(e){}
7345             return this;
7346         },
7347
7348         /**
7349          * Tries to blur the element. Any exceptions are caught and ignored.
7350          * @return {Roo.Element} this
7351          */
7352         blur : function() {
7353             try{
7354                 this.dom.blur();
7355             }catch(e){}
7356             return this;
7357         },
7358
7359         /**
7360          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7361          * @param {String/Array} className The CSS class to add, or an array of classes
7362          * @return {Roo.Element} this
7363          */
7364         addClass : function(className){
7365             if(className instanceof Array){
7366                 for(var i = 0, len = className.length; i < len; i++) {
7367                     this.addClass(className[i]);
7368                 }
7369             }else{
7370                 if(className && !this.hasClass(className)){
7371                     this.dom.className = this.dom.className + " " + className;
7372                 }
7373             }
7374             return this;
7375         },
7376
7377         /**
7378          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7379          * @param {String/Array} className The CSS class to add, or an array of classes
7380          * @return {Roo.Element} this
7381          */
7382         radioClass : function(className){
7383             var siblings = this.dom.parentNode.childNodes;
7384             for(var i = 0; i < siblings.length; i++) {
7385                 var s = siblings[i];
7386                 if(s.nodeType == 1){
7387                     Roo.get(s).removeClass(className);
7388                 }
7389             }
7390             this.addClass(className);
7391             return this;
7392         },
7393
7394         /**
7395          * Removes one or more CSS classes from the element.
7396          * @param {String/Array} className The CSS class to remove, or an array of classes
7397          * @return {Roo.Element} this
7398          */
7399         removeClass : function(className){
7400             if(!className || !this.dom.className){
7401                 return this;
7402             }
7403             if(className instanceof Array){
7404                 for(var i = 0, len = className.length; i < len; i++) {
7405                     this.removeClass(className[i]);
7406                 }
7407             }else{
7408                 if(this.hasClass(className)){
7409                     var re = this.classReCache[className];
7410                     if (!re) {
7411                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7412                        this.classReCache[className] = re;
7413                     }
7414                     this.dom.className =
7415                         this.dom.className.replace(re, " ");
7416                 }
7417             }
7418             return this;
7419         },
7420
7421         // private
7422         classReCache: {},
7423
7424         /**
7425          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7426          * @param {String} className The CSS class to toggle
7427          * @return {Roo.Element} this
7428          */
7429         toggleClass : function(className){
7430             if(this.hasClass(className)){
7431                 this.removeClass(className);
7432             }else{
7433                 this.addClass(className);
7434             }
7435             return this;
7436         },
7437
7438         /**
7439          * Checks if the specified CSS class exists on this element's DOM node.
7440          * @param {String} className The CSS class to check for
7441          * @return {Boolean} True if the class exists, else false
7442          */
7443         hasClass : function(className){
7444             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7445         },
7446
7447         /**
7448          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7449          * @param {String} oldClassName The CSS class to replace
7450          * @param {String} newClassName The replacement CSS class
7451          * @return {Roo.Element} this
7452          */
7453         replaceClass : function(oldClassName, newClassName){
7454             this.removeClass(oldClassName);
7455             this.addClass(newClassName);
7456             return this;
7457         },
7458
7459         /**
7460          * Returns an object with properties matching the styles requested.
7461          * For example, el.getStyles('color', 'font-size', 'width') might return
7462          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7463          * @param {String} style1 A style name
7464          * @param {String} style2 A style name
7465          * @param {String} etc.
7466          * @return {Object} The style object
7467          */
7468         getStyles : function(){
7469             var a = arguments, len = a.length, r = {};
7470             for(var i = 0; i < len; i++){
7471                 r[a[i]] = this.getStyle(a[i]);
7472             }
7473             return r;
7474         },
7475
7476         /**
7477          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7478          * @param {String} property The style property whose value is returned.
7479          * @return {String} The current value of the style property for this element.
7480          */
7481         getStyle : function(){
7482             return view && view.getComputedStyle ?
7483                 function(prop){
7484                     var el = this.dom, v, cs, camel;
7485                     if(prop == 'float'){
7486                         prop = "cssFloat";
7487                     }
7488                     if(el.style && (v = el.style[prop])){
7489                         return v;
7490                     }
7491                     if(cs = view.getComputedStyle(el, "")){
7492                         if(!(camel = propCache[prop])){
7493                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7494                         }
7495                         return cs[camel];
7496                     }
7497                     return null;
7498                 } :
7499                 function(prop){
7500                     var el = this.dom, v, cs, camel;
7501                     if(prop == 'opacity'){
7502                         if(typeof el.style.filter == 'string'){
7503                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7504                             if(m){
7505                                 var fv = parseFloat(m[1]);
7506                                 if(!isNaN(fv)){
7507                                     return fv ? fv / 100 : 0;
7508                                 }
7509                             }
7510                         }
7511                         return 1;
7512                     }else if(prop == 'float'){
7513                         prop = "styleFloat";
7514                     }
7515                     if(!(camel = propCache[prop])){
7516                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7517                     }
7518                     if(v = el.style[camel]){
7519                         return v;
7520                     }
7521                     if(cs = el.currentStyle){
7522                         return cs[camel];
7523                     }
7524                     return null;
7525                 };
7526         }(),
7527
7528         /**
7529          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7530          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7531          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7532          * @return {Roo.Element} this
7533          */
7534         setStyle : function(prop, value){
7535             if(typeof prop == "string"){
7536                 
7537                 if (prop == 'float') {
7538                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7539                     return this;
7540                 }
7541                 
7542                 var camel;
7543                 if(!(camel = propCache[prop])){
7544                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7545                 }
7546                 
7547                 if(camel == 'opacity') {
7548                     this.setOpacity(value);
7549                 }else{
7550                     this.dom.style[camel] = value;
7551                 }
7552             }else{
7553                 for(var style in prop){
7554                     if(typeof prop[style] != "function"){
7555                        this.setStyle(style, prop[style]);
7556                     }
7557                 }
7558             }
7559             return this;
7560         },
7561
7562         /**
7563          * More flexible version of {@link #setStyle} for setting style properties.
7564          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7565          * a function which returns such a specification.
7566          * @return {Roo.Element} this
7567          */
7568         applyStyles : function(style){
7569             Roo.DomHelper.applyStyles(this.dom, style);
7570             return this;
7571         },
7572
7573         /**
7574           * 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).
7575           * @return {Number} The X position of the element
7576           */
7577         getX : function(){
7578             return D.getX(this.dom);
7579         },
7580
7581         /**
7582           * 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).
7583           * @return {Number} The Y position of the element
7584           */
7585         getY : function(){
7586             return D.getY(this.dom);
7587         },
7588
7589         /**
7590           * 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).
7591           * @return {Array} The XY position of the element
7592           */
7593         getXY : function(){
7594             return D.getXY(this.dom);
7595         },
7596
7597         /**
7598          * 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).
7599          * @param {Number} The X position of the element
7600          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7601          * @return {Roo.Element} this
7602          */
7603         setX : function(x, animate){
7604             if(!animate || !A){
7605                 D.setX(this.dom, x);
7606             }else{
7607                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7608             }
7609             return this;
7610         },
7611
7612         /**
7613          * 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).
7614          * @param {Number} The Y position of the element
7615          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7616          * @return {Roo.Element} this
7617          */
7618         setY : function(y, animate){
7619             if(!animate || !A){
7620                 D.setY(this.dom, y);
7621             }else{
7622                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7623             }
7624             return this;
7625         },
7626
7627         /**
7628          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7629          * @param {String} left The left CSS property value
7630          * @return {Roo.Element} this
7631          */
7632         setLeft : function(left){
7633             this.setStyle("left", this.addUnits(left));
7634             return this;
7635         },
7636
7637         /**
7638          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7639          * @param {String} top The top CSS property value
7640          * @return {Roo.Element} this
7641          */
7642         setTop : function(top){
7643             this.setStyle("top", this.addUnits(top));
7644             return this;
7645         },
7646
7647         /**
7648          * Sets the element's CSS right style.
7649          * @param {String} right The right CSS property value
7650          * @return {Roo.Element} this
7651          */
7652         setRight : function(right){
7653             this.setStyle("right", this.addUnits(right));
7654             return this;
7655         },
7656
7657         /**
7658          * Sets the element's CSS bottom style.
7659          * @param {String} bottom The bottom CSS property value
7660          * @return {Roo.Element} this
7661          */
7662         setBottom : function(bottom){
7663             this.setStyle("bottom", this.addUnits(bottom));
7664             return this;
7665         },
7666
7667         /**
7668          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7669          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7670          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7671          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7672          * @return {Roo.Element} this
7673          */
7674         setXY : function(pos, animate){
7675             if(!animate || !A){
7676                 D.setXY(this.dom, pos);
7677             }else{
7678                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7679             }
7680             return this;
7681         },
7682
7683         /**
7684          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7685          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7686          * @param {Number} x X value for new position (coordinates are page-based)
7687          * @param {Number} y Y value for new position (coordinates are page-based)
7688          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7689          * @return {Roo.Element} this
7690          */
7691         setLocation : function(x, y, animate){
7692             this.setXY([x, y], this.preanim(arguments, 2));
7693             return this;
7694         },
7695
7696         /**
7697          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7698          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7699          * @param {Number} x X value for new position (coordinates are page-based)
7700          * @param {Number} y Y value for new position (coordinates are page-based)
7701          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7702          * @return {Roo.Element} this
7703          */
7704         moveTo : function(x, y, animate){
7705             this.setXY([x, y], this.preanim(arguments, 2));
7706             return this;
7707         },
7708
7709         /**
7710          * Returns the region of the given element.
7711          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7712          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7713          */
7714         getRegion : function(){
7715             return D.getRegion(this.dom);
7716         },
7717
7718         /**
7719          * Returns the offset height of the element
7720          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7721          * @return {Number} The element's height
7722          */
7723         getHeight : function(contentHeight){
7724             var h = this.dom.offsetHeight || 0;
7725             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7726         },
7727
7728         /**
7729          * Returns the offset width of the element
7730          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7731          * @return {Number} The element's width
7732          */
7733         getWidth : function(contentWidth){
7734             var w = this.dom.offsetWidth || 0;
7735             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7736         },
7737
7738         /**
7739          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7740          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7741          * if a height has not been set using CSS.
7742          * @return {Number}
7743          */
7744         getComputedHeight : function(){
7745             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7746             if(!h){
7747                 h = parseInt(this.getStyle('height'), 10) || 0;
7748                 if(!this.isBorderBox()){
7749                     h += this.getFrameWidth('tb');
7750                 }
7751             }
7752             return h;
7753         },
7754
7755         /**
7756          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7757          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7758          * if a width has not been set using CSS.
7759          * @return {Number}
7760          */
7761         getComputedWidth : function(){
7762             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7763             if(!w){
7764                 w = parseInt(this.getStyle('width'), 10) || 0;
7765                 if(!this.isBorderBox()){
7766                     w += this.getFrameWidth('lr');
7767                 }
7768             }
7769             return w;
7770         },
7771
7772         /**
7773          * Returns the size of the element.
7774          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7775          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7776          */
7777         getSize : function(contentSize){
7778             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7779         },
7780
7781         /**
7782          * Returns the width and height of the viewport.
7783          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7784          */
7785         getViewSize : function(){
7786             var d = this.dom, doc = document, aw = 0, ah = 0;
7787             if(d == doc || d == doc.body){
7788                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7789             }else{
7790                 return {
7791                     width : d.clientWidth,
7792                     height: d.clientHeight
7793                 };
7794             }
7795         },
7796
7797         /**
7798          * Returns the value of the "value" attribute
7799          * @param {Boolean} asNumber true to parse the value as a number
7800          * @return {String/Number}
7801          */
7802         getValue : function(asNumber){
7803             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7804         },
7805
7806         // private
7807         adjustWidth : function(width){
7808             if(typeof width == "number"){
7809                 if(this.autoBoxAdjust && !this.isBorderBox()){
7810                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7811                 }
7812                 if(width < 0){
7813                     width = 0;
7814                 }
7815             }
7816             return width;
7817         },
7818
7819         // private
7820         adjustHeight : function(height){
7821             if(typeof height == "number"){
7822                if(this.autoBoxAdjust && !this.isBorderBox()){
7823                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7824                }
7825                if(height < 0){
7826                    height = 0;
7827                }
7828             }
7829             return height;
7830         },
7831
7832         /**
7833          * Set the width of the element
7834          * @param {Number} width The new width
7835          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7836          * @return {Roo.Element} this
7837          */
7838         setWidth : function(width, animate){
7839             width = this.adjustWidth(width);
7840             if(!animate || !A){
7841                 this.dom.style.width = this.addUnits(width);
7842             }else{
7843                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7844             }
7845             return this;
7846         },
7847
7848         /**
7849          * Set the height of the element
7850          * @param {Number} height The new height
7851          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7852          * @return {Roo.Element} this
7853          */
7854          setHeight : function(height, animate){
7855             height = this.adjustHeight(height);
7856             if(!animate || !A){
7857                 this.dom.style.height = this.addUnits(height);
7858             }else{
7859                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7860             }
7861             return this;
7862         },
7863
7864         /**
7865          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7866          * @param {Number} width The new width
7867          * @param {Number} height The new height
7868          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7869          * @return {Roo.Element} this
7870          */
7871          setSize : function(width, height, animate){
7872             if(typeof width == "object"){ // in case of object from getSize()
7873                 height = width.height; width = width.width;
7874             }
7875             width = this.adjustWidth(width); height = this.adjustHeight(height);
7876             if(!animate || !A){
7877                 this.dom.style.width = this.addUnits(width);
7878                 this.dom.style.height = this.addUnits(height);
7879             }else{
7880                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7881             }
7882             return this;
7883         },
7884
7885         /**
7886          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7887          * @param {Number} x X value for new position (coordinates are page-based)
7888          * @param {Number} y Y value for new position (coordinates are page-based)
7889          * @param {Number} width The new width
7890          * @param {Number} height The new height
7891          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7892          * @return {Roo.Element} this
7893          */
7894         setBounds : function(x, y, width, height, animate){
7895             if(!animate || !A){
7896                 this.setSize(width, height);
7897                 this.setLocation(x, y);
7898             }else{
7899                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7900                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7901                               this.preanim(arguments, 4), 'motion');
7902             }
7903             return this;
7904         },
7905
7906         /**
7907          * 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.
7908          * @param {Roo.lib.Region} region The region to fill
7909          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910          * @return {Roo.Element} this
7911          */
7912         setRegion : function(region, animate){
7913             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7914             return this;
7915         },
7916
7917         /**
7918          * Appends an event handler
7919          *
7920          * @param {String}   eventName     The type of event to append
7921          * @param {Function} fn        The method the event invokes
7922          * @param {Object} scope       (optional) The scope (this object) of the fn
7923          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7924          */
7925         addListener : function(eventName, fn, scope, options){
7926             if (this.dom) {
7927                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7928             }
7929         },
7930
7931         /**
7932          * Removes an event handler from this element
7933          * @param {String} eventName the type of event to remove
7934          * @param {Function} fn the method the event invokes
7935          * @return {Roo.Element} this
7936          */
7937         removeListener : function(eventName, fn){
7938             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7939             return this;
7940         },
7941
7942         /**
7943          * Removes all previous added listeners from this element
7944          * @return {Roo.Element} this
7945          */
7946         removeAllListeners : function(){
7947             E.purgeElement(this.dom);
7948             return this;
7949         },
7950
7951         relayEvent : function(eventName, observable){
7952             this.on(eventName, function(e){
7953                 observable.fireEvent(eventName, e);
7954             });
7955         },
7956
7957         /**
7958          * Set the opacity of the element
7959          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7960          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961          * @return {Roo.Element} this
7962          */
7963          setOpacity : function(opacity, animate){
7964             if(!animate || !A){
7965                 var s = this.dom.style;
7966                 if(Roo.isIE){
7967                     s.zoom = 1;
7968                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7969                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7970                 }else{
7971                     s.opacity = opacity;
7972                 }
7973             }else{
7974                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7975             }
7976             return this;
7977         },
7978
7979         /**
7980          * Gets the left X coordinate
7981          * @param {Boolean} local True to get the local css position instead of page coordinate
7982          * @return {Number}
7983          */
7984         getLeft : function(local){
7985             if(!local){
7986                 return this.getX();
7987             }else{
7988                 return parseInt(this.getStyle("left"), 10) || 0;
7989             }
7990         },
7991
7992         /**
7993          * Gets the right X coordinate of the element (element X position + element width)
7994          * @param {Boolean} local True to get the local css position instead of page coordinate
7995          * @return {Number}
7996          */
7997         getRight : function(local){
7998             if(!local){
7999                 return this.getX() + this.getWidth();
8000             }else{
8001                 return (this.getLeft(true) + this.getWidth()) || 0;
8002             }
8003         },
8004
8005         /**
8006          * Gets the top Y coordinate
8007          * @param {Boolean} local True to get the local css position instead of page coordinate
8008          * @return {Number}
8009          */
8010         getTop : function(local) {
8011             if(!local){
8012                 return this.getY();
8013             }else{
8014                 return parseInt(this.getStyle("top"), 10) || 0;
8015             }
8016         },
8017
8018         /**
8019          * Gets the bottom Y coordinate of the element (element Y position + element height)
8020          * @param {Boolean} local True to get the local css position instead of page coordinate
8021          * @return {Number}
8022          */
8023         getBottom : function(local){
8024             if(!local){
8025                 return this.getY() + this.getHeight();
8026             }else{
8027                 return (this.getTop(true) + this.getHeight()) || 0;
8028             }
8029         },
8030
8031         /**
8032         * Initializes positioning on this element. If a desired position is not passed, it will make the
8033         * the element positioned relative IF it is not already positioned.
8034         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8035         * @param {Number} zIndex (optional) The zIndex to apply
8036         * @param {Number} x (optional) Set the page X position
8037         * @param {Number} y (optional) Set the page Y position
8038         */
8039         position : function(pos, zIndex, x, y){
8040             if(!pos){
8041                if(this.getStyle('position') == 'static'){
8042                    this.setStyle('position', 'relative');
8043                }
8044             }else{
8045                 this.setStyle("position", pos);
8046             }
8047             if(zIndex){
8048                 this.setStyle("z-index", zIndex);
8049             }
8050             if(x !== undefined && y !== undefined){
8051                 this.setXY([x, y]);
8052             }else if(x !== undefined){
8053                 this.setX(x);
8054             }else if(y !== undefined){
8055                 this.setY(y);
8056             }
8057         },
8058
8059         /**
8060         * Clear positioning back to the default when the document was loaded
8061         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8062         * @return {Roo.Element} this
8063          */
8064         clearPositioning : function(value){
8065             value = value ||'';
8066             this.setStyle({
8067                 "left": value,
8068                 "right": value,
8069                 "top": value,
8070                 "bottom": value,
8071                 "z-index": "",
8072                 "position" : "static"
8073             });
8074             return this;
8075         },
8076
8077         /**
8078         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8079         * snapshot before performing an update and then restoring the element.
8080         * @return {Object}
8081         */
8082         getPositioning : function(){
8083             var l = this.getStyle("left");
8084             var t = this.getStyle("top");
8085             return {
8086                 "position" : this.getStyle("position"),
8087                 "left" : l,
8088                 "right" : l ? "" : this.getStyle("right"),
8089                 "top" : t,
8090                 "bottom" : t ? "" : this.getStyle("bottom"),
8091                 "z-index" : this.getStyle("z-index")
8092             };
8093         },
8094
8095         /**
8096          * Gets the width of the border(s) for the specified side(s)
8097          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8098          * passing lr would get the border (l)eft width + the border (r)ight width.
8099          * @return {Number} The width of the sides passed added together
8100          */
8101         getBorderWidth : function(side){
8102             return this.addStyles(side, El.borders);
8103         },
8104
8105         /**
8106          * Gets the width of the padding(s) for the specified side(s)
8107          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8108          * passing lr would get the padding (l)eft + the padding (r)ight.
8109          * @return {Number} The padding of the sides passed added together
8110          */
8111         getPadding : function(side){
8112             return this.addStyles(side, El.paddings);
8113         },
8114
8115         /**
8116         * Set positioning with an object returned by getPositioning().
8117         * @param {Object} posCfg
8118         * @return {Roo.Element} this
8119          */
8120         setPositioning : function(pc){
8121             this.applyStyles(pc);
8122             if(pc.right == "auto"){
8123                 this.dom.style.right = "";
8124             }
8125             if(pc.bottom == "auto"){
8126                 this.dom.style.bottom = "";
8127             }
8128             return this;
8129         },
8130
8131         // private
8132         fixDisplay : function(){
8133             if(this.getStyle("display") == "none"){
8134                 this.setStyle("visibility", "hidden");
8135                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8136                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8137                     this.setStyle("display", "block");
8138                 }
8139             }
8140         },
8141
8142         /**
8143          * Quick set left and top adding default units
8144          * @param {String} left The left CSS property value
8145          * @param {String} top The top CSS property value
8146          * @return {Roo.Element} this
8147          */
8148          setLeftTop : function(left, top){
8149             this.dom.style.left = this.addUnits(left);
8150             this.dom.style.top = this.addUnits(top);
8151             return this;
8152         },
8153
8154         /**
8155          * Move this element relative to its current position.
8156          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8157          * @param {Number} distance How far to move the element in pixels
8158          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8159          * @return {Roo.Element} this
8160          */
8161          move : function(direction, distance, animate){
8162             var xy = this.getXY();
8163             direction = direction.toLowerCase();
8164             switch(direction){
8165                 case "l":
8166                 case "left":
8167                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8168                     break;
8169                case "r":
8170                case "right":
8171                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8172                     break;
8173                case "t":
8174                case "top":
8175                case "up":
8176                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8177                     break;
8178                case "b":
8179                case "bottom":
8180                case "down":
8181                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8182                     break;
8183             }
8184             return this;
8185         },
8186
8187         /**
8188          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8189          * @return {Roo.Element} this
8190          */
8191         clip : function(){
8192             if(!this.isClipped){
8193                this.isClipped = true;
8194                this.originalClip = {
8195                    "o": this.getStyle("overflow"),
8196                    "x": this.getStyle("overflow-x"),
8197                    "y": this.getStyle("overflow-y")
8198                };
8199                this.setStyle("overflow", "hidden");
8200                this.setStyle("overflow-x", "hidden");
8201                this.setStyle("overflow-y", "hidden");
8202             }
8203             return this;
8204         },
8205
8206         /**
8207          *  Return clipping (overflow) to original clipping before clip() was called
8208          * @return {Roo.Element} this
8209          */
8210         unclip : function(){
8211             if(this.isClipped){
8212                 this.isClipped = false;
8213                 var o = this.originalClip;
8214                 if(o.o){this.setStyle("overflow", o.o);}
8215                 if(o.x){this.setStyle("overflow-x", o.x);}
8216                 if(o.y){this.setStyle("overflow-y", o.y);}
8217             }
8218             return this;
8219         },
8220
8221
8222         /**
8223          * Gets the x,y coordinates specified by the anchor position on the element.
8224          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8225          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8226          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8227          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8228          * @return {Array} [x, y] An array containing the element's x and y coordinates
8229          */
8230         getAnchorXY : function(anchor, local, s){
8231             //Passing a different size is useful for pre-calculating anchors,
8232             //especially for anchored animations that change the el size.
8233
8234             var w, h, vp = false;
8235             if(!s){
8236                 var d = this.dom;
8237                 if(d == document.body || d == document){
8238                     vp = true;
8239                     w = D.getViewWidth(); h = D.getViewHeight();
8240                 }else{
8241                     w = this.getWidth(); h = this.getHeight();
8242                 }
8243             }else{
8244                 w = s.width;  h = s.height;
8245             }
8246             var x = 0, y = 0, r = Math.round;
8247             switch((anchor || "tl").toLowerCase()){
8248                 case "c":
8249                     x = r(w*.5);
8250                     y = r(h*.5);
8251                 break;
8252                 case "t":
8253                     x = r(w*.5);
8254                     y = 0;
8255                 break;
8256                 case "l":
8257                     x = 0;
8258                     y = r(h*.5);
8259                 break;
8260                 case "r":
8261                     x = w;
8262                     y = r(h*.5);
8263                 break;
8264                 case "b":
8265                     x = r(w*.5);
8266                     y = h;
8267                 break;
8268                 case "tl":
8269                     x = 0;
8270                     y = 0;
8271                 break;
8272                 case "bl":
8273                     x = 0;
8274                     y = h;
8275                 break;
8276                 case "br":
8277                     x = w;
8278                     y = h;
8279                 break;
8280                 case "tr":
8281                     x = w;
8282                     y = 0;
8283                 break;
8284             }
8285             if(local === true){
8286                 return [x, y];
8287             }
8288             if(vp){
8289                 var sc = this.getScroll();
8290                 return [x + sc.left, y + sc.top];
8291             }
8292             //Add the element's offset xy
8293             var o = this.getXY();
8294             return [x+o[0], y+o[1]];
8295         },
8296
8297         /**
8298          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8299          * supported position values.
8300          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8301          * @param {String} position The position to align to.
8302          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8303          * @return {Array} [x, y]
8304          */
8305         getAlignToXY : function(el, p, o){
8306             el = Roo.get(el);
8307             var d = this.dom;
8308             if(!el.dom){
8309                 throw "Element.alignTo with an element that doesn't exist";
8310             }
8311             var c = false; //constrain to viewport
8312             var p1 = "", p2 = "";
8313             o = o || [0,0];
8314
8315             if(!p){
8316                 p = "tl-bl";
8317             }else if(p == "?"){
8318                 p = "tl-bl?";
8319             }else if(p.indexOf("-") == -1){
8320                 p = "tl-" + p;
8321             }
8322             p = p.toLowerCase();
8323             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8324             if(!m){
8325                throw "Element.alignTo with an invalid alignment " + p;
8326             }
8327             p1 = m[1]; p2 = m[2]; c = !!m[3];
8328
8329             //Subtract the aligned el's internal xy from the target's offset xy
8330             //plus custom offset to get the aligned el's new offset xy
8331             var a1 = this.getAnchorXY(p1, true);
8332             var a2 = el.getAnchorXY(p2, false);
8333             var x = a2[0] - a1[0] + o[0];
8334             var y = a2[1] - a1[1] + o[1];
8335             if(c){
8336                 //constrain the aligned el to viewport if necessary
8337                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8338                 // 5px of margin for ie
8339                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8340
8341                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8342                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8343                 //otherwise swap the aligned el to the opposite border of the target.
8344                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8345                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8346                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8347                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8348
8349                var doc = document;
8350                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8351                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8352
8353                if((x+w) > dw + scrollX){
8354                     x = swapX ? r.left-w : dw+scrollX-w;
8355                 }
8356                if(x < scrollX){
8357                    x = swapX ? r.right : scrollX;
8358                }
8359                if((y+h) > dh + scrollY){
8360                     y = swapY ? r.top-h : dh+scrollY-h;
8361                 }
8362                if (y < scrollY){
8363                    y = swapY ? r.bottom : scrollY;
8364                }
8365             }
8366             return [x,y];
8367         },
8368
8369         // private
8370         getConstrainToXY : function(){
8371             var os = {top:0, left:0, bottom:0, right: 0};
8372
8373             return function(el, local, offsets, proposedXY){
8374                 el = Roo.get(el);
8375                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8376
8377                 var vw, vh, vx = 0, vy = 0;
8378                 if(el.dom == document.body || el.dom == document){
8379                     vw = Roo.lib.Dom.getViewWidth();
8380                     vh = Roo.lib.Dom.getViewHeight();
8381                 }else{
8382                     vw = el.dom.clientWidth;
8383                     vh = el.dom.clientHeight;
8384                     if(!local){
8385                         var vxy = el.getXY();
8386                         vx = vxy[0];
8387                         vy = vxy[1];
8388                     }
8389                 }
8390
8391                 var s = el.getScroll();
8392
8393                 vx += offsets.left + s.left;
8394                 vy += offsets.top + s.top;
8395
8396                 vw -= offsets.right;
8397                 vh -= offsets.bottom;
8398
8399                 var vr = vx+vw;
8400                 var vb = vy+vh;
8401
8402                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8403                 var x = xy[0], y = xy[1];
8404                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8405
8406                 // only move it if it needs it
8407                 var moved = false;
8408
8409                 // first validate right/bottom
8410                 if((x + w) > vr){
8411                     x = vr - w;
8412                     moved = true;
8413                 }
8414                 if((y + h) > vb){
8415                     y = vb - h;
8416                     moved = true;
8417                 }
8418                 // then make sure top/left isn't negative
8419                 if(x < vx){
8420                     x = vx;
8421                     moved = true;
8422                 }
8423                 if(y < vy){
8424                     y = vy;
8425                     moved = true;
8426                 }
8427                 return moved ? [x, y] : false;
8428             };
8429         }(),
8430
8431         // private
8432         adjustForConstraints : function(xy, parent, offsets){
8433             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8434         },
8435
8436         /**
8437          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8438          * document it aligns it to the viewport.
8439          * The position parameter is optional, and can be specified in any one of the following formats:
8440          * <ul>
8441          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8442          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8443          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8444          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8445          *   <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
8446          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8447          * </ul>
8448          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8449          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8450          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8451          * that specified in order to enforce the viewport constraints.
8452          * Following are all of the supported anchor positions:
8453     <pre>
8454     Value  Description
8455     -----  -----------------------------
8456     tl     The top left corner (default)
8457     t      The center of the top edge
8458     tr     The top right corner
8459     l      The center of the left edge
8460     c      In the center of the element
8461     r      The center of the right edge
8462     bl     The bottom left corner
8463     b      The center of the bottom edge
8464     br     The bottom right corner
8465     </pre>
8466     Example Usage:
8467     <pre><code>
8468     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8469     el.alignTo("other-el");
8470
8471     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8472     el.alignTo("other-el", "tr?");
8473
8474     // align the bottom right corner of el with the center left edge of other-el
8475     el.alignTo("other-el", "br-l?");
8476
8477     // align the center of el with the bottom left corner of other-el and
8478     // adjust the x position by -6 pixels (and the y position by 0)
8479     el.alignTo("other-el", "c-bl", [-6, 0]);
8480     </code></pre>
8481          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8482          * @param {String} position The position to align to.
8483          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8484          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8485          * @return {Roo.Element} this
8486          */
8487         alignTo : function(element, position, offsets, animate){
8488             var xy = this.getAlignToXY(element, position, offsets);
8489             this.setXY(xy, this.preanim(arguments, 3));
8490             return this;
8491         },
8492
8493         /**
8494          * Anchors an element to another element and realigns it when the window is resized.
8495          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8496          * @param {String} position The position to align to.
8497          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8498          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8499          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8500          * is a number, it is used as the buffer delay (defaults to 50ms).
8501          * @param {Function} callback The function to call after the animation finishes
8502          * @return {Roo.Element} this
8503          */
8504         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8505             var action = function(){
8506                 this.alignTo(el, alignment, offsets, animate);
8507                 Roo.callback(callback, this);
8508             };
8509             Roo.EventManager.onWindowResize(action, this);
8510             var tm = typeof monitorScroll;
8511             if(tm != 'undefined'){
8512                 Roo.EventManager.on(window, 'scroll', action, this,
8513                     {buffer: tm == 'number' ? monitorScroll : 50});
8514             }
8515             action.call(this); // align immediately
8516             return this;
8517         },
8518         /**
8519          * Clears any opacity settings from this element. Required in some cases for IE.
8520          * @return {Roo.Element} this
8521          */
8522         clearOpacity : function(){
8523             if (window.ActiveXObject) {
8524                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8525                     this.dom.style.filter = "";
8526                 }
8527             } else {
8528                 this.dom.style.opacity = "";
8529                 this.dom.style["-moz-opacity"] = "";
8530                 this.dom.style["-khtml-opacity"] = "";
8531             }
8532             return this;
8533         },
8534
8535         /**
8536          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8537          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8538          * @return {Roo.Element} this
8539          */
8540         hide : function(animate){
8541             this.setVisible(false, this.preanim(arguments, 0));
8542             return this;
8543         },
8544
8545         /**
8546         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8547         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8548          * @return {Roo.Element} this
8549          */
8550         show : function(animate){
8551             this.setVisible(true, this.preanim(arguments, 0));
8552             return this;
8553         },
8554
8555         /**
8556          * @private Test if size has a unit, otherwise appends the default
8557          */
8558         addUnits : function(size){
8559             return Roo.Element.addUnits(size, this.defaultUnit);
8560         },
8561
8562         /**
8563          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8564          * @return {Roo.Element} this
8565          */
8566         beginMeasure : function(){
8567             var el = this.dom;
8568             if(el.offsetWidth || el.offsetHeight){
8569                 return this; // offsets work already
8570             }
8571             var changed = [];
8572             var p = this.dom, b = document.body; // start with this element
8573             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8574                 var pe = Roo.get(p);
8575                 if(pe.getStyle('display') == 'none'){
8576                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8577                     p.style.visibility = "hidden";
8578                     p.style.display = "block";
8579                 }
8580                 p = p.parentNode;
8581             }
8582             this._measureChanged = changed;
8583             return this;
8584
8585         },
8586
8587         /**
8588          * Restores displays to before beginMeasure was called
8589          * @return {Roo.Element} this
8590          */
8591         endMeasure : function(){
8592             var changed = this._measureChanged;
8593             if(changed){
8594                 for(var i = 0, len = changed.length; i < len; i++) {
8595                     var r = changed[i];
8596                     r.el.style.visibility = r.visibility;
8597                     r.el.style.display = "none";
8598                 }
8599                 this._measureChanged = null;
8600             }
8601             return this;
8602         },
8603
8604         /**
8605         * Update the innerHTML of this element, optionally searching for and processing scripts
8606         * @param {String} html The new HTML
8607         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8608         * @param {Function} callback For async script loading you can be noticed when the update completes
8609         * @return {Roo.Element} this
8610          */
8611         update : function(html, loadScripts, callback){
8612             if(typeof html == "undefined"){
8613                 html = "";
8614             }
8615             if(loadScripts !== true){
8616                 this.dom.innerHTML = html;
8617                 if(typeof callback == "function"){
8618                     callback();
8619                 }
8620                 return this;
8621             }
8622             var id = Roo.id();
8623             var dom = this.dom;
8624
8625             html += '<span id="' + id + '"></span>';
8626
8627             E.onAvailable(id, function(){
8628                 var hd = document.getElementsByTagName("head")[0];
8629                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8630                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8631                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8632
8633                 var match;
8634                 while(match = re.exec(html)){
8635                     var attrs = match[1];
8636                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8637                     if(srcMatch && srcMatch[2]){
8638                        var s = document.createElement("script");
8639                        s.src = srcMatch[2];
8640                        var typeMatch = attrs.match(typeRe);
8641                        if(typeMatch && typeMatch[2]){
8642                            s.type = typeMatch[2];
8643                        }
8644                        hd.appendChild(s);
8645                     }else if(match[2] && match[2].length > 0){
8646                         if(window.execScript) {
8647                            window.execScript(match[2]);
8648                         } else {
8649                             /**
8650                              * eval:var:id
8651                              * eval:var:dom
8652                              * eval:var:html
8653                              * 
8654                              */
8655                            window.eval(match[2]);
8656                         }
8657                     }
8658                 }
8659                 var el = document.getElementById(id);
8660                 if(el){el.parentNode.removeChild(el);}
8661                 if(typeof callback == "function"){
8662                     callback();
8663                 }
8664             });
8665             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8666             return this;
8667         },
8668
8669         /**
8670          * Direct access to the UpdateManager update() method (takes the same parameters).
8671          * @param {String/Function} url The url for this request or a function to call to get the url
8672          * @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}
8673          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8674          * @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.
8675          * @return {Roo.Element} this
8676          */
8677         load : function(){
8678             var um = this.getUpdateManager();
8679             um.update.apply(um, arguments);
8680             return this;
8681         },
8682
8683         /**
8684         * Gets this element's UpdateManager
8685         * @return {Roo.UpdateManager} The UpdateManager
8686         */
8687         getUpdateManager : function(){
8688             if(!this.updateManager){
8689                 this.updateManager = new Roo.UpdateManager(this);
8690             }
8691             return this.updateManager;
8692         },
8693
8694         /**
8695          * Disables text selection for this element (normalized across browsers)
8696          * @return {Roo.Element} this
8697          */
8698         unselectable : function(){
8699             this.dom.unselectable = "on";
8700             this.swallowEvent("selectstart", true);
8701             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8702             this.addClass("x-unselectable");
8703             return this;
8704         },
8705
8706         /**
8707         * Calculates the x, y to center this element on the screen
8708         * @return {Array} The x, y values [x, y]
8709         */
8710         getCenterXY : function(){
8711             return this.getAlignToXY(document, 'c-c');
8712         },
8713
8714         /**
8715         * Centers the Element in either the viewport, or another Element.
8716         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8717         */
8718         center : function(centerIn){
8719             this.alignTo(centerIn || document, 'c-c');
8720             return this;
8721         },
8722
8723         /**
8724          * Tests various css rules/browsers to determine if this element uses a border box
8725          * @return {Boolean}
8726          */
8727         isBorderBox : function(){
8728             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8729         },
8730
8731         /**
8732          * Return a box {x, y, width, height} that can be used to set another elements
8733          * size/location to match this element.
8734          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8735          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8736          * @return {Object} box An object in the format {x, y, width, height}
8737          */
8738         getBox : function(contentBox, local){
8739             var xy;
8740             if(!local){
8741                 xy = this.getXY();
8742             }else{
8743                 var left = parseInt(this.getStyle("left"), 10) || 0;
8744                 var top = parseInt(this.getStyle("top"), 10) || 0;
8745                 xy = [left, top];
8746             }
8747             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8748             if(!contentBox){
8749                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8750             }else{
8751                 var l = this.getBorderWidth("l")+this.getPadding("l");
8752                 var r = this.getBorderWidth("r")+this.getPadding("r");
8753                 var t = this.getBorderWidth("t")+this.getPadding("t");
8754                 var b = this.getBorderWidth("b")+this.getPadding("b");
8755                 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)};
8756             }
8757             bx.right = bx.x + bx.width;
8758             bx.bottom = bx.y + bx.height;
8759             return bx;
8760         },
8761
8762         /**
8763          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8764          for more information about the sides.
8765          * @param {String} sides
8766          * @return {Number}
8767          */
8768         getFrameWidth : function(sides, onlyContentBox){
8769             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8770         },
8771
8772         /**
8773          * 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.
8774          * @param {Object} box The box to fill {x, y, width, height}
8775          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8776          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8777          * @return {Roo.Element} this
8778          */
8779         setBox : function(box, adjust, animate){
8780             var w = box.width, h = box.height;
8781             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8782                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8783                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8784             }
8785             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8786             return this;
8787         },
8788
8789         /**
8790          * Forces the browser to repaint this element
8791          * @return {Roo.Element} this
8792          */
8793          repaint : function(){
8794             var dom = this.dom;
8795             this.addClass("x-repaint");
8796             setTimeout(function(){
8797                 Roo.get(dom).removeClass("x-repaint");
8798             }, 1);
8799             return this;
8800         },
8801
8802         /**
8803          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8804          * then it returns the calculated width of the sides (see getPadding)
8805          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8806          * @return {Object/Number}
8807          */
8808         getMargins : function(side){
8809             if(!side){
8810                 return {
8811                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8812                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8813                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8814                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8815                 };
8816             }else{
8817                 return this.addStyles(side, El.margins);
8818              }
8819         },
8820
8821         // private
8822         addStyles : function(sides, styles){
8823             var val = 0, v, w;
8824             for(var i = 0, len = sides.length; i < len; i++){
8825                 v = this.getStyle(styles[sides.charAt(i)]);
8826                 if(v){
8827                      w = parseInt(v, 10);
8828                      if(w){ val += w; }
8829                 }
8830             }
8831             return val;
8832         },
8833
8834         /**
8835          * Creates a proxy element of this element
8836          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8837          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8838          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8839          * @return {Roo.Element} The new proxy element
8840          */
8841         createProxy : function(config, renderTo, matchBox){
8842             if(renderTo){
8843                 renderTo = Roo.getDom(renderTo);
8844             }else{
8845                 renderTo = document.body;
8846             }
8847             config = typeof config == "object" ?
8848                 config : {tag : "div", cls: config};
8849             var proxy = Roo.DomHelper.append(renderTo, config, true);
8850             if(matchBox){
8851                proxy.setBox(this.getBox());
8852             }
8853             return proxy;
8854         },
8855
8856         /**
8857          * Puts a mask over this element to disable user interaction. Requires core.css.
8858          * This method can only be applied to elements which accept child nodes.
8859          * @param {String} msg (optional) A message to display in the mask
8860          * @param {String} msgCls (optional) A css class to apply to the msg element
8861          * @return {Element} The mask  element
8862          */
8863         mask : function(msg, msgCls)
8864         {
8865             if(this.getStyle("position") == "static"){
8866                 this.setStyle("position", "relative");
8867             }
8868             if(!this._mask){
8869                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8870             }
8871             this.addClass("x-masked");
8872             this._mask.setDisplayed(true);
8873             
8874             // we wander
8875             var z = 0;
8876             var dom = this.dom
8877             while (dom && dom.style) {
8878                 if (!isNaN(parseInt(dom.style.zIndex))) {
8879                     z = Math.max(z, parseInt(dom.style.zIndex));
8880                 }
8881                 dom = dom.parentNode;
8882             }
8883             // if we are masking the body - then it hides everything..
8884             if (this.dom == document.body) {
8885                 z = 1000000;
8886                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8887                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8888             }
8889            
8890             if(typeof msg == 'string'){
8891                 if(!this._maskMsg){
8892                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8893                 }
8894                 var mm = this._maskMsg;
8895                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8896                 mm.dom.firstChild.innerHTML = msg;
8897                 mm.setDisplayed(true);
8898                 mm.center(this);
8899                 mm.setStyle('z-index', z + 102);
8900             }
8901             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8902                 this._mask.setHeight(this.getHeight());
8903             }
8904             this._mask.setStyle('z-index', z + 100);
8905             
8906             return this._mask;
8907         },
8908
8909         /**
8910          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8911          * it is cached for reuse.
8912          */
8913         unmask : function(removeEl){
8914             if(this._mask){
8915                 if(removeEl === true){
8916                     this._mask.remove();
8917                     delete this._mask;
8918                     if(this._maskMsg){
8919                         this._maskMsg.remove();
8920                         delete this._maskMsg;
8921                     }
8922                 }else{
8923                     this._mask.setDisplayed(false);
8924                     if(this._maskMsg){
8925                         this._maskMsg.setDisplayed(false);
8926                     }
8927                 }
8928             }
8929             this.removeClass("x-masked");
8930         },
8931
8932         /**
8933          * Returns true if this element is masked
8934          * @return {Boolean}
8935          */
8936         isMasked : function(){
8937             return this._mask && this._mask.isVisible();
8938         },
8939
8940         /**
8941          * Creates an iframe shim for this element to keep selects and other windowed objects from
8942          * showing through.
8943          * @return {Roo.Element} The new shim element
8944          */
8945         createShim : function(){
8946             var el = document.createElement('iframe');
8947             el.frameBorder = 'no';
8948             el.className = 'roo-shim';
8949             if(Roo.isIE && Roo.isSecure){
8950                 el.src = Roo.SSL_SECURE_URL;
8951             }
8952             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8953             shim.autoBoxAdjust = false;
8954             return shim;
8955         },
8956
8957         /**
8958          * Removes this element from the DOM and deletes it from the cache
8959          */
8960         remove : function(){
8961             if(this.dom.parentNode){
8962                 this.dom.parentNode.removeChild(this.dom);
8963             }
8964             delete El.cache[this.dom.id];
8965         },
8966
8967         /**
8968          * Sets up event handlers to add and remove a css class when the mouse is over this element
8969          * @param {String} className
8970          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8971          * mouseout events for children elements
8972          * @return {Roo.Element} this
8973          */
8974         addClassOnOver : function(className, preventFlicker){
8975             this.on("mouseover", function(){
8976                 Roo.fly(this, '_internal').addClass(className);
8977             }, this.dom);
8978             var removeFn = function(e){
8979                 if(preventFlicker !== true || !e.within(this, true)){
8980                     Roo.fly(this, '_internal').removeClass(className);
8981                 }
8982             };
8983             this.on("mouseout", removeFn, this.dom);
8984             return this;
8985         },
8986
8987         /**
8988          * Sets up event handlers to add and remove a css class when this element has the focus
8989          * @param {String} className
8990          * @return {Roo.Element} this
8991          */
8992         addClassOnFocus : function(className){
8993             this.on("focus", function(){
8994                 Roo.fly(this, '_internal').addClass(className);
8995             }, this.dom);
8996             this.on("blur", function(){
8997                 Roo.fly(this, '_internal').removeClass(className);
8998             }, this.dom);
8999             return this;
9000         },
9001         /**
9002          * 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)
9003          * @param {String} className
9004          * @return {Roo.Element} this
9005          */
9006         addClassOnClick : function(className){
9007             var dom = this.dom;
9008             this.on("mousedown", function(){
9009                 Roo.fly(dom, '_internal').addClass(className);
9010                 var d = Roo.get(document);
9011                 var fn = function(){
9012                     Roo.fly(dom, '_internal').removeClass(className);
9013                     d.removeListener("mouseup", fn);
9014                 };
9015                 d.on("mouseup", fn);
9016             });
9017             return this;
9018         },
9019
9020         /**
9021          * Stops the specified event from bubbling and optionally prevents the default action
9022          * @param {String} eventName
9023          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9024          * @return {Roo.Element} this
9025          */
9026         swallowEvent : function(eventName, preventDefault){
9027             var fn = function(e){
9028                 e.stopPropagation();
9029                 if(preventDefault){
9030                     e.preventDefault();
9031                 }
9032             };
9033             if(eventName instanceof Array){
9034                 for(var i = 0, len = eventName.length; i < len; i++){
9035                      this.on(eventName[i], fn);
9036                 }
9037                 return this;
9038             }
9039             this.on(eventName, fn);
9040             return this;
9041         },
9042
9043         /**
9044          * @private
9045          */
9046       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9047
9048         /**
9049          * Sizes this element to its parent element's dimensions performing
9050          * neccessary box adjustments.
9051          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9052          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9053          * @return {Roo.Element} this
9054          */
9055         fitToParent : function(monitorResize, targetParent) {
9056           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9057           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9058           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9059             return;
9060           }
9061           var p = Roo.get(targetParent || this.dom.parentNode);
9062           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9063           if (monitorResize === true) {
9064             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9065             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9066           }
9067           return this;
9068         },
9069
9070         /**
9071          * Gets the next sibling, skipping text nodes
9072          * @return {HTMLElement} The next sibling or null
9073          */
9074         getNextSibling : function(){
9075             var n = this.dom.nextSibling;
9076             while(n && n.nodeType != 1){
9077                 n = n.nextSibling;
9078             }
9079             return n;
9080         },
9081
9082         /**
9083          * Gets the previous sibling, skipping text nodes
9084          * @return {HTMLElement} The previous sibling or null
9085          */
9086         getPrevSibling : function(){
9087             var n = this.dom.previousSibling;
9088             while(n && n.nodeType != 1){
9089                 n = n.previousSibling;
9090             }
9091             return n;
9092         },
9093
9094
9095         /**
9096          * Appends the passed element(s) to this element
9097          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9098          * @return {Roo.Element} this
9099          */
9100         appendChild: function(el){
9101             el = Roo.get(el);
9102             el.appendTo(this);
9103             return this;
9104         },
9105
9106         /**
9107          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9108          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9109          * automatically generated with the specified attributes.
9110          * @param {HTMLElement} insertBefore (optional) a child element of this element
9111          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9112          * @return {Roo.Element} The new child element
9113          */
9114         createChild: function(config, insertBefore, returnDom){
9115             config = config || {tag:'div'};
9116             if(insertBefore){
9117                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9118             }
9119             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9120         },
9121
9122         /**
9123          * Appends this element to the passed element
9124          * @param {String/HTMLElement/Element} el The new parent element
9125          * @return {Roo.Element} this
9126          */
9127         appendTo: function(el){
9128             el = Roo.getDom(el);
9129             el.appendChild(this.dom);
9130             return this;
9131         },
9132
9133         /**
9134          * Inserts this element before the passed element in the DOM
9135          * @param {String/HTMLElement/Element} el The element to insert before
9136          * @return {Roo.Element} this
9137          */
9138         insertBefore: function(el){
9139             el = Roo.getDom(el);
9140             el.parentNode.insertBefore(this.dom, el);
9141             return this;
9142         },
9143
9144         /**
9145          * Inserts this element after the passed element in the DOM
9146          * @param {String/HTMLElement/Element} el The element to insert after
9147          * @return {Roo.Element} this
9148          */
9149         insertAfter: function(el){
9150             el = Roo.getDom(el);
9151             el.parentNode.insertBefore(this.dom, el.nextSibling);
9152             return this;
9153         },
9154
9155         /**
9156          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9157          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9158          * @return {Roo.Element} The new child
9159          */
9160         insertFirst: function(el, returnDom){
9161             el = el || {};
9162             if(typeof el == 'object' && !el.nodeType){ // dh config
9163                 return this.createChild(el, this.dom.firstChild, returnDom);
9164             }else{
9165                 el = Roo.getDom(el);
9166                 this.dom.insertBefore(el, this.dom.firstChild);
9167                 return !returnDom ? Roo.get(el) : el;
9168             }
9169         },
9170
9171         /**
9172          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9173          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9174          * @param {String} where (optional) 'before' or 'after' defaults to before
9175          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9176          * @return {Roo.Element} the inserted Element
9177          */
9178         insertSibling: function(el, where, returnDom){
9179             where = where ? where.toLowerCase() : 'before';
9180             el = el || {};
9181             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9182
9183             if(typeof el == 'object' && !el.nodeType){ // dh config
9184                 if(where == 'after' && !this.dom.nextSibling){
9185                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9186                 }else{
9187                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9188                 }
9189
9190             }else{
9191                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9192                             where == 'before' ? this.dom : this.dom.nextSibling);
9193                 if(!returnDom){
9194                     rt = Roo.get(rt);
9195                 }
9196             }
9197             return rt;
9198         },
9199
9200         /**
9201          * Creates and wraps this element with another element
9202          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9203          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9204          * @return {HTMLElement/Element} The newly created wrapper element
9205          */
9206         wrap: function(config, returnDom){
9207             if(!config){
9208                 config = {tag: "div"};
9209             }
9210             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9211             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9212             return newEl;
9213         },
9214
9215         /**
9216          * Replaces the passed element with this element
9217          * @param {String/HTMLElement/Element} el The element to replace
9218          * @return {Roo.Element} this
9219          */
9220         replace: function(el){
9221             el = Roo.get(el);
9222             this.insertBefore(el);
9223             el.remove();
9224             return this;
9225         },
9226
9227         /**
9228          * Inserts an html fragment into this element
9229          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9230          * @param {String} html The HTML fragment
9231          * @param {Boolean} returnEl True to return an Roo.Element
9232          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9233          */
9234         insertHtml : function(where, html, returnEl){
9235             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9236             return returnEl ? Roo.get(el) : el;
9237         },
9238
9239         /**
9240          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9241          * @param {Object} o The object with the attributes
9242          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9243          * @return {Roo.Element} this
9244          */
9245         set : function(o, useSet){
9246             var el = this.dom;
9247             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9248             for(var attr in o){
9249                 if(attr == "style" || typeof o[attr] == "function") continue;
9250                 if(attr=="cls"){
9251                     el.className = o["cls"];
9252                 }else{
9253                     if(useSet) el.setAttribute(attr, o[attr]);
9254                     else el[attr] = o[attr];
9255                 }
9256             }
9257             if(o.style){
9258                 Roo.DomHelper.applyStyles(el, o.style);
9259             }
9260             return this;
9261         },
9262
9263         /**
9264          * Convenience method for constructing a KeyMap
9265          * @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:
9266          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9267          * @param {Function} fn The function to call
9268          * @param {Object} scope (optional) The scope of the function
9269          * @return {Roo.KeyMap} The KeyMap created
9270          */
9271         addKeyListener : function(key, fn, scope){
9272             var config;
9273             if(typeof key != "object" || key instanceof Array){
9274                 config = {
9275                     key: key,
9276                     fn: fn,
9277                     scope: scope
9278                 };
9279             }else{
9280                 config = {
9281                     key : key.key,
9282                     shift : key.shift,
9283                     ctrl : key.ctrl,
9284                     alt : key.alt,
9285                     fn: fn,
9286                     scope: scope
9287                 };
9288             }
9289             return new Roo.KeyMap(this, config);
9290         },
9291
9292         /**
9293          * Creates a KeyMap for this element
9294          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9295          * @return {Roo.KeyMap} The KeyMap created
9296          */
9297         addKeyMap : function(config){
9298             return new Roo.KeyMap(this, config);
9299         },
9300
9301         /**
9302          * Returns true if this element is scrollable.
9303          * @return {Boolean}
9304          */
9305          isScrollable : function(){
9306             var dom = this.dom;
9307             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9308         },
9309
9310         /**
9311          * 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().
9312          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9313          * @param {Number} value The new scroll value
9314          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9315          * @return {Element} this
9316          */
9317
9318         scrollTo : function(side, value, animate){
9319             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9320             if(!animate || !A){
9321                 this.dom[prop] = value;
9322             }else{
9323                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9324                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9325             }
9326             return this;
9327         },
9328
9329         /**
9330          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9331          * within this element's scrollable range.
9332          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9333          * @param {Number} distance How far to scroll the element in pixels
9334          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9335          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9336          * was scrolled as far as it could go.
9337          */
9338          scroll : function(direction, distance, animate){
9339              if(!this.isScrollable()){
9340                  return;
9341              }
9342              var el = this.dom;
9343              var l = el.scrollLeft, t = el.scrollTop;
9344              var w = el.scrollWidth, h = el.scrollHeight;
9345              var cw = el.clientWidth, ch = el.clientHeight;
9346              direction = direction.toLowerCase();
9347              var scrolled = false;
9348              var a = this.preanim(arguments, 2);
9349              switch(direction){
9350                  case "l":
9351                  case "left":
9352                      if(w - l > cw){
9353                          var v = Math.min(l + distance, w-cw);
9354                          this.scrollTo("left", v, a);
9355                          scrolled = true;
9356                      }
9357                      break;
9358                 case "r":
9359                 case "right":
9360                      if(l > 0){
9361                          var v = Math.max(l - distance, 0);
9362                          this.scrollTo("left", v, a);
9363                          scrolled = true;
9364                      }
9365                      break;
9366                 case "t":
9367                 case "top":
9368                 case "up":
9369                      if(t > 0){
9370                          var v = Math.max(t - distance, 0);
9371                          this.scrollTo("top", v, a);
9372                          scrolled = true;
9373                      }
9374                      break;
9375                 case "b":
9376                 case "bottom":
9377                 case "down":
9378                      if(h - t > ch){
9379                          var v = Math.min(t + distance, h-ch);
9380                          this.scrollTo("top", v, a);
9381                          scrolled = true;
9382                      }
9383                      break;
9384              }
9385              return scrolled;
9386         },
9387
9388         /**
9389          * Translates the passed page coordinates into left/top css values for this element
9390          * @param {Number/Array} x The page x or an array containing [x, y]
9391          * @param {Number} y The page y
9392          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9393          */
9394         translatePoints : function(x, y){
9395             if(typeof x == 'object' || x instanceof Array){
9396                 y = x[1]; x = x[0];
9397             }
9398             var p = this.getStyle('position');
9399             var o = this.getXY();
9400
9401             var l = parseInt(this.getStyle('left'), 10);
9402             var t = parseInt(this.getStyle('top'), 10);
9403
9404             if(isNaN(l)){
9405                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9406             }
9407             if(isNaN(t)){
9408                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9409             }
9410
9411             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9412         },
9413
9414         /**
9415          * Returns the current scroll position of the element.
9416          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9417          */
9418         getScroll : function(){
9419             var d = this.dom, doc = document;
9420             if(d == doc || d == doc.body){
9421                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9422                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9423                 return {left: l, top: t};
9424             }else{
9425                 return {left: d.scrollLeft, top: d.scrollTop};
9426             }
9427         },
9428
9429         /**
9430          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9431          * are convert to standard 6 digit hex color.
9432          * @param {String} attr The css attribute
9433          * @param {String} defaultValue The default value to use when a valid color isn't found
9434          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9435          * YUI color anims.
9436          */
9437         getColor : function(attr, defaultValue, prefix){
9438             var v = this.getStyle(attr);
9439             if(!v || v == "transparent" || v == "inherit") {
9440                 return defaultValue;
9441             }
9442             var color = typeof prefix == "undefined" ? "#" : prefix;
9443             if(v.substr(0, 4) == "rgb("){
9444                 var rvs = v.slice(4, v.length -1).split(",");
9445                 for(var i = 0; i < 3; i++){
9446                     var h = parseInt(rvs[i]).toString(16);
9447                     if(h < 16){
9448                         h = "0" + h;
9449                     }
9450                     color += h;
9451                 }
9452             } else {
9453                 if(v.substr(0, 1) == "#"){
9454                     if(v.length == 4) {
9455                         for(var i = 1; i < 4; i++){
9456                             var c = v.charAt(i);
9457                             color +=  c + c;
9458                         }
9459                     }else if(v.length == 7){
9460                         color += v.substr(1);
9461                     }
9462                 }
9463             }
9464             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9465         },
9466
9467         /**
9468          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9469          * gradient background, rounded corners and a 4-way shadow.
9470          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9471          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9472          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9473          * @return {Roo.Element} this
9474          */
9475         boxWrap : function(cls){
9476             cls = cls || 'x-box';
9477             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9478             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9479             return el;
9480         },
9481
9482         /**
9483          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9484          * @param {String} namespace The namespace in which to look for the attribute
9485          * @param {String} name The attribute name
9486          * @return {String} The attribute value
9487          */
9488         getAttributeNS : Roo.isIE ? function(ns, name){
9489             var d = this.dom;
9490             var type = typeof d[ns+":"+name];
9491             if(type != 'undefined' && type != 'unknown'){
9492                 return d[ns+":"+name];
9493             }
9494             return d[name];
9495         } : function(ns, name){
9496             var d = this.dom;
9497             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9498         }
9499     };
9500
9501     var ep = El.prototype;
9502
9503     /**
9504      * Appends an event handler (Shorthand for addListener)
9505      * @param {String}   eventName     The type of event to append
9506      * @param {Function} fn        The method the event invokes
9507      * @param {Object} scope       (optional) The scope (this object) of the fn
9508      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9509      * @method
9510      */
9511     ep.on = ep.addListener;
9512         // backwards compat
9513     ep.mon = ep.addListener;
9514
9515     /**
9516      * Removes an event handler from this element (shorthand for removeListener)
9517      * @param {String} eventName the type of event to remove
9518      * @param {Function} fn the method the event invokes
9519      * @return {Roo.Element} this
9520      * @method
9521      */
9522     ep.un = ep.removeListener;
9523
9524     /**
9525      * true to automatically adjust width and height settings for box-model issues (default to true)
9526      */
9527     ep.autoBoxAdjust = true;
9528
9529     // private
9530     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9531
9532     // private
9533     El.addUnits = function(v, defaultUnit){
9534         if(v === "" || v == "auto"){
9535             return v;
9536         }
9537         if(v === undefined){
9538             return '';
9539         }
9540         if(typeof v == "number" || !El.unitPattern.test(v)){
9541             return v + (defaultUnit || 'px');
9542         }
9543         return v;
9544     };
9545
9546     // special markup used throughout Roo when box wrapping elements
9547     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>';
9548     /**
9549      * Visibility mode constant - Use visibility to hide element
9550      * @static
9551      * @type Number
9552      */
9553     El.VISIBILITY = 1;
9554     /**
9555      * Visibility mode constant - Use display to hide element
9556      * @static
9557      * @type Number
9558      */
9559     El.DISPLAY = 2;
9560
9561     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9562     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9563     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9564
9565
9566
9567     /**
9568      * @private
9569      */
9570     El.cache = {};
9571
9572     var docEl;
9573
9574     /**
9575      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9576      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9577      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9578      * @return {Element} The Element object
9579      * @static
9580      */
9581     El.get = function(el){
9582         var ex, elm, id;
9583         if(!el){ return null; }
9584         if(typeof el == "string"){ // element id
9585             if(!(elm = document.getElementById(el))){
9586                 return null;
9587             }
9588             if(ex = El.cache[el]){
9589                 ex.dom = elm;
9590             }else{
9591                 ex = El.cache[el] = new El(elm);
9592             }
9593             return ex;
9594         }else if(el.tagName){ // dom element
9595             if(!(id = el.id)){
9596                 id = Roo.id(el);
9597             }
9598             if(ex = El.cache[id]){
9599                 ex.dom = el;
9600             }else{
9601                 ex = El.cache[id] = new El(el);
9602             }
9603             return ex;
9604         }else if(el instanceof El){
9605             if(el != docEl){
9606                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9607                                                               // catch case where it hasn't been appended
9608                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9609             }
9610             return el;
9611         }else if(el.isComposite){
9612             return el;
9613         }else if(el instanceof Array){
9614             return El.select(el);
9615         }else if(el == document){
9616             // create a bogus element object representing the document object
9617             if(!docEl){
9618                 var f = function(){};
9619                 f.prototype = El.prototype;
9620                 docEl = new f();
9621                 docEl.dom = document;
9622             }
9623             return docEl;
9624         }
9625         return null;
9626     };
9627
9628     // private
9629     El.uncache = function(el){
9630         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9631             if(a[i]){
9632                 delete El.cache[a[i].id || a[i]];
9633             }
9634         }
9635     };
9636
9637     // private
9638     // Garbage collection - uncache elements/purge listeners on orphaned elements
9639     // so we don't hold a reference and cause the browser to retain them
9640     El.garbageCollect = function(){
9641         if(!Roo.enableGarbageCollector){
9642             clearInterval(El.collectorThread);
9643             return;
9644         }
9645         for(var eid in El.cache){
9646             var el = El.cache[eid], d = el.dom;
9647             // -------------------------------------------------------
9648             // Determining what is garbage:
9649             // -------------------------------------------------------
9650             // !d
9651             // dom node is null, definitely garbage
9652             // -------------------------------------------------------
9653             // !d.parentNode
9654             // no parentNode == direct orphan, definitely garbage
9655             // -------------------------------------------------------
9656             // !d.offsetParent && !document.getElementById(eid)
9657             // display none elements have no offsetParent so we will
9658             // also try to look it up by it's id. However, check
9659             // offsetParent first so we don't do unneeded lookups.
9660             // This enables collection of elements that are not orphans
9661             // directly, but somewhere up the line they have an orphan
9662             // parent.
9663             // -------------------------------------------------------
9664             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9665                 delete El.cache[eid];
9666                 if(d && Roo.enableListenerCollection){
9667                     E.purgeElement(d);
9668                 }
9669             }
9670         }
9671     }
9672     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9673
9674
9675     // dom is optional
9676     El.Flyweight = function(dom){
9677         this.dom = dom;
9678     };
9679     El.Flyweight.prototype = El.prototype;
9680
9681     El._flyweights = {};
9682     /**
9683      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9684      * the dom node can be overwritten by other code.
9685      * @param {String/HTMLElement} el The dom node or id
9686      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9687      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9688      * @static
9689      * @return {Element} The shared Element object
9690      */
9691     El.fly = function(el, named){
9692         named = named || '_global';
9693         el = Roo.getDom(el);
9694         if(!el){
9695             return null;
9696         }
9697         if(!El._flyweights[named]){
9698             El._flyweights[named] = new El.Flyweight();
9699         }
9700         El._flyweights[named].dom = el;
9701         return El._flyweights[named];
9702     };
9703
9704     /**
9705      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9706      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9707      * Shorthand of {@link Roo.Element#get}
9708      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9709      * @return {Element} The Element object
9710      * @member Roo
9711      * @method get
9712      */
9713     Roo.get = El.get;
9714     /**
9715      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9716      * the dom node can be overwritten by other code.
9717      * Shorthand of {@link Roo.Element#fly}
9718      * @param {String/HTMLElement} el The dom node or id
9719      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9720      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9721      * @static
9722      * @return {Element} The shared Element object
9723      * @member Roo
9724      * @method fly
9725      */
9726     Roo.fly = El.fly;
9727
9728     // speedy lookup for elements never to box adjust
9729     var noBoxAdjust = Roo.isStrict ? {
9730         select:1
9731     } : {
9732         input:1, select:1, textarea:1
9733     };
9734     if(Roo.isIE || Roo.isGecko){
9735         noBoxAdjust['button'] = 1;
9736     }
9737
9738
9739     Roo.EventManager.on(window, 'unload', function(){
9740         delete El.cache;
9741         delete El._flyweights;
9742     });
9743 })();
9744
9745
9746
9747
9748 if(Roo.DomQuery){
9749     Roo.Element.selectorFunction = Roo.DomQuery.select;
9750 }
9751
9752 Roo.Element.select = function(selector, unique, root){
9753     var els;
9754     if(typeof selector == "string"){
9755         els = Roo.Element.selectorFunction(selector, root);
9756     }else if(selector.length !== undefined){
9757         els = selector;
9758     }else{
9759         throw "Invalid selector";
9760     }
9761     if(unique === true){
9762         return new Roo.CompositeElement(els);
9763     }else{
9764         return new Roo.CompositeElementLite(els);
9765     }
9766 };
9767 /**
9768  * Selects elements based on the passed CSS selector to enable working on them as 1.
9769  * @param {String/Array} selector The CSS selector or an array of elements
9770  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9771  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9772  * @return {CompositeElementLite/CompositeElement}
9773  * @member Roo
9774  * @method select
9775  */
9776 Roo.select = Roo.Element.select;
9777
9778
9779
9780
9781
9782
9783
9784
9785
9786
9787
9788
9789
9790
9791 /*
9792  * Based on:
9793  * Ext JS Library 1.1.1
9794  * Copyright(c) 2006-2007, Ext JS, LLC.
9795  *
9796  * Originally Released Under LGPL - original licence link has changed is not relivant.
9797  *
9798  * Fork - LGPL
9799  * <script type="text/javascript">
9800  */
9801
9802
9803
9804 //Notifies Element that fx methods are available
9805 Roo.enableFx = true;
9806
9807 /**
9808  * @class Roo.Fx
9809  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9810  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9811  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9812  * Element effects to work.</p><br/>
9813  *
9814  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9815  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9816  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9817  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9818  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9819  * expected results and should be done with care.</p><br/>
9820  *
9821  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9822  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9823 <pre>
9824 Value  Description
9825 -----  -----------------------------
9826 tl     The top left corner
9827 t      The center of the top edge
9828 tr     The top right corner
9829 l      The center of the left edge
9830 r      The center of the right edge
9831 bl     The bottom left corner
9832 b      The center of the bottom edge
9833 br     The bottom right corner
9834 </pre>
9835  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9836  * below are common options that can be passed to any Fx method.</b>
9837  * @cfg {Function} callback A function called when the effect is finished
9838  * @cfg {Object} scope The scope of the effect function
9839  * @cfg {String} easing A valid Easing value for the effect
9840  * @cfg {String} afterCls A css class to apply after the effect
9841  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9842  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9843  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9844  * effects that end with the element being visually hidden, ignored otherwise)
9845  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9846  * a function which returns such a specification that will be applied to the Element after the effect finishes
9847  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9848  * @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
9849  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9850  */
9851 Roo.Fx = {
9852         /**
9853          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9854          * origin for the slide effect.  This function automatically handles wrapping the element with
9855          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9856          * Usage:
9857          *<pre><code>
9858 // default: slide the element in from the top
9859 el.slideIn();
9860
9861 // custom: slide the element in from the right with a 2-second duration
9862 el.slideIn('r', { duration: 2 });
9863
9864 // common config options shown with default values
9865 el.slideIn('t', {
9866     easing: 'easeOut',
9867     duration: .5
9868 });
9869 </code></pre>
9870          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9871          * @param {Object} options (optional) Object literal with any of the Fx config options
9872          * @return {Roo.Element} The Element
9873          */
9874     slideIn : function(anchor, o){
9875         var el = this.getFxEl();
9876         o = o || {};
9877
9878         el.queueFx(o, function(){
9879
9880             anchor = anchor || "t";
9881
9882             // fix display to visibility
9883             this.fixDisplay();
9884
9885             // restore values after effect
9886             var r = this.getFxRestore();
9887             var b = this.getBox();
9888             // fixed size for slide
9889             this.setSize(b);
9890
9891             // wrap if needed
9892             var wrap = this.fxWrap(r.pos, o, "hidden");
9893
9894             var st = this.dom.style;
9895             st.visibility = "visible";
9896             st.position = "absolute";
9897
9898             // clear out temp styles after slide and unwrap
9899             var after = function(){
9900                 el.fxUnwrap(wrap, r.pos, o);
9901                 st.width = r.width;
9902                 st.height = r.height;
9903                 el.afterFx(o);
9904             };
9905             // time to calc the positions
9906             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9907
9908             switch(anchor.toLowerCase()){
9909                 case "t":
9910                     wrap.setSize(b.width, 0);
9911                     st.left = st.bottom = "0";
9912                     a = {height: bh};
9913                 break;
9914                 case "l":
9915                     wrap.setSize(0, b.height);
9916                     st.right = st.top = "0";
9917                     a = {width: bw};
9918                 break;
9919                 case "r":
9920                     wrap.setSize(0, b.height);
9921                     wrap.setX(b.right);
9922                     st.left = st.top = "0";
9923                     a = {width: bw, points: pt};
9924                 break;
9925                 case "b":
9926                     wrap.setSize(b.width, 0);
9927                     wrap.setY(b.bottom);
9928                     st.left = st.top = "0";
9929                     a = {height: bh, points: pt};
9930                 break;
9931                 case "tl":
9932                     wrap.setSize(0, 0);
9933                     st.right = st.bottom = "0";
9934                     a = {width: bw, height: bh};
9935                 break;
9936                 case "bl":
9937                     wrap.setSize(0, 0);
9938                     wrap.setY(b.y+b.height);
9939                     st.right = st.top = "0";
9940                     a = {width: bw, height: bh, points: pt};
9941                 break;
9942                 case "br":
9943                     wrap.setSize(0, 0);
9944                     wrap.setXY([b.right, b.bottom]);
9945                     st.left = st.top = "0";
9946                     a = {width: bw, height: bh, points: pt};
9947                 break;
9948                 case "tr":
9949                     wrap.setSize(0, 0);
9950                     wrap.setX(b.x+b.width);
9951                     st.left = st.bottom = "0";
9952                     a = {width: bw, height: bh, points: pt};
9953                 break;
9954             }
9955             this.dom.style.visibility = "visible";
9956             wrap.show();
9957
9958             arguments.callee.anim = wrap.fxanim(a,
9959                 o,
9960                 'motion',
9961                 .5,
9962                 'easeOut', after);
9963         });
9964         return this;
9965     },
9966     
9967         /**
9968          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9969          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9970          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9971          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9972          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9973          * Usage:
9974          *<pre><code>
9975 // default: slide the element out to the top
9976 el.slideOut();
9977
9978 // custom: slide the element out to the right with a 2-second duration
9979 el.slideOut('r', { duration: 2 });
9980
9981 // common config options shown with default values
9982 el.slideOut('t', {
9983     easing: 'easeOut',
9984     duration: .5,
9985     remove: false,
9986     useDisplay: false
9987 });
9988 </code></pre>
9989          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9990          * @param {Object} options (optional) Object literal with any of the Fx config options
9991          * @return {Roo.Element} The Element
9992          */
9993     slideOut : function(anchor, o){
9994         var el = this.getFxEl();
9995         o = o || {};
9996
9997         el.queueFx(o, function(){
9998
9999             anchor = anchor || "t";
10000
10001             // restore values after effect
10002             var r = this.getFxRestore();
10003             
10004             var b = this.getBox();
10005             // fixed size for slide
10006             this.setSize(b);
10007
10008             // wrap if needed
10009             var wrap = this.fxWrap(r.pos, o, "visible");
10010
10011             var st = this.dom.style;
10012             st.visibility = "visible";
10013             st.position = "absolute";
10014
10015             wrap.setSize(b);
10016
10017             var after = function(){
10018                 if(o.useDisplay){
10019                     el.setDisplayed(false);
10020                 }else{
10021                     el.hide();
10022                 }
10023
10024                 el.fxUnwrap(wrap, r.pos, o);
10025
10026                 st.width = r.width;
10027                 st.height = r.height;
10028
10029                 el.afterFx(o);
10030             };
10031
10032             var a, zero = {to: 0};
10033             switch(anchor.toLowerCase()){
10034                 case "t":
10035                     st.left = st.bottom = "0";
10036                     a = {height: zero};
10037                 break;
10038                 case "l":
10039                     st.right = st.top = "0";
10040                     a = {width: zero};
10041                 break;
10042                 case "r":
10043                     st.left = st.top = "0";
10044                     a = {width: zero, points: {to:[b.right, b.y]}};
10045                 break;
10046                 case "b":
10047                     st.left = st.top = "0";
10048                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10049                 break;
10050                 case "tl":
10051                     st.right = st.bottom = "0";
10052                     a = {width: zero, height: zero};
10053                 break;
10054                 case "bl":
10055                     st.right = st.top = "0";
10056                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10057                 break;
10058                 case "br":
10059                     st.left = st.top = "0";
10060                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10061                 break;
10062                 case "tr":
10063                     st.left = st.bottom = "0";
10064                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10065                 break;
10066             }
10067
10068             arguments.callee.anim = wrap.fxanim(a,
10069                 o,
10070                 'motion',
10071                 .5,
10072                 "easeOut", after);
10073         });
10074         return this;
10075     },
10076
10077         /**
10078          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10079          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10080          * The element must be removed from the DOM using the 'remove' config option if desired.
10081          * Usage:
10082          *<pre><code>
10083 // default
10084 el.puff();
10085
10086 // common config options shown with default values
10087 el.puff({
10088     easing: 'easeOut',
10089     duration: .5,
10090     remove: false,
10091     useDisplay: false
10092 });
10093 </code></pre>
10094          * @param {Object} options (optional) Object literal with any of the Fx config options
10095          * @return {Roo.Element} The Element
10096          */
10097     puff : function(o){
10098         var el = this.getFxEl();
10099         o = o || {};
10100
10101         el.queueFx(o, function(){
10102             this.clearOpacity();
10103             this.show();
10104
10105             // restore values after effect
10106             var r = this.getFxRestore();
10107             var st = this.dom.style;
10108
10109             var after = function(){
10110                 if(o.useDisplay){
10111                     el.setDisplayed(false);
10112                 }else{
10113                     el.hide();
10114                 }
10115
10116                 el.clearOpacity();
10117
10118                 el.setPositioning(r.pos);
10119                 st.width = r.width;
10120                 st.height = r.height;
10121                 st.fontSize = '';
10122                 el.afterFx(o);
10123             };
10124
10125             var width = this.getWidth();
10126             var height = this.getHeight();
10127
10128             arguments.callee.anim = this.fxanim({
10129                     width : {to: this.adjustWidth(width * 2)},
10130                     height : {to: this.adjustHeight(height * 2)},
10131                     points : {by: [-(width * .5), -(height * .5)]},
10132                     opacity : {to: 0},
10133                     fontSize: {to:200, unit: "%"}
10134                 },
10135                 o,
10136                 'motion',
10137                 .5,
10138                 "easeOut", after);
10139         });
10140         return this;
10141     },
10142
10143         /**
10144          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10145          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10146          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10147          * Usage:
10148          *<pre><code>
10149 // default
10150 el.switchOff();
10151
10152 // all config options shown with default values
10153 el.switchOff({
10154     easing: 'easeIn',
10155     duration: .3,
10156     remove: false,
10157     useDisplay: false
10158 });
10159 </code></pre>
10160          * @param {Object} options (optional) Object literal with any of the Fx config options
10161          * @return {Roo.Element} The Element
10162          */
10163     switchOff : function(o){
10164         var el = this.getFxEl();
10165         o = o || {};
10166
10167         el.queueFx(o, function(){
10168             this.clearOpacity();
10169             this.clip();
10170
10171             // restore values after effect
10172             var r = this.getFxRestore();
10173             var st = this.dom.style;
10174
10175             var after = function(){
10176                 if(o.useDisplay){
10177                     el.setDisplayed(false);
10178                 }else{
10179                     el.hide();
10180                 }
10181
10182                 el.clearOpacity();
10183                 el.setPositioning(r.pos);
10184                 st.width = r.width;
10185                 st.height = r.height;
10186
10187                 el.afterFx(o);
10188             };
10189
10190             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10191                 this.clearOpacity();
10192                 (function(){
10193                     this.fxanim({
10194                         height:{to:1},
10195                         points:{by:[0, this.getHeight() * .5]}
10196                     }, o, 'motion', 0.3, 'easeIn', after);
10197                 }).defer(100, this);
10198             });
10199         });
10200         return this;
10201     },
10202
10203     /**
10204      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10205      * changed using the "attr" config option) and then fading back to the original color. If no original
10206      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10207      * Usage:
10208 <pre><code>
10209 // default: highlight background to yellow
10210 el.highlight();
10211
10212 // custom: highlight foreground text to blue for 2 seconds
10213 el.highlight("0000ff", { attr: 'color', duration: 2 });
10214
10215 // common config options shown with default values
10216 el.highlight("ffff9c", {
10217     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10218     endColor: (current color) or "ffffff",
10219     easing: 'easeIn',
10220     duration: 1
10221 });
10222 </code></pre>
10223      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10224      * @param {Object} options (optional) Object literal with any of the Fx config options
10225      * @return {Roo.Element} The Element
10226      */ 
10227     highlight : function(color, o){
10228         var el = this.getFxEl();
10229         o = o || {};
10230
10231         el.queueFx(o, function(){
10232             color = color || "ffff9c";
10233             attr = o.attr || "backgroundColor";
10234
10235             this.clearOpacity();
10236             this.show();
10237
10238             var origColor = this.getColor(attr);
10239             var restoreColor = this.dom.style[attr];
10240             endColor = (o.endColor || origColor) || "ffffff";
10241
10242             var after = function(){
10243                 el.dom.style[attr] = restoreColor;
10244                 el.afterFx(o);
10245             };
10246
10247             var a = {};
10248             a[attr] = {from: color, to: endColor};
10249             arguments.callee.anim = this.fxanim(a,
10250                 o,
10251                 'color',
10252                 1,
10253                 'easeIn', after);
10254         });
10255         return this;
10256     },
10257
10258    /**
10259     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10260     * Usage:
10261 <pre><code>
10262 // default: a single light blue ripple
10263 el.frame();
10264
10265 // custom: 3 red ripples lasting 3 seconds total
10266 el.frame("ff0000", 3, { duration: 3 });
10267
10268 // common config options shown with default values
10269 el.frame("C3DAF9", 1, {
10270     duration: 1 //duration of entire animation (not each individual ripple)
10271     // Note: Easing is not configurable and will be ignored if included
10272 });
10273 </code></pre>
10274     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10275     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10276     * @param {Object} options (optional) Object literal with any of the Fx config options
10277     * @return {Roo.Element} The Element
10278     */
10279     frame : function(color, count, o){
10280         var el = this.getFxEl();
10281         o = o || {};
10282
10283         el.queueFx(o, function(){
10284             color = color || "#C3DAF9";
10285             if(color.length == 6){
10286                 color = "#" + color;
10287             }
10288             count = count || 1;
10289             duration = o.duration || 1;
10290             this.show();
10291
10292             var b = this.getBox();
10293             var animFn = function(){
10294                 var proxy = this.createProxy({
10295
10296                      style:{
10297                         visbility:"hidden",
10298                         position:"absolute",
10299                         "z-index":"35000", // yee haw
10300                         border:"0px solid " + color
10301                      }
10302                   });
10303                 var scale = Roo.isBorderBox ? 2 : 1;
10304                 proxy.animate({
10305                     top:{from:b.y, to:b.y - 20},
10306                     left:{from:b.x, to:b.x - 20},
10307                     borderWidth:{from:0, to:10},
10308                     opacity:{from:1, to:0},
10309                     height:{from:b.height, to:(b.height + (20*scale))},
10310                     width:{from:b.width, to:(b.width + (20*scale))}
10311                 }, duration, function(){
10312                     proxy.remove();
10313                 });
10314                 if(--count > 0){
10315                      animFn.defer((duration/2)*1000, this);
10316                 }else{
10317                     el.afterFx(o);
10318                 }
10319             };
10320             animFn.call(this);
10321         });
10322         return this;
10323     },
10324
10325    /**
10326     * Creates a pause before any subsequent queued effects begin.  If there are
10327     * no effects queued after the pause it will have no effect.
10328     * Usage:
10329 <pre><code>
10330 el.pause(1);
10331 </code></pre>
10332     * @param {Number} seconds The length of time to pause (in seconds)
10333     * @return {Roo.Element} The Element
10334     */
10335     pause : function(seconds){
10336         var el = this.getFxEl();
10337         var o = {};
10338
10339         el.queueFx(o, function(){
10340             setTimeout(function(){
10341                 el.afterFx(o);
10342             }, seconds * 1000);
10343         });
10344         return this;
10345     },
10346
10347    /**
10348     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10349     * using the "endOpacity" config option.
10350     * Usage:
10351 <pre><code>
10352 // default: fade in from opacity 0 to 100%
10353 el.fadeIn();
10354
10355 // custom: fade in from opacity 0 to 75% over 2 seconds
10356 el.fadeIn({ endOpacity: .75, duration: 2});
10357
10358 // common config options shown with default values
10359 el.fadeIn({
10360     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10361     easing: 'easeOut',
10362     duration: .5
10363 });
10364 </code></pre>
10365     * @param {Object} options (optional) Object literal with any of the Fx config options
10366     * @return {Roo.Element} The Element
10367     */
10368     fadeIn : function(o){
10369         var el = this.getFxEl();
10370         o = o || {};
10371         el.queueFx(o, function(){
10372             this.setOpacity(0);
10373             this.fixDisplay();
10374             this.dom.style.visibility = 'visible';
10375             var to = o.endOpacity || 1;
10376             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10377                 o, null, .5, "easeOut", function(){
10378                 if(to == 1){
10379                     this.clearOpacity();
10380                 }
10381                 el.afterFx(o);
10382             });
10383         });
10384         return this;
10385     },
10386
10387    /**
10388     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10389     * using the "endOpacity" config option.
10390     * Usage:
10391 <pre><code>
10392 // default: fade out from the element's current opacity to 0
10393 el.fadeOut();
10394
10395 // custom: fade out from the element's current opacity to 25% over 2 seconds
10396 el.fadeOut({ endOpacity: .25, duration: 2});
10397
10398 // common config options shown with default values
10399 el.fadeOut({
10400     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10401     easing: 'easeOut',
10402     duration: .5
10403     remove: false,
10404     useDisplay: false
10405 });
10406 </code></pre>
10407     * @param {Object} options (optional) Object literal with any of the Fx config options
10408     * @return {Roo.Element} The Element
10409     */
10410     fadeOut : function(o){
10411         var el = this.getFxEl();
10412         o = o || {};
10413         el.queueFx(o, function(){
10414             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10415                 o, null, .5, "easeOut", function(){
10416                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10417                      this.dom.style.display = "none";
10418                 }else{
10419                      this.dom.style.visibility = "hidden";
10420                 }
10421                 this.clearOpacity();
10422                 el.afterFx(o);
10423             });
10424         });
10425         return this;
10426     },
10427
10428    /**
10429     * Animates the transition of an element's dimensions from a starting height/width
10430     * to an ending height/width.
10431     * Usage:
10432 <pre><code>
10433 // change height and width to 100x100 pixels
10434 el.scale(100, 100);
10435
10436 // common config options shown with default values.  The height and width will default to
10437 // the element's existing values if passed as null.
10438 el.scale(
10439     [element's width],
10440     [element's height], {
10441     easing: 'easeOut',
10442     duration: .35
10443 });
10444 </code></pre>
10445     * @param {Number} width  The new width (pass undefined to keep the original width)
10446     * @param {Number} height  The new height (pass undefined to keep the original height)
10447     * @param {Object} options (optional) Object literal with any of the Fx config options
10448     * @return {Roo.Element} The Element
10449     */
10450     scale : function(w, h, o){
10451         this.shift(Roo.apply({}, o, {
10452             width: w,
10453             height: h
10454         }));
10455         return this;
10456     },
10457
10458    /**
10459     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10460     * Any of these properties not specified in the config object will not be changed.  This effect 
10461     * requires that at least one new dimension, position or opacity setting must be passed in on
10462     * the config object in order for the function to have any effect.
10463     * Usage:
10464 <pre><code>
10465 // slide the element horizontally to x position 200 while changing the height and opacity
10466 el.shift({ x: 200, height: 50, opacity: .8 });
10467
10468 // common config options shown with default values.
10469 el.shift({
10470     width: [element's width],
10471     height: [element's height],
10472     x: [element's x position],
10473     y: [element's y position],
10474     opacity: [element's opacity],
10475     easing: 'easeOut',
10476     duration: .35
10477 });
10478 </code></pre>
10479     * @param {Object} options  Object literal with any of the Fx config options
10480     * @return {Roo.Element} The Element
10481     */
10482     shift : function(o){
10483         var el = this.getFxEl();
10484         o = o || {};
10485         el.queueFx(o, function(){
10486             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10487             if(w !== undefined){
10488                 a.width = {to: this.adjustWidth(w)};
10489             }
10490             if(h !== undefined){
10491                 a.height = {to: this.adjustHeight(h)};
10492             }
10493             if(x !== undefined || y !== undefined){
10494                 a.points = {to: [
10495                     x !== undefined ? x : this.getX(),
10496                     y !== undefined ? y : this.getY()
10497                 ]};
10498             }
10499             if(op !== undefined){
10500                 a.opacity = {to: op};
10501             }
10502             if(o.xy !== undefined){
10503                 a.points = {to: o.xy};
10504             }
10505             arguments.callee.anim = this.fxanim(a,
10506                 o, 'motion', .35, "easeOut", function(){
10507                 el.afterFx(o);
10508             });
10509         });
10510         return this;
10511     },
10512
10513         /**
10514          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10515          * ending point of the effect.
10516          * Usage:
10517          *<pre><code>
10518 // default: slide the element downward while fading out
10519 el.ghost();
10520
10521 // custom: slide the element out to the right with a 2-second duration
10522 el.ghost('r', { duration: 2 });
10523
10524 // common config options shown with default values
10525 el.ghost('b', {
10526     easing: 'easeOut',
10527     duration: .5
10528     remove: false,
10529     useDisplay: false
10530 });
10531 </code></pre>
10532          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10533          * @param {Object} options (optional) Object literal with any of the Fx config options
10534          * @return {Roo.Element} The Element
10535          */
10536     ghost : function(anchor, o){
10537         var el = this.getFxEl();
10538         o = o || {};
10539
10540         el.queueFx(o, function(){
10541             anchor = anchor || "b";
10542
10543             // restore values after effect
10544             var r = this.getFxRestore();
10545             var w = this.getWidth(),
10546                 h = this.getHeight();
10547
10548             var st = this.dom.style;
10549
10550             var after = function(){
10551                 if(o.useDisplay){
10552                     el.setDisplayed(false);
10553                 }else{
10554                     el.hide();
10555                 }
10556
10557                 el.clearOpacity();
10558                 el.setPositioning(r.pos);
10559                 st.width = r.width;
10560                 st.height = r.height;
10561
10562                 el.afterFx(o);
10563             };
10564
10565             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10566             switch(anchor.toLowerCase()){
10567                 case "t":
10568                     pt.by = [0, -h];
10569                 break;
10570                 case "l":
10571                     pt.by = [-w, 0];
10572                 break;
10573                 case "r":
10574                     pt.by = [w, 0];
10575                 break;
10576                 case "b":
10577                     pt.by = [0, h];
10578                 break;
10579                 case "tl":
10580                     pt.by = [-w, -h];
10581                 break;
10582                 case "bl":
10583                     pt.by = [-w, h];
10584                 break;
10585                 case "br":
10586                     pt.by = [w, h];
10587                 break;
10588                 case "tr":
10589                     pt.by = [w, -h];
10590                 break;
10591             }
10592
10593             arguments.callee.anim = this.fxanim(a,
10594                 o,
10595                 'motion',
10596                 .5,
10597                 "easeOut", after);
10598         });
10599         return this;
10600     },
10601
10602         /**
10603          * Ensures that all effects queued after syncFx is called on the element are
10604          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10605          * @return {Roo.Element} The Element
10606          */
10607     syncFx : function(){
10608         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10609             block : false,
10610             concurrent : true,
10611             stopFx : false
10612         });
10613         return this;
10614     },
10615
10616         /**
10617          * Ensures that all effects queued after sequenceFx is called on the element are
10618          * run in sequence.  This is the opposite of {@link #syncFx}.
10619          * @return {Roo.Element} The Element
10620          */
10621     sequenceFx : function(){
10622         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10623             block : false,
10624             concurrent : false,
10625             stopFx : false
10626         });
10627         return this;
10628     },
10629
10630         /* @private */
10631     nextFx : function(){
10632         var ef = this.fxQueue[0];
10633         if(ef){
10634             ef.call(this);
10635         }
10636     },
10637
10638         /**
10639          * Returns true if the element has any effects actively running or queued, else returns false.
10640          * @return {Boolean} True if element has active effects, else false
10641          */
10642     hasActiveFx : function(){
10643         return this.fxQueue && this.fxQueue[0];
10644     },
10645
10646         /**
10647          * Stops any running effects and clears the element's internal effects queue if it contains
10648          * any additional effects that haven't started yet.
10649          * @return {Roo.Element} The Element
10650          */
10651     stopFx : function(){
10652         if(this.hasActiveFx()){
10653             var cur = this.fxQueue[0];
10654             if(cur && cur.anim && cur.anim.isAnimated()){
10655                 this.fxQueue = [cur]; // clear out others
10656                 cur.anim.stop(true);
10657             }
10658         }
10659         return this;
10660     },
10661
10662         /* @private */
10663     beforeFx : function(o){
10664         if(this.hasActiveFx() && !o.concurrent){
10665            if(o.stopFx){
10666                this.stopFx();
10667                return true;
10668            }
10669            return false;
10670         }
10671         return true;
10672     },
10673
10674         /**
10675          * Returns true if the element is currently blocking so that no other effect can be queued
10676          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10677          * used to ensure that an effect initiated by a user action runs to completion prior to the
10678          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10679          * @return {Boolean} True if blocking, else false
10680          */
10681     hasFxBlock : function(){
10682         var q = this.fxQueue;
10683         return q && q[0] && q[0].block;
10684     },
10685
10686         /* @private */
10687     queueFx : function(o, fn){
10688         if(!this.fxQueue){
10689             this.fxQueue = [];
10690         }
10691         if(!this.hasFxBlock()){
10692             Roo.applyIf(o, this.fxDefaults);
10693             if(!o.concurrent){
10694                 var run = this.beforeFx(o);
10695                 fn.block = o.block;
10696                 this.fxQueue.push(fn);
10697                 if(run){
10698                     this.nextFx();
10699                 }
10700             }else{
10701                 fn.call(this);
10702             }
10703         }
10704         return this;
10705     },
10706
10707         /* @private */
10708     fxWrap : function(pos, o, vis){
10709         var wrap;
10710         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10711             var wrapXY;
10712             if(o.fixPosition){
10713                 wrapXY = this.getXY();
10714             }
10715             var div = document.createElement("div");
10716             div.style.visibility = vis;
10717             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10718             wrap.setPositioning(pos);
10719             if(wrap.getStyle("position") == "static"){
10720                 wrap.position("relative");
10721             }
10722             this.clearPositioning('auto');
10723             wrap.clip();
10724             wrap.dom.appendChild(this.dom);
10725             if(wrapXY){
10726                 wrap.setXY(wrapXY);
10727             }
10728         }
10729         return wrap;
10730     },
10731
10732         /* @private */
10733     fxUnwrap : function(wrap, pos, o){
10734         this.clearPositioning();
10735         this.setPositioning(pos);
10736         if(!o.wrap){
10737             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10738             wrap.remove();
10739         }
10740     },
10741
10742         /* @private */
10743     getFxRestore : function(){
10744         var st = this.dom.style;
10745         return {pos: this.getPositioning(), width: st.width, height : st.height};
10746     },
10747
10748         /* @private */
10749     afterFx : function(o){
10750         if(o.afterStyle){
10751             this.applyStyles(o.afterStyle);
10752         }
10753         if(o.afterCls){
10754             this.addClass(o.afterCls);
10755         }
10756         if(o.remove === true){
10757             this.remove();
10758         }
10759         Roo.callback(o.callback, o.scope, [this]);
10760         if(!o.concurrent){
10761             this.fxQueue.shift();
10762             this.nextFx();
10763         }
10764     },
10765
10766         /* @private */
10767     getFxEl : function(){ // support for composite element fx
10768         return Roo.get(this.dom);
10769     },
10770
10771         /* @private */
10772     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10773         animType = animType || 'run';
10774         opt = opt || {};
10775         var anim = Roo.lib.Anim[animType](
10776             this.dom, args,
10777             (opt.duration || defaultDur) || .35,
10778             (opt.easing || defaultEase) || 'easeOut',
10779             function(){
10780                 Roo.callback(cb, this);
10781             },
10782             this
10783         );
10784         opt.anim = anim;
10785         return anim;
10786     }
10787 };
10788
10789 // backwords compat
10790 Roo.Fx.resize = Roo.Fx.scale;
10791
10792 //When included, Roo.Fx is automatically applied to Element so that all basic
10793 //effects are available directly via the Element API
10794 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10795  * Based on:
10796  * Ext JS Library 1.1.1
10797  * Copyright(c) 2006-2007, Ext JS, LLC.
10798  *
10799  * Originally Released Under LGPL - original licence link has changed is not relivant.
10800  *
10801  * Fork - LGPL
10802  * <script type="text/javascript">
10803  */
10804
10805
10806 /**
10807  * @class Roo.CompositeElement
10808  * Standard composite class. Creates a Roo.Element for every element in the collection.
10809  * <br><br>
10810  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10811  * actions will be performed on all the elements in this collection.</b>
10812  * <br><br>
10813  * All methods return <i>this</i> and can be chained.
10814  <pre><code>
10815  var els = Roo.select("#some-el div.some-class", true);
10816  // or select directly from an existing element
10817  var el = Roo.get('some-el');
10818  el.select('div.some-class', true);
10819
10820  els.setWidth(100); // all elements become 100 width
10821  els.hide(true); // all elements fade out and hide
10822  // or
10823  els.setWidth(100).hide(true);
10824  </code></pre>
10825  */
10826 Roo.CompositeElement = function(els){
10827     this.elements = [];
10828     this.addElements(els);
10829 };
10830 Roo.CompositeElement.prototype = {
10831     isComposite: true,
10832     addElements : function(els){
10833         if(!els) return this;
10834         if(typeof els == "string"){
10835             els = Roo.Element.selectorFunction(els);
10836         }
10837         var yels = this.elements;
10838         var index = yels.length-1;
10839         for(var i = 0, len = els.length; i < len; i++) {
10840                 yels[++index] = Roo.get(els[i]);
10841         }
10842         return this;
10843     },
10844
10845     /**
10846     * Clears this composite and adds the elements returned by the passed selector.
10847     * @param {String/Array} els A string CSS selector, an array of elements or an element
10848     * @return {CompositeElement} this
10849     */
10850     fill : function(els){
10851         this.elements = [];
10852         this.add(els);
10853         return this;
10854     },
10855
10856     /**
10857     * Filters this composite to only elements that match the passed selector.
10858     * @param {String} selector A string CSS selector
10859     * @return {CompositeElement} this
10860     */
10861     filter : function(selector){
10862         var els = [];
10863         this.each(function(el){
10864             if(el.is(selector)){
10865                 els[els.length] = el.dom;
10866             }
10867         });
10868         this.fill(els);
10869         return this;
10870     },
10871
10872     invoke : function(fn, args){
10873         var els = this.elements;
10874         for(var i = 0, len = els.length; i < len; i++) {
10875                 Roo.Element.prototype[fn].apply(els[i], args);
10876         }
10877         return this;
10878     },
10879     /**
10880     * Adds elements to this composite.
10881     * @param {String/Array} els A string CSS selector, an array of elements or an element
10882     * @return {CompositeElement} this
10883     */
10884     add : function(els){
10885         if(typeof els == "string"){
10886             this.addElements(Roo.Element.selectorFunction(els));
10887         }else if(els.length !== undefined){
10888             this.addElements(els);
10889         }else{
10890             this.addElements([els]);
10891         }
10892         return this;
10893     },
10894     /**
10895     * Calls the passed function passing (el, this, index) for each element in this composite.
10896     * @param {Function} fn The function to call
10897     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10898     * @return {CompositeElement} this
10899     */
10900     each : function(fn, scope){
10901         var els = this.elements;
10902         for(var i = 0, len = els.length; i < len; i++){
10903             if(fn.call(scope || els[i], els[i], this, i) === false) {
10904                 break;
10905             }
10906         }
10907         return this;
10908     },
10909
10910     /**
10911      * Returns the Element object at the specified index
10912      * @param {Number} index
10913      * @return {Roo.Element}
10914      */
10915     item : function(index){
10916         return this.elements[index] || null;
10917     },
10918
10919     /**
10920      * Returns the first Element
10921      * @return {Roo.Element}
10922      */
10923     first : function(){
10924         return this.item(0);
10925     },
10926
10927     /**
10928      * Returns the last Element
10929      * @return {Roo.Element}
10930      */
10931     last : function(){
10932         return this.item(this.elements.length-1);
10933     },
10934
10935     /**
10936      * Returns the number of elements in this composite
10937      * @return Number
10938      */
10939     getCount : function(){
10940         return this.elements.length;
10941     },
10942
10943     /**
10944      * Returns true if this composite contains the passed element
10945      * @return Boolean
10946      */
10947     contains : function(el){
10948         return this.indexOf(el) !== -1;
10949     },
10950
10951     /**
10952      * Returns true if this composite contains the passed element
10953      * @return Boolean
10954      */
10955     indexOf : function(el){
10956         return this.elements.indexOf(Roo.get(el));
10957     },
10958
10959
10960     /**
10961     * Removes the specified element(s).
10962     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10963     * or an array of any of those.
10964     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10965     * @return {CompositeElement} this
10966     */
10967     removeElement : function(el, removeDom){
10968         if(el instanceof Array){
10969             for(var i = 0, len = el.length; i < len; i++){
10970                 this.removeElement(el[i]);
10971             }
10972             return this;
10973         }
10974         var index = typeof el == 'number' ? el : this.indexOf(el);
10975         if(index !== -1){
10976             if(removeDom){
10977                 var d = this.elements[index];
10978                 if(d.dom){
10979                     d.remove();
10980                 }else{
10981                     d.parentNode.removeChild(d);
10982                 }
10983             }
10984             this.elements.splice(index, 1);
10985         }
10986         return this;
10987     },
10988
10989     /**
10990     * Replaces the specified element with the passed element.
10991     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10992     * to replace.
10993     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10994     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10995     * @return {CompositeElement} this
10996     */
10997     replaceElement : function(el, replacement, domReplace){
10998         var index = typeof el == 'number' ? el : this.indexOf(el);
10999         if(index !== -1){
11000             if(domReplace){
11001                 this.elements[index].replaceWith(replacement);
11002             }else{
11003                 this.elements.splice(index, 1, Roo.get(replacement))
11004             }
11005         }
11006         return this;
11007     },
11008
11009     /**
11010      * Removes all elements.
11011      */
11012     clear : function(){
11013         this.elements = [];
11014     }
11015 };
11016 (function(){
11017     Roo.CompositeElement.createCall = function(proto, fnName){
11018         if(!proto[fnName]){
11019             proto[fnName] = function(){
11020                 return this.invoke(fnName, arguments);
11021             };
11022         }
11023     };
11024     for(var fnName in Roo.Element.prototype){
11025         if(typeof Roo.Element.prototype[fnName] == "function"){
11026             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11027         }
11028     };
11029 })();
11030 /*
11031  * Based on:
11032  * Ext JS Library 1.1.1
11033  * Copyright(c) 2006-2007, Ext JS, LLC.
11034  *
11035  * Originally Released Under LGPL - original licence link has changed is not relivant.
11036  *
11037  * Fork - LGPL
11038  * <script type="text/javascript">
11039  */
11040
11041 /**
11042  * @class Roo.CompositeElementLite
11043  * @extends Roo.CompositeElement
11044  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11045  <pre><code>
11046  var els = Roo.select("#some-el div.some-class");
11047  // or select directly from an existing element
11048  var el = Roo.get('some-el');
11049  el.select('div.some-class');
11050
11051  els.setWidth(100); // all elements become 100 width
11052  els.hide(true); // all elements fade out and hide
11053  // or
11054  els.setWidth(100).hide(true);
11055  </code></pre><br><br>
11056  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11057  * actions will be performed on all the elements in this collection.</b>
11058  */
11059 Roo.CompositeElementLite = function(els){
11060     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11061     this.el = new Roo.Element.Flyweight();
11062 };
11063 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11064     addElements : function(els){
11065         if(els){
11066             if(els instanceof Array){
11067                 this.elements = this.elements.concat(els);
11068             }else{
11069                 var yels = this.elements;
11070                 var index = yels.length-1;
11071                 for(var i = 0, len = els.length; i < len; i++) {
11072                     yels[++index] = els[i];
11073                 }
11074             }
11075         }
11076         return this;
11077     },
11078     invoke : function(fn, args){
11079         var els = this.elements;
11080         var el = this.el;
11081         for(var i = 0, len = els.length; i < len; i++) {
11082             el.dom = els[i];
11083                 Roo.Element.prototype[fn].apply(el, args);
11084         }
11085         return this;
11086     },
11087     /**
11088      * Returns a flyweight Element of the dom element object at the specified index
11089      * @param {Number} index
11090      * @return {Roo.Element}
11091      */
11092     item : function(index){
11093         if(!this.elements[index]){
11094             return null;
11095         }
11096         this.el.dom = this.elements[index];
11097         return this.el;
11098     },
11099
11100     // fixes scope with flyweight
11101     addListener : function(eventName, handler, scope, opt){
11102         var els = this.elements;
11103         for(var i = 0, len = els.length; i < len; i++) {
11104             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11105         }
11106         return this;
11107     },
11108
11109     /**
11110     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11111     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11112     * a reference to the dom node, use el.dom.</b>
11113     * @param {Function} fn The function to call
11114     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11115     * @return {CompositeElement} this
11116     */
11117     each : function(fn, scope){
11118         var els = this.elements;
11119         var el = this.el;
11120         for(var i = 0, len = els.length; i < len; i++){
11121             el.dom = els[i];
11122                 if(fn.call(scope || el, el, this, i) === false){
11123                 break;
11124             }
11125         }
11126         return this;
11127     },
11128
11129     indexOf : function(el){
11130         return this.elements.indexOf(Roo.getDom(el));
11131     },
11132
11133     replaceElement : function(el, replacement, domReplace){
11134         var index = typeof el == 'number' ? el : this.indexOf(el);
11135         if(index !== -1){
11136             replacement = Roo.getDom(replacement);
11137             if(domReplace){
11138                 var d = this.elements[index];
11139                 d.parentNode.insertBefore(replacement, d);
11140                 d.parentNode.removeChild(d);
11141             }
11142             this.elements.splice(index, 1, replacement);
11143         }
11144         return this;
11145     }
11146 });
11147 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11148
11149 /*
11150  * Based on:
11151  * Ext JS Library 1.1.1
11152  * Copyright(c) 2006-2007, Ext JS, LLC.
11153  *
11154  * Originally Released Under LGPL - original licence link has changed is not relivant.
11155  *
11156  * Fork - LGPL
11157  * <script type="text/javascript">
11158  */
11159
11160  
11161
11162 /**
11163  * @class Roo.data.Connection
11164  * @extends Roo.util.Observable
11165  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11166  * either to a configured URL, or to a URL specified at request time.<br><br>
11167  * <p>
11168  * Requests made by this class are asynchronous, and will return immediately. No data from
11169  * the server will be available to the statement immediately following the {@link #request} call.
11170  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11171  * <p>
11172  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11173  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11174  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11175  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11176  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11177  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11178  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11179  * standard DOM methods.
11180  * @constructor
11181  * @param {Object} config a configuration object.
11182  */
11183 Roo.data.Connection = function(config){
11184     Roo.apply(this, config);
11185     this.addEvents({
11186         /**
11187          * @event beforerequest
11188          * Fires before a network request is made to retrieve a data object.
11189          * @param {Connection} conn This Connection object.
11190          * @param {Object} options The options config object passed to the {@link #request} method.
11191          */
11192         "beforerequest" : true,
11193         /**
11194          * @event requestcomplete
11195          * Fires if the request was successfully completed.
11196          * @param {Connection} conn This Connection object.
11197          * @param {Object} response The XHR object containing the response data.
11198          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11199          * @param {Object} options The options config object passed to the {@link #request} method.
11200          */
11201         "requestcomplete" : true,
11202         /**
11203          * @event requestexception
11204          * Fires if an error HTTP status was returned from the server.
11205          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11206          * @param {Connection} conn This Connection object.
11207          * @param {Object} response The XHR object containing the response data.
11208          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11209          * @param {Object} options The options config object passed to the {@link #request} method.
11210          */
11211         "requestexception" : true
11212     });
11213     Roo.data.Connection.superclass.constructor.call(this);
11214 };
11215
11216 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11217     /**
11218      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11219      */
11220     /**
11221      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11222      * extra parameters to each request made by this object. (defaults to undefined)
11223      */
11224     /**
11225      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11226      *  to each request made by this object. (defaults to undefined)
11227      */
11228     /**
11229      * @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)
11230      */
11231     /**
11232      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11233      */
11234     timeout : 30000,
11235     /**
11236      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11237      * @type Boolean
11238      */
11239     autoAbort:false,
11240
11241     /**
11242      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11243      * @type Boolean
11244      */
11245     disableCaching: true,
11246
11247     /**
11248      * Sends an HTTP request to a remote server.
11249      * @param {Object} options An object which may contain the following properties:<ul>
11250      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11251      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11252      * request, a url encoded string or a function to call to get either.</li>
11253      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11254      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11255      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11256      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11257      * <li>options {Object} The parameter to the request call.</li>
11258      * <li>success {Boolean} True if the request succeeded.</li>
11259      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11260      * </ul></li>
11261      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11262      * The callback is passed the following parameters:<ul>
11263      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11264      * <li>options {Object} The parameter to the request call.</li>
11265      * </ul></li>
11266      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11267      * The callback is passed the following parameters:<ul>
11268      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11269      * <li>options {Object} The parameter to the request call.</li>
11270      * </ul></li>
11271      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11272      * for the callback function. Defaults to the browser window.</li>
11273      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11274      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11275      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11276      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11277      * params for the post data. Any params will be appended to the URL.</li>
11278      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11279      * </ul>
11280      * @return {Number} transactionId
11281      */
11282     request : function(o){
11283         if(this.fireEvent("beforerequest", this, o) !== false){
11284             var p = o.params;
11285
11286             if(typeof p == "function"){
11287                 p = p.call(o.scope||window, o);
11288             }
11289             if(typeof p == "object"){
11290                 p = Roo.urlEncode(o.params);
11291             }
11292             if(this.extraParams){
11293                 var extras = Roo.urlEncode(this.extraParams);
11294                 p = p ? (p + '&' + extras) : extras;
11295             }
11296
11297             var url = o.url || this.url;
11298             if(typeof url == 'function'){
11299                 url = url.call(o.scope||window, o);
11300             }
11301
11302             if(o.form){
11303                 var form = Roo.getDom(o.form);
11304                 url = url || form.action;
11305
11306                 var enctype = form.getAttribute("enctype");
11307                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11308                     return this.doFormUpload(o, p, url);
11309                 }
11310                 var f = Roo.lib.Ajax.serializeForm(form);
11311                 p = p ? (p + '&' + f) : f;
11312             }
11313
11314             var hs = o.headers;
11315             if(this.defaultHeaders){
11316                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11317                 if(!o.headers){
11318                     o.headers = hs;
11319                 }
11320             }
11321
11322             var cb = {
11323                 success: this.handleResponse,
11324                 failure: this.handleFailure,
11325                 scope: this,
11326                 argument: {options: o},
11327                 timeout : this.timeout
11328             };
11329
11330             var method = o.method||this.method||(p ? "POST" : "GET");
11331
11332             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11333                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11334             }
11335
11336             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11337                 if(o.autoAbort){
11338                     this.abort();
11339                 }
11340             }else if(this.autoAbort !== false){
11341                 this.abort();
11342             }
11343
11344             if((method == 'GET' && p) || o.xmlData){
11345                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11346                 p = '';
11347             }
11348             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11349             return this.transId;
11350         }else{
11351             Roo.callback(o.callback, o.scope, [o, null, null]);
11352             return null;
11353         }
11354     },
11355
11356     /**
11357      * Determine whether this object has a request outstanding.
11358      * @param {Number} transactionId (Optional) defaults to the last transaction
11359      * @return {Boolean} True if there is an outstanding request.
11360      */
11361     isLoading : function(transId){
11362         if(transId){
11363             return Roo.lib.Ajax.isCallInProgress(transId);
11364         }else{
11365             return this.transId ? true : false;
11366         }
11367     },
11368
11369     /**
11370      * Aborts any outstanding request.
11371      * @param {Number} transactionId (Optional) defaults to the last transaction
11372      */
11373     abort : function(transId){
11374         if(transId || this.isLoading()){
11375             Roo.lib.Ajax.abort(transId || this.transId);
11376         }
11377     },
11378
11379     // private
11380     handleResponse : function(response){
11381         this.transId = false;
11382         var options = response.argument.options;
11383         response.argument = options ? options.argument : null;
11384         this.fireEvent("requestcomplete", this, response, options);
11385         Roo.callback(options.success, options.scope, [response, options]);
11386         Roo.callback(options.callback, options.scope, [options, true, response]);
11387     },
11388
11389     // private
11390     handleFailure : function(response, e){
11391         this.transId = false;
11392         var options = response.argument.options;
11393         response.argument = options ? options.argument : null;
11394         this.fireEvent("requestexception", this, response, options, e);
11395         Roo.callback(options.failure, options.scope, [response, options]);
11396         Roo.callback(options.callback, options.scope, [options, false, response]);
11397     },
11398
11399     // private
11400     doFormUpload : function(o, ps, url){
11401         var id = Roo.id();
11402         var frame = document.createElement('iframe');
11403         frame.id = id;
11404         frame.name = id;
11405         frame.className = 'x-hidden';
11406         if(Roo.isIE){
11407             frame.src = Roo.SSL_SECURE_URL;
11408         }
11409         document.body.appendChild(frame);
11410
11411         if(Roo.isIE){
11412            document.frames[id].name = id;
11413         }
11414
11415         var form = Roo.getDom(o.form);
11416         form.target = id;
11417         form.method = 'POST';
11418         form.enctype = form.encoding = 'multipart/form-data';
11419         if(url){
11420             form.action = url;
11421         }
11422
11423         var hiddens, hd;
11424         if(ps){ // add dynamic params
11425             hiddens = [];
11426             ps = Roo.urlDecode(ps, false);
11427             for(var k in ps){
11428                 if(ps.hasOwnProperty(k)){
11429                     hd = document.createElement('input');
11430                     hd.type = 'hidden';
11431                     hd.name = k;
11432                     hd.value = ps[k];
11433                     form.appendChild(hd);
11434                     hiddens.push(hd);
11435                 }
11436             }
11437         }
11438
11439         function cb(){
11440             var r = {  // bogus response object
11441                 responseText : '',
11442                 responseXML : null
11443             };
11444
11445             r.argument = o ? o.argument : null;
11446
11447             try { //
11448                 var doc;
11449                 if(Roo.isIE){
11450                     doc = frame.contentWindow.document;
11451                 }else {
11452                     doc = (frame.contentDocument || window.frames[id].document);
11453                 }
11454                 if(doc && doc.body){
11455                     r.responseText = doc.body.innerHTML;
11456                 }
11457                 if(doc && doc.XMLDocument){
11458                     r.responseXML = doc.XMLDocument;
11459                 }else {
11460                     r.responseXML = doc;
11461                 }
11462             }
11463             catch(e) {
11464                 // ignore
11465             }
11466
11467             Roo.EventManager.removeListener(frame, 'load', cb, this);
11468
11469             this.fireEvent("requestcomplete", this, r, o);
11470             Roo.callback(o.success, o.scope, [r, o]);
11471             Roo.callback(o.callback, o.scope, [o, true, r]);
11472
11473             setTimeout(function(){document.body.removeChild(frame);}, 100);
11474         }
11475
11476         Roo.EventManager.on(frame, 'load', cb, this);
11477         form.submit();
11478
11479         if(hiddens){ // remove dynamic params
11480             for(var i = 0, len = hiddens.length; i < len; i++){
11481                 form.removeChild(hiddens[i]);
11482             }
11483         }
11484     }
11485 });
11486
11487 /**
11488  * @class Roo.Ajax
11489  * @extends Roo.data.Connection
11490  * Global Ajax request class.
11491  *
11492  * @singleton
11493  */
11494 Roo.Ajax = new Roo.data.Connection({
11495     // fix up the docs
11496    /**
11497      * @cfg {String} url @hide
11498      */
11499     /**
11500      * @cfg {Object} extraParams @hide
11501      */
11502     /**
11503      * @cfg {Object} defaultHeaders @hide
11504      */
11505     /**
11506      * @cfg {String} method (Optional) @hide
11507      */
11508     /**
11509      * @cfg {Number} timeout (Optional) @hide
11510      */
11511     /**
11512      * @cfg {Boolean} autoAbort (Optional) @hide
11513      */
11514
11515     /**
11516      * @cfg {Boolean} disableCaching (Optional) @hide
11517      */
11518
11519     /**
11520      * @property  disableCaching
11521      * True to add a unique cache-buster param to GET requests. (defaults to true)
11522      * @type Boolean
11523      */
11524     /**
11525      * @property  url
11526      * The default URL to be used for requests to the server. (defaults to undefined)
11527      * @type String
11528      */
11529     /**
11530      * @property  extraParams
11531      * An object containing properties which are used as
11532      * extra parameters to each request made by this object. (defaults to undefined)
11533      * @type Object
11534      */
11535     /**
11536      * @property  defaultHeaders
11537      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11538      * @type Object
11539      */
11540     /**
11541      * @property  method
11542      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11543      * @type String
11544      */
11545     /**
11546      * @property  timeout
11547      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11548      * @type Number
11549      */
11550
11551     /**
11552      * @property  autoAbort
11553      * Whether a new request should abort any pending requests. (defaults to false)
11554      * @type Boolean
11555      */
11556     autoAbort : false,
11557
11558     /**
11559      * Serialize the passed form into a url encoded string
11560      * @param {String/HTMLElement} form
11561      * @return {String}
11562      */
11563     serializeForm : function(form){
11564         return Roo.lib.Ajax.serializeForm(form);
11565     }
11566 });/*
11567  * Based on:
11568  * Ext JS Library 1.1.1
11569  * Copyright(c) 2006-2007, Ext JS, LLC.
11570  *
11571  * Originally Released Under LGPL - original licence link has changed is not relivant.
11572  *
11573  * Fork - LGPL
11574  * <script type="text/javascript">
11575  */
11576  
11577 /**
11578  * Global Ajax request class.
11579  * 
11580  * @class Roo.Ajax
11581  * @extends Roo.data.Connection
11582  * @static
11583  * 
11584  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11585  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11586  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11587  * @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)
11588  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11589  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11590  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11591  */
11592 Roo.Ajax = new Roo.data.Connection({
11593     // fix up the docs
11594     /**
11595      * @scope Roo.Ajax
11596      * @type {Boolear} 
11597      */
11598     autoAbort : false,
11599
11600     /**
11601      * Serialize the passed form into a url encoded string
11602      * @scope Roo.Ajax
11603      * @param {String/HTMLElement} form
11604      * @return {String}
11605      */
11606     serializeForm : function(form){
11607         return Roo.lib.Ajax.serializeForm(form);
11608     }
11609 });/*
11610  * Based on:
11611  * Ext JS Library 1.1.1
11612  * Copyright(c) 2006-2007, Ext JS, LLC.
11613  *
11614  * Originally Released Under LGPL - original licence link has changed is not relivant.
11615  *
11616  * Fork - LGPL
11617  * <script type="text/javascript">
11618  */
11619
11620  
11621 /**
11622  * @class Roo.UpdateManager
11623  * @extends Roo.util.Observable
11624  * Provides AJAX-style update for Element object.<br><br>
11625  * Usage:<br>
11626  * <pre><code>
11627  * // Get it from a Roo.Element object
11628  * var el = Roo.get("foo");
11629  * var mgr = el.getUpdateManager();
11630  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11631  * ...
11632  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11633  * <br>
11634  * // or directly (returns the same UpdateManager instance)
11635  * var mgr = new Roo.UpdateManager("myElementId");
11636  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11637  * mgr.on("update", myFcnNeedsToKnow);
11638  * <br>
11639    // short handed call directly from the element object
11640    Roo.get("foo").load({
11641         url: "bar.php",
11642         scripts:true,
11643         params: "for=bar",
11644         text: "Loading Foo..."
11645    });
11646  * </code></pre>
11647  * @constructor
11648  * Create new UpdateManager directly.
11649  * @param {String/HTMLElement/Roo.Element} el The element to update
11650  * @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).
11651  */
11652 Roo.UpdateManager = function(el, forceNew){
11653     el = Roo.get(el);
11654     if(!forceNew && el.updateManager){
11655         return el.updateManager;
11656     }
11657     /**
11658      * The Element object
11659      * @type Roo.Element
11660      */
11661     this.el = el;
11662     /**
11663      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11664      * @type String
11665      */
11666     this.defaultUrl = null;
11667
11668     this.addEvents({
11669         /**
11670          * @event beforeupdate
11671          * Fired before an update is made, return false from your handler and the update is cancelled.
11672          * @param {Roo.Element} el
11673          * @param {String/Object/Function} url
11674          * @param {String/Object} params
11675          */
11676         "beforeupdate": true,
11677         /**
11678          * @event update
11679          * Fired after successful update is made.
11680          * @param {Roo.Element} el
11681          * @param {Object} oResponseObject The response Object
11682          */
11683         "update": true,
11684         /**
11685          * @event failure
11686          * Fired on update failure.
11687          * @param {Roo.Element} el
11688          * @param {Object} oResponseObject The response Object
11689          */
11690         "failure": true
11691     });
11692     var d = Roo.UpdateManager.defaults;
11693     /**
11694      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11695      * @type String
11696      */
11697     this.sslBlankUrl = d.sslBlankUrl;
11698     /**
11699      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11700      * @type Boolean
11701      */
11702     this.disableCaching = d.disableCaching;
11703     /**
11704      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11705      * @type String
11706      */
11707     this.indicatorText = d.indicatorText;
11708     /**
11709      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11710      * @type String
11711      */
11712     this.showLoadIndicator = d.showLoadIndicator;
11713     /**
11714      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11715      * @type Number
11716      */
11717     this.timeout = d.timeout;
11718
11719     /**
11720      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11721      * @type Boolean
11722      */
11723     this.loadScripts = d.loadScripts;
11724
11725     /**
11726      * Transaction object of current executing transaction
11727      */
11728     this.transaction = null;
11729
11730     /**
11731      * @private
11732      */
11733     this.autoRefreshProcId = null;
11734     /**
11735      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11736      * @type Function
11737      */
11738     this.refreshDelegate = this.refresh.createDelegate(this);
11739     /**
11740      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11741      * @type Function
11742      */
11743     this.updateDelegate = this.update.createDelegate(this);
11744     /**
11745      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11746      * @type Function
11747      */
11748     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11749     /**
11750      * @private
11751      */
11752     this.successDelegate = this.processSuccess.createDelegate(this);
11753     /**
11754      * @private
11755      */
11756     this.failureDelegate = this.processFailure.createDelegate(this);
11757
11758     if(!this.renderer){
11759      /**
11760       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11761       */
11762     this.renderer = new Roo.UpdateManager.BasicRenderer();
11763     }
11764     
11765     Roo.UpdateManager.superclass.constructor.call(this);
11766 };
11767
11768 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11769     /**
11770      * Get the Element this UpdateManager is bound to
11771      * @return {Roo.Element} The element
11772      */
11773     getEl : function(){
11774         return this.el;
11775     },
11776     /**
11777      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11778      * @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:
11779 <pre><code>
11780 um.update({<br/>
11781     url: "your-url.php",<br/>
11782     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11783     callback: yourFunction,<br/>
11784     scope: yourObject, //(optional scope)  <br/>
11785     discardUrl: false, <br/>
11786     nocache: false,<br/>
11787     text: "Loading...",<br/>
11788     timeout: 30,<br/>
11789     scripts: false<br/>
11790 });
11791 </code></pre>
11792      * The only required property is url. The optional properties nocache, text and scripts
11793      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11794      * @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}
11795      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11796      * @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.
11797      */
11798     update : function(url, params, callback, discardUrl){
11799         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11800             var method = this.method, cfg;
11801             if(typeof url == "object"){ // must be config object
11802                 cfg = url;
11803                 url = cfg.url;
11804                 params = params || cfg.params;
11805                 callback = callback || cfg.callback;
11806                 discardUrl = discardUrl || cfg.discardUrl;
11807                 if(callback && cfg.scope){
11808                     callback = callback.createDelegate(cfg.scope);
11809                 }
11810                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11811                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11812                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11813                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11814                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11815             }
11816             this.showLoading();
11817             if(!discardUrl){
11818                 this.defaultUrl = url;
11819             }
11820             if(typeof url == "function"){
11821                 url = url.call(this);
11822             }
11823
11824             method = method || (params ? "POST" : "GET");
11825             if(method == "GET"){
11826                 url = this.prepareUrl(url);
11827             }
11828
11829             var o = Roo.apply(cfg ||{}, {
11830                 url : url,
11831                 params: params,
11832                 success: this.successDelegate,
11833                 failure: this.failureDelegate,
11834                 callback: undefined,
11835                 timeout: (this.timeout*1000),
11836                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11837             });
11838
11839             this.transaction = Roo.Ajax.request(o);
11840         }
11841     },
11842
11843     /**
11844      * 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.
11845      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11846      * @param {String/HTMLElement} form The form Id or form element
11847      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11848      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11849      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11850      */
11851     formUpdate : function(form, url, reset, callback){
11852         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11853             if(typeof url == "function"){
11854                 url = url.call(this);
11855             }
11856             form = Roo.getDom(form);
11857             this.transaction = Roo.Ajax.request({
11858                 form: form,
11859                 url:url,
11860                 success: this.successDelegate,
11861                 failure: this.failureDelegate,
11862                 timeout: (this.timeout*1000),
11863                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11864             });
11865             this.showLoading.defer(1, this);
11866         }
11867     },
11868
11869     /**
11870      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11871      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11872      */
11873     refresh : function(callback){
11874         if(this.defaultUrl == null){
11875             return;
11876         }
11877         this.update(this.defaultUrl, null, callback, true);
11878     },
11879
11880     /**
11881      * Set this element to auto refresh.
11882      * @param {Number} interval How often to update (in seconds).
11883      * @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)
11884      * @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}
11885      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11886      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11887      */
11888     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11889         if(refreshNow){
11890             this.update(url || this.defaultUrl, params, callback, true);
11891         }
11892         if(this.autoRefreshProcId){
11893             clearInterval(this.autoRefreshProcId);
11894         }
11895         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11896     },
11897
11898     /**
11899      * Stop auto refresh on this element.
11900      */
11901      stopAutoRefresh : function(){
11902         if(this.autoRefreshProcId){
11903             clearInterval(this.autoRefreshProcId);
11904             delete this.autoRefreshProcId;
11905         }
11906     },
11907
11908     isAutoRefreshing : function(){
11909        return this.autoRefreshProcId ? true : false;
11910     },
11911     /**
11912      * Called to update the element to "Loading" state. Override to perform custom action.
11913      */
11914     showLoading : function(){
11915         if(this.showLoadIndicator){
11916             this.el.update(this.indicatorText);
11917         }
11918     },
11919
11920     /**
11921      * Adds unique parameter to query string if disableCaching = true
11922      * @private
11923      */
11924     prepareUrl : function(url){
11925         if(this.disableCaching){
11926             var append = "_dc=" + (new Date().getTime());
11927             if(url.indexOf("?") !== -1){
11928                 url += "&" + append;
11929             }else{
11930                 url += "?" + append;
11931             }
11932         }
11933         return url;
11934     },
11935
11936     /**
11937      * @private
11938      */
11939     processSuccess : function(response){
11940         this.transaction = null;
11941         if(response.argument.form && response.argument.reset){
11942             try{ // put in try/catch since some older FF releases had problems with this
11943                 response.argument.form.reset();
11944             }catch(e){}
11945         }
11946         if(this.loadScripts){
11947             this.renderer.render(this.el, response, this,
11948                 this.updateComplete.createDelegate(this, [response]));
11949         }else{
11950             this.renderer.render(this.el, response, this);
11951             this.updateComplete(response);
11952         }
11953     },
11954
11955     updateComplete : function(response){
11956         this.fireEvent("update", this.el, response);
11957         if(typeof response.argument.callback == "function"){
11958             response.argument.callback(this.el, true, response);
11959         }
11960     },
11961
11962     /**
11963      * @private
11964      */
11965     processFailure : function(response){
11966         this.transaction = null;
11967         this.fireEvent("failure", this.el, response);
11968         if(typeof response.argument.callback == "function"){
11969             response.argument.callback(this.el, false, response);
11970         }
11971     },
11972
11973     /**
11974      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11975      * @param {Object} renderer The object implementing the render() method
11976      */
11977     setRenderer : function(renderer){
11978         this.renderer = renderer;
11979     },
11980
11981     getRenderer : function(){
11982        return this.renderer;
11983     },
11984
11985     /**
11986      * Set the defaultUrl used for updates
11987      * @param {String/Function} defaultUrl The url or a function to call to get the url
11988      */
11989     setDefaultUrl : function(defaultUrl){
11990         this.defaultUrl = defaultUrl;
11991     },
11992
11993     /**
11994      * Aborts the executing transaction
11995      */
11996     abort : function(){
11997         if(this.transaction){
11998             Roo.Ajax.abort(this.transaction);
11999         }
12000     },
12001
12002     /**
12003      * Returns true if an update is in progress
12004      * @return {Boolean}
12005      */
12006     isUpdating : function(){
12007         if(this.transaction){
12008             return Roo.Ajax.isLoading(this.transaction);
12009         }
12010         return false;
12011     }
12012 });
12013
12014 /**
12015  * @class Roo.UpdateManager.defaults
12016  * @static (not really - but it helps the doc tool)
12017  * The defaults collection enables customizing the default properties of UpdateManager
12018  */
12019    Roo.UpdateManager.defaults = {
12020        /**
12021          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12022          * @type Number
12023          */
12024          timeout : 30,
12025
12026          /**
12027          * True to process scripts by default (Defaults to false).
12028          * @type Boolean
12029          */
12030         loadScripts : false,
12031
12032         /**
12033         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12034         * @type String
12035         */
12036         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12037         /**
12038          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12039          * @type Boolean
12040          */
12041         disableCaching : false,
12042         /**
12043          * Whether to show indicatorText when loading (Defaults to true).
12044          * @type Boolean
12045          */
12046         showLoadIndicator : true,
12047         /**
12048          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12049          * @type String
12050          */
12051         indicatorText : '<div class="loading-indicator">Loading...</div>'
12052    };
12053
12054 /**
12055  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12056  *Usage:
12057  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12058  * @param {String/HTMLElement/Roo.Element} el The element to update
12059  * @param {String} url The url
12060  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12061  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12062  * @static
12063  * @deprecated
12064  * @member Roo.UpdateManager
12065  */
12066 Roo.UpdateManager.updateElement = function(el, url, params, options){
12067     var um = Roo.get(el, true).getUpdateManager();
12068     Roo.apply(um, options);
12069     um.update(url, params, options ? options.callback : null);
12070 };
12071 // alias for backwards compat
12072 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12073 /**
12074  * @class Roo.UpdateManager.BasicRenderer
12075  * Default Content renderer. Updates the elements innerHTML with the responseText.
12076  */
12077 Roo.UpdateManager.BasicRenderer = function(){};
12078
12079 Roo.UpdateManager.BasicRenderer.prototype = {
12080     /**
12081      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12082      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12083      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12084      * @param {Roo.Element} el The element being rendered
12085      * @param {Object} response The YUI Connect response object
12086      * @param {UpdateManager} updateManager The calling update manager
12087      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12088      */
12089      render : function(el, response, updateManager, callback){
12090         el.update(response.responseText, updateManager.loadScripts, callback);
12091     }
12092 };
12093 /*
12094  * Based on:
12095  * Ext JS Library 1.1.1
12096  * Copyright(c) 2006-2007, Ext JS, LLC.
12097  *
12098  * Originally Released Under LGPL - original licence link has changed is not relivant.
12099  *
12100  * Fork - LGPL
12101  * <script type="text/javascript">
12102  */
12103
12104 /**
12105  * @class Roo.util.DelayedTask
12106  * Provides a convenient method of performing setTimeout where a new
12107  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12108  * You can use this class to buffer
12109  * the keypress events for a certain number of milliseconds, and perform only if they stop
12110  * for that amount of time.
12111  * @constructor The parameters to this constructor serve as defaults and are not required.
12112  * @param {Function} fn (optional) The default function to timeout
12113  * @param {Object} scope (optional) The default scope of that timeout
12114  * @param {Array} args (optional) The default Array of arguments
12115  */
12116 Roo.util.DelayedTask = function(fn, scope, args){
12117     var id = null, d, t;
12118
12119     var call = function(){
12120         var now = new Date().getTime();
12121         if(now - t >= d){
12122             clearInterval(id);
12123             id = null;
12124             fn.apply(scope, args || []);
12125         }
12126     };
12127     /**
12128      * Cancels any pending timeout and queues a new one
12129      * @param {Number} delay The milliseconds to delay
12130      * @param {Function} newFn (optional) Overrides function passed to constructor
12131      * @param {Object} newScope (optional) Overrides scope passed to constructor
12132      * @param {Array} newArgs (optional) Overrides args passed to constructor
12133      */
12134     this.delay = function(delay, newFn, newScope, newArgs){
12135         if(id && delay != d){
12136             this.cancel();
12137         }
12138         d = delay;
12139         t = new Date().getTime();
12140         fn = newFn || fn;
12141         scope = newScope || scope;
12142         args = newArgs || args;
12143         if(!id){
12144             id = setInterval(call, d);
12145         }
12146     };
12147
12148     /**
12149      * Cancel the last queued timeout
12150      */
12151     this.cancel = function(){
12152         if(id){
12153             clearInterval(id);
12154             id = null;
12155         }
12156     };
12157 };/*
12158  * Based on:
12159  * Ext JS Library 1.1.1
12160  * Copyright(c) 2006-2007, Ext JS, LLC.
12161  *
12162  * Originally Released Under LGPL - original licence link has changed is not relivant.
12163  *
12164  * Fork - LGPL
12165  * <script type="text/javascript">
12166  */
12167  
12168  
12169 Roo.util.TaskRunner = function(interval){
12170     interval = interval || 10;
12171     var tasks = [], removeQueue = [];
12172     var id = 0;
12173     var running = false;
12174
12175     var stopThread = function(){
12176         running = false;
12177         clearInterval(id);
12178         id = 0;
12179     };
12180
12181     var startThread = function(){
12182         if(!running){
12183             running = true;
12184             id = setInterval(runTasks, interval);
12185         }
12186     };
12187
12188     var removeTask = function(task){
12189         removeQueue.push(task);
12190         if(task.onStop){
12191             task.onStop();
12192         }
12193     };
12194
12195     var runTasks = function(){
12196         if(removeQueue.length > 0){
12197             for(var i = 0, len = removeQueue.length; i < len; i++){
12198                 tasks.remove(removeQueue[i]);
12199             }
12200             removeQueue = [];
12201             if(tasks.length < 1){
12202                 stopThread();
12203                 return;
12204             }
12205         }
12206         var now = new Date().getTime();
12207         for(var i = 0, len = tasks.length; i < len; ++i){
12208             var t = tasks[i];
12209             var itime = now - t.taskRunTime;
12210             if(t.interval <= itime){
12211                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12212                 t.taskRunTime = now;
12213                 if(rt === false || t.taskRunCount === t.repeat){
12214                     removeTask(t);
12215                     return;
12216                 }
12217             }
12218             if(t.duration && t.duration <= (now - t.taskStartTime)){
12219                 removeTask(t);
12220             }
12221         }
12222     };
12223
12224     /**
12225      * Queues a new task.
12226      * @param {Object} task
12227      */
12228     this.start = function(task){
12229         tasks.push(task);
12230         task.taskStartTime = new Date().getTime();
12231         task.taskRunTime = 0;
12232         task.taskRunCount = 0;
12233         startThread();
12234         return task;
12235     };
12236
12237     this.stop = function(task){
12238         removeTask(task);
12239         return task;
12240     };
12241
12242     this.stopAll = function(){
12243         stopThread();
12244         for(var i = 0, len = tasks.length; i < len; i++){
12245             if(tasks[i].onStop){
12246                 tasks[i].onStop();
12247             }
12248         }
12249         tasks = [];
12250         removeQueue = [];
12251     };
12252 };
12253
12254 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12255  * Based on:
12256  * Ext JS Library 1.1.1
12257  * Copyright(c) 2006-2007, Ext JS, LLC.
12258  *
12259  * Originally Released Under LGPL - original licence link has changed is not relivant.
12260  *
12261  * Fork - LGPL
12262  * <script type="text/javascript">
12263  */
12264
12265  
12266 /**
12267  * @class Roo.util.MixedCollection
12268  * @extends Roo.util.Observable
12269  * A Collection class that maintains both numeric indexes and keys and exposes events.
12270  * @constructor
12271  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12272  * collection (defaults to false)
12273  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12274  * and return the key value for that item.  This is used when available to look up the key on items that
12275  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12276  * equivalent to providing an implementation for the {@link #getKey} method.
12277  */
12278 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12279     this.items = [];
12280     this.map = {};
12281     this.keys = [];
12282     this.length = 0;
12283     this.addEvents({
12284         /**
12285          * @event clear
12286          * Fires when the collection is cleared.
12287          */
12288         "clear" : true,
12289         /**
12290          * @event add
12291          * Fires when an item is added to the collection.
12292          * @param {Number} index The index at which the item was added.
12293          * @param {Object} o The item added.
12294          * @param {String} key The key associated with the added item.
12295          */
12296         "add" : true,
12297         /**
12298          * @event replace
12299          * Fires when an item is replaced in the collection.
12300          * @param {String} key he key associated with the new added.
12301          * @param {Object} old The item being replaced.
12302          * @param {Object} new The new item.
12303          */
12304         "replace" : true,
12305         /**
12306          * @event remove
12307          * Fires when an item is removed from the collection.
12308          * @param {Object} o The item being removed.
12309          * @param {String} key (optional) The key associated with the removed item.
12310          */
12311         "remove" : true,
12312         "sort" : true
12313     });
12314     this.allowFunctions = allowFunctions === true;
12315     if(keyFn){
12316         this.getKey = keyFn;
12317     }
12318     Roo.util.MixedCollection.superclass.constructor.call(this);
12319 };
12320
12321 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12322     allowFunctions : false,
12323     
12324 /**
12325  * Adds an item to the collection.
12326  * @param {String} key The key to associate with the item
12327  * @param {Object} o The item to add.
12328  * @return {Object} The item added.
12329  */
12330     add : function(key, o){
12331         if(arguments.length == 1){
12332             o = arguments[0];
12333             key = this.getKey(o);
12334         }
12335         if(typeof key == "undefined" || key === null){
12336             this.length++;
12337             this.items.push(o);
12338             this.keys.push(null);
12339         }else{
12340             var old = this.map[key];
12341             if(old){
12342                 return this.replace(key, o);
12343             }
12344             this.length++;
12345             this.items.push(o);
12346             this.map[key] = o;
12347             this.keys.push(key);
12348         }
12349         this.fireEvent("add", this.length-1, o, key);
12350         return o;
12351     },
12352        
12353 /**
12354   * MixedCollection has a generic way to fetch keys if you implement getKey.
12355 <pre><code>
12356 // normal way
12357 var mc = new Roo.util.MixedCollection();
12358 mc.add(someEl.dom.id, someEl);
12359 mc.add(otherEl.dom.id, otherEl);
12360 //and so on
12361
12362 // using getKey
12363 var mc = new Roo.util.MixedCollection();
12364 mc.getKey = function(el){
12365    return el.dom.id;
12366 };
12367 mc.add(someEl);
12368 mc.add(otherEl);
12369
12370 // or via the constructor
12371 var mc = new Roo.util.MixedCollection(false, function(el){
12372    return el.dom.id;
12373 });
12374 mc.add(someEl);
12375 mc.add(otherEl);
12376 </code></pre>
12377  * @param o {Object} The item for which to find the key.
12378  * @return {Object} The key for the passed item.
12379  */
12380     getKey : function(o){
12381          return o.id; 
12382     },
12383    
12384 /**
12385  * Replaces an item in the collection.
12386  * @param {String} key The key associated with the item to replace, or the item to replace.
12387  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12388  * @return {Object}  The new item.
12389  */
12390     replace : function(key, o){
12391         if(arguments.length == 1){
12392             o = arguments[0];
12393             key = this.getKey(o);
12394         }
12395         var old = this.item(key);
12396         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12397              return this.add(key, o);
12398         }
12399         var index = this.indexOfKey(key);
12400         this.items[index] = o;
12401         this.map[key] = o;
12402         this.fireEvent("replace", key, old, o);
12403         return o;
12404     },
12405    
12406 /**
12407  * Adds all elements of an Array or an Object to the collection.
12408  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12409  * an Array of values, each of which are added to the collection.
12410  */
12411     addAll : function(objs){
12412         if(arguments.length > 1 || objs instanceof Array){
12413             var args = arguments.length > 1 ? arguments : objs;
12414             for(var i = 0, len = args.length; i < len; i++){
12415                 this.add(args[i]);
12416             }
12417         }else{
12418             for(var key in objs){
12419                 if(this.allowFunctions || typeof objs[key] != "function"){
12420                     this.add(key, objs[key]);
12421                 }
12422             }
12423         }
12424     },
12425    
12426 /**
12427  * Executes the specified function once for every item in the collection, passing each
12428  * item as the first and only parameter. returning false from the function will stop the iteration.
12429  * @param {Function} fn The function to execute for each item.
12430  * @param {Object} scope (optional) The scope in which to execute the function.
12431  */
12432     each : function(fn, scope){
12433         var items = [].concat(this.items); // each safe for removal
12434         for(var i = 0, len = items.length; i < len; i++){
12435             if(fn.call(scope || items[i], items[i], i, len) === false){
12436                 break;
12437             }
12438         }
12439     },
12440    
12441 /**
12442  * Executes the specified function once for every key in the collection, passing each
12443  * key, and its associated item as the first two parameters.
12444  * @param {Function} fn The function to execute for each item.
12445  * @param {Object} scope (optional) The scope in which to execute the function.
12446  */
12447     eachKey : function(fn, scope){
12448         for(var i = 0, len = this.keys.length; i < len; i++){
12449             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12450         }
12451     },
12452    
12453 /**
12454  * Returns the first item in the collection which elicits a true return value from the
12455  * passed selection function.
12456  * @param {Function} fn The selection function to execute for each item.
12457  * @param {Object} scope (optional) The scope in which to execute the function.
12458  * @return {Object} The first item in the collection which returned true from the selection function.
12459  */
12460     find : function(fn, scope){
12461         for(var i = 0, len = this.items.length; i < len; i++){
12462             if(fn.call(scope || window, this.items[i], this.keys[i])){
12463                 return this.items[i];
12464             }
12465         }
12466         return null;
12467     },
12468    
12469 /**
12470  * Inserts an item at the specified index in the collection.
12471  * @param {Number} index The index to insert the item at.
12472  * @param {String} key The key to associate with the new item, or the item itself.
12473  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12474  * @return {Object} The item inserted.
12475  */
12476     insert : function(index, key, o){
12477         if(arguments.length == 2){
12478             o = arguments[1];
12479             key = this.getKey(o);
12480         }
12481         if(index >= this.length){
12482             return this.add(key, o);
12483         }
12484         this.length++;
12485         this.items.splice(index, 0, o);
12486         if(typeof key != "undefined" && key != null){
12487             this.map[key] = o;
12488         }
12489         this.keys.splice(index, 0, key);
12490         this.fireEvent("add", index, o, key);
12491         return o;
12492     },
12493    
12494 /**
12495  * Removed an item from the collection.
12496  * @param {Object} o The item to remove.
12497  * @return {Object} The item removed.
12498  */
12499     remove : function(o){
12500         return this.removeAt(this.indexOf(o));
12501     },
12502    
12503 /**
12504  * Remove an item from a specified index in the collection.
12505  * @param {Number} index The index within the collection of the item to remove.
12506  */
12507     removeAt : function(index){
12508         if(index < this.length && index >= 0){
12509             this.length--;
12510             var o = this.items[index];
12511             this.items.splice(index, 1);
12512             var key = this.keys[index];
12513             if(typeof key != "undefined"){
12514                 delete this.map[key];
12515             }
12516             this.keys.splice(index, 1);
12517             this.fireEvent("remove", o, key);
12518         }
12519     },
12520    
12521 /**
12522  * Removed an item associated with the passed key fom the collection.
12523  * @param {String} key The key of the item to remove.
12524  */
12525     removeKey : function(key){
12526         return this.removeAt(this.indexOfKey(key));
12527     },
12528    
12529 /**
12530  * Returns the number of items in the collection.
12531  * @return {Number} the number of items in the collection.
12532  */
12533     getCount : function(){
12534         return this.length; 
12535     },
12536    
12537 /**
12538  * Returns index within the collection of the passed Object.
12539  * @param {Object} o The item to find the index of.
12540  * @return {Number} index of the item.
12541  */
12542     indexOf : function(o){
12543         if(!this.items.indexOf){
12544             for(var i = 0, len = this.items.length; i < len; i++){
12545                 if(this.items[i] == o) return i;
12546             }
12547             return -1;
12548         }else{
12549             return this.items.indexOf(o);
12550         }
12551     },
12552    
12553 /**
12554  * Returns index within the collection of the passed key.
12555  * @param {String} key The key to find the index of.
12556  * @return {Number} index of the key.
12557  */
12558     indexOfKey : function(key){
12559         if(!this.keys.indexOf){
12560             for(var i = 0, len = this.keys.length; i < len; i++){
12561                 if(this.keys[i] == key) return i;
12562             }
12563             return -1;
12564         }else{
12565             return this.keys.indexOf(key);
12566         }
12567     },
12568    
12569 /**
12570  * Returns the item associated with the passed key OR index. Key has priority over index.
12571  * @param {String/Number} key The key or index of the item.
12572  * @return {Object} The item associated with the passed key.
12573  */
12574     item : function(key){
12575         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12576         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12577     },
12578     
12579 /**
12580  * Returns the item at the specified index.
12581  * @param {Number} index The index of the item.
12582  * @return {Object}
12583  */
12584     itemAt : function(index){
12585         return this.items[index];
12586     },
12587     
12588 /**
12589  * Returns the item associated with the passed key.
12590  * @param {String/Number} key The key of the item.
12591  * @return {Object} The item associated with the passed key.
12592  */
12593     key : function(key){
12594         return this.map[key];
12595     },
12596    
12597 /**
12598  * Returns true if the collection contains the passed Object as an item.
12599  * @param {Object} o  The Object to look for in the collection.
12600  * @return {Boolean} True if the collection contains the Object as an item.
12601  */
12602     contains : function(o){
12603         return this.indexOf(o) != -1;
12604     },
12605    
12606 /**
12607  * Returns true if the collection contains the passed Object as a key.
12608  * @param {String} key The key to look for in the collection.
12609  * @return {Boolean} True if the collection contains the Object as a key.
12610  */
12611     containsKey : function(key){
12612         return typeof this.map[key] != "undefined";
12613     },
12614    
12615 /**
12616  * Removes all items from the collection.
12617  */
12618     clear : function(){
12619         this.length = 0;
12620         this.items = [];
12621         this.keys = [];
12622         this.map = {};
12623         this.fireEvent("clear");
12624     },
12625    
12626 /**
12627  * Returns the first item in the collection.
12628  * @return {Object} the first item in the collection..
12629  */
12630     first : function(){
12631         return this.items[0]; 
12632     },
12633    
12634 /**
12635  * Returns the last item in the collection.
12636  * @return {Object} the last item in the collection..
12637  */
12638     last : function(){
12639         return this.items[this.length-1];   
12640     },
12641     
12642     _sort : function(property, dir, fn){
12643         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12644         fn = fn || function(a, b){
12645             return a-b;
12646         };
12647         var c = [], k = this.keys, items = this.items;
12648         for(var i = 0, len = items.length; i < len; i++){
12649             c[c.length] = {key: k[i], value: items[i], index: i};
12650         }
12651         c.sort(function(a, b){
12652             var v = fn(a[property], b[property]) * dsc;
12653             if(v == 0){
12654                 v = (a.index < b.index ? -1 : 1);
12655             }
12656             return v;
12657         });
12658         for(var i = 0, len = c.length; i < len; i++){
12659             items[i] = c[i].value;
12660             k[i] = c[i].key;
12661         }
12662         this.fireEvent("sort", this);
12663     },
12664     
12665     /**
12666      * Sorts this collection with the passed comparison function
12667      * @param {String} direction (optional) "ASC" or "DESC"
12668      * @param {Function} fn (optional) comparison function
12669      */
12670     sort : function(dir, fn){
12671         this._sort("value", dir, fn);
12672     },
12673     
12674     /**
12675      * Sorts this collection by keys
12676      * @param {String} direction (optional) "ASC" or "DESC"
12677      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12678      */
12679     keySort : function(dir, fn){
12680         this._sort("key", dir, fn || function(a, b){
12681             return String(a).toUpperCase()-String(b).toUpperCase();
12682         });
12683     },
12684     
12685     /**
12686      * Returns a range of items in this collection
12687      * @param {Number} startIndex (optional) defaults to 0
12688      * @param {Number} endIndex (optional) default to the last item
12689      * @return {Array} An array of items
12690      */
12691     getRange : function(start, end){
12692         var items = this.items;
12693         if(items.length < 1){
12694             return [];
12695         }
12696         start = start || 0;
12697         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12698         var r = [];
12699         if(start <= end){
12700             for(var i = start; i <= end; i++) {
12701                     r[r.length] = items[i];
12702             }
12703         }else{
12704             for(var i = start; i >= end; i--) {
12705                     r[r.length] = items[i];
12706             }
12707         }
12708         return r;
12709     },
12710         
12711     /**
12712      * Filter the <i>objects</i> in this collection by a specific property. 
12713      * Returns a new collection that has been filtered.
12714      * @param {String} property A property on your objects
12715      * @param {String/RegExp} value Either string that the property values 
12716      * should start with or a RegExp to test against the property
12717      * @return {MixedCollection} The new filtered collection
12718      */
12719     filter : function(property, value){
12720         if(!value.exec){ // not a regex
12721             value = String(value);
12722             if(value.length == 0){
12723                 return this.clone();
12724             }
12725             value = new RegExp("^" + Roo.escapeRe(value), "i");
12726         }
12727         return this.filterBy(function(o){
12728             return o && value.test(o[property]);
12729         });
12730         },
12731     
12732     /**
12733      * Filter by a function. * Returns a new collection that has been filtered.
12734      * The passed function will be called with each 
12735      * object in the collection. If the function returns true, the value is included 
12736      * otherwise it is filtered.
12737      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12738      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12739      * @return {MixedCollection} The new filtered collection
12740      */
12741     filterBy : function(fn, scope){
12742         var r = new Roo.util.MixedCollection();
12743         r.getKey = this.getKey;
12744         var k = this.keys, it = this.items;
12745         for(var i = 0, len = it.length; i < len; i++){
12746             if(fn.call(scope||this, it[i], k[i])){
12747                                 r.add(k[i], it[i]);
12748                         }
12749         }
12750         return r;
12751     },
12752     
12753     /**
12754      * Creates a duplicate of this collection
12755      * @return {MixedCollection}
12756      */
12757     clone : function(){
12758         var r = new Roo.util.MixedCollection();
12759         var k = this.keys, it = this.items;
12760         for(var i = 0, len = it.length; i < len; i++){
12761             r.add(k[i], it[i]);
12762         }
12763         r.getKey = this.getKey;
12764         return r;
12765     }
12766 });
12767 /**
12768  * Returns the item associated with the passed key or index.
12769  * @method
12770  * @param {String/Number} key The key or index of the item.
12771  * @return {Object} The item associated with the passed key.
12772  */
12773 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12774  * Based on:
12775  * Ext JS Library 1.1.1
12776  * Copyright(c) 2006-2007, Ext JS, LLC.
12777  *
12778  * Originally Released Under LGPL - original licence link has changed is not relivant.
12779  *
12780  * Fork - LGPL
12781  * <script type="text/javascript">
12782  */
12783 /**
12784  * @class Roo.util.JSON
12785  * Modified version of Douglas Crockford"s json.js that doesn"t
12786  * mess with the Object prototype 
12787  * http://www.json.org/js.html
12788  * @singleton
12789  */
12790 Roo.util.JSON = new (function(){
12791     var useHasOwn = {}.hasOwnProperty ? true : false;
12792     
12793     // crashes Safari in some instances
12794     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12795     
12796     var pad = function(n) {
12797         return n < 10 ? "0" + n : n;
12798     };
12799     
12800     var m = {
12801         "\b": '\\b',
12802         "\t": '\\t',
12803         "\n": '\\n',
12804         "\f": '\\f',
12805         "\r": '\\r',
12806         '"' : '\\"',
12807         "\\": '\\\\'
12808     };
12809
12810     var encodeString = function(s){
12811         if (/["\\\x00-\x1f]/.test(s)) {
12812             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12813                 var c = m[b];
12814                 if(c){
12815                     return c;
12816                 }
12817                 c = b.charCodeAt();
12818                 return "\\u00" +
12819                     Math.floor(c / 16).toString(16) +
12820                     (c % 16).toString(16);
12821             }) + '"';
12822         }
12823         return '"' + s + '"';
12824     };
12825     
12826     var encodeArray = function(o){
12827         var a = ["["], b, i, l = o.length, v;
12828             for (i = 0; i < l; i += 1) {
12829                 v = o[i];
12830                 switch (typeof v) {
12831                     case "undefined":
12832                     case "function":
12833                     case "unknown":
12834                         break;
12835                     default:
12836                         if (b) {
12837                             a.push(',');
12838                         }
12839                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12840                         b = true;
12841                 }
12842             }
12843             a.push("]");
12844             return a.join("");
12845     };
12846     
12847     var encodeDate = function(o){
12848         return '"' + o.getFullYear() + "-" +
12849                 pad(o.getMonth() + 1) + "-" +
12850                 pad(o.getDate()) + "T" +
12851                 pad(o.getHours()) + ":" +
12852                 pad(o.getMinutes()) + ":" +
12853                 pad(o.getSeconds()) + '"';
12854     };
12855     
12856     /**
12857      * Encodes an Object, Array or other value
12858      * @param {Mixed} o The variable to encode
12859      * @return {String} The JSON string
12860      */
12861     this.encode = function(o)
12862     {
12863         // should this be extended to fully wrap stringify..
12864         
12865         if(typeof o == "undefined" || o === null){
12866             return "null";
12867         }else if(o instanceof Array){
12868             return encodeArray(o);
12869         }else if(o instanceof Date){
12870             return encodeDate(o);
12871         }else if(typeof o == "string"){
12872             return encodeString(o);
12873         }else if(typeof o == "number"){
12874             return isFinite(o) ? String(o) : "null";
12875         }else if(typeof o == "boolean"){
12876             return String(o);
12877         }else {
12878             var a = ["{"], b, i, v;
12879             for (i in o) {
12880                 if(!useHasOwn || o.hasOwnProperty(i)) {
12881                     v = o[i];
12882                     switch (typeof v) {
12883                     case "undefined":
12884                     case "function":
12885                     case "unknown":
12886                         break;
12887                     default:
12888                         if(b){
12889                             a.push(',');
12890                         }
12891                         a.push(this.encode(i), ":",
12892                                 v === null ? "null" : this.encode(v));
12893                         b = true;
12894                     }
12895                 }
12896             }
12897             a.push("}");
12898             return a.join("");
12899         }
12900     };
12901     
12902     /**
12903      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12904      * @param {String} json The JSON string
12905      * @return {Object} The resulting object
12906      */
12907     this.decode = function(json){
12908         
12909         return  /** eval:var:json */ eval("(" + json + ')');
12910     };
12911 })();
12912 /** 
12913  * Shorthand for {@link Roo.util.JSON#encode}
12914  * @member Roo encode 
12915  * @method */
12916 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12917 /** 
12918  * Shorthand for {@link Roo.util.JSON#decode}
12919  * @member Roo decode 
12920  * @method */
12921 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12922 /*
12923  * Based on:
12924  * Ext JS Library 1.1.1
12925  * Copyright(c) 2006-2007, Ext JS, LLC.
12926  *
12927  * Originally Released Under LGPL - original licence link has changed is not relivant.
12928  *
12929  * Fork - LGPL
12930  * <script type="text/javascript">
12931  */
12932  
12933 /**
12934  * @class Roo.util.Format
12935  * Reusable data formatting functions
12936  * @singleton
12937  */
12938 Roo.util.Format = function(){
12939     var trimRe = /^\s+|\s+$/g;
12940     return {
12941         /**
12942          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12943          * @param {String} value The string to truncate
12944          * @param {Number} length The maximum length to allow before truncating
12945          * @return {String} The converted text
12946          */
12947         ellipsis : function(value, len){
12948             if(value && value.length > len){
12949                 return value.substr(0, len-3)+"...";
12950             }
12951             return value;
12952         },
12953
12954         /**
12955          * Checks a reference and converts it to empty string if it is undefined
12956          * @param {Mixed} value Reference to check
12957          * @return {Mixed} Empty string if converted, otherwise the original value
12958          */
12959         undef : function(value){
12960             return typeof value != "undefined" ? value : "";
12961         },
12962
12963         /**
12964          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12965          * @param {String} value The string to encode
12966          * @return {String} The encoded text
12967          */
12968         htmlEncode : function(value){
12969             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12970         },
12971
12972         /**
12973          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12974          * @param {String} value The string to decode
12975          * @return {String} The decoded text
12976          */
12977         htmlDecode : function(value){
12978             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12979         },
12980
12981         /**
12982          * Trims any whitespace from either side of a string
12983          * @param {String} value The text to trim
12984          * @return {String} The trimmed text
12985          */
12986         trim : function(value){
12987             return String(value).replace(trimRe, "");
12988         },
12989
12990         /**
12991          * Returns a substring from within an original string
12992          * @param {String} value The original text
12993          * @param {Number} start The start index of the substring
12994          * @param {Number} length The length of the substring
12995          * @return {String} The substring
12996          */
12997         substr : function(value, start, length){
12998             return String(value).substr(start, length);
12999         },
13000
13001         /**
13002          * Converts a string to all lower case letters
13003          * @param {String} value The text to convert
13004          * @return {String} The converted text
13005          */
13006         lowercase : function(value){
13007             return String(value).toLowerCase();
13008         },
13009
13010         /**
13011          * Converts a string to all upper case letters
13012          * @param {String} value The text to convert
13013          * @return {String} The converted text
13014          */
13015         uppercase : function(value){
13016             return String(value).toUpperCase();
13017         },
13018
13019         /**
13020          * Converts the first character only of a string to upper case
13021          * @param {String} value The text to convert
13022          * @return {String} The converted text
13023          */
13024         capitalize : function(value){
13025             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13026         },
13027
13028         // private
13029         call : function(value, fn){
13030             if(arguments.length > 2){
13031                 var args = Array.prototype.slice.call(arguments, 2);
13032                 args.unshift(value);
13033                  
13034                 return /** eval:var:value */  eval(fn).apply(window, args);
13035             }else{
13036                 /** eval:var:value */
13037                 return /** eval:var:value */ eval(fn).call(window, value);
13038             }
13039         },
13040
13041        
13042         /**
13043          * safer version of Math.toFixed..??/
13044          * @param {Number/String} value The numeric value to format
13045          * @param {Number/String} value Decimal places 
13046          * @return {String} The formatted currency string
13047          */
13048         toFixed : function(v, n)
13049         {
13050             // why not use to fixed - precision is buggered???
13051             if (!n) {
13052                 return Math.round(v-0);
13053             }
13054             var fact = Math.pow(10,n+1);
13055             v = (Math.round((v-0)*fact))/fact;
13056             var z = (''+fact).substring(2);
13057             if (v == Math.floor(v)) {
13058                 return Math.floor(v) + '.' + z;
13059             }
13060             
13061             // now just padd decimals..
13062             var ps = String(v).split('.');
13063             var fd = (ps[1] + z);
13064             var r = fd.substring(0,n); 
13065             var rm = fd.substring(n); 
13066             if (rm < 5) {
13067                 return ps[0] + '.' + r;
13068             }
13069             r*=1; // turn it into a number;
13070             r++;
13071             if (String(r).length != n) {
13072                 ps[0]*=1;
13073                 ps[0]++;
13074                 r = String(r).substring(1); // chop the end off.
13075             }
13076             
13077             return ps[0] + '.' + r;
13078              
13079         },
13080         
13081         /**
13082          * Format a number as US currency
13083          * @param {Number/String} value The numeric value to format
13084          * @return {String} The formatted currency string
13085          */
13086         usMoney : function(v){
13087             v = (Math.round((v-0)*100))/100;
13088             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13089             v = String(v);
13090             var ps = v.split('.');
13091             var whole = ps[0];
13092             var sub = ps[1] ? '.'+ ps[1] : '.00';
13093             var r = /(\d+)(\d{3})/;
13094             while (r.test(whole)) {
13095                 whole = whole.replace(r, '$1' + ',' + '$2');
13096             }
13097             return "$" + whole + sub ;
13098         },
13099         
13100         /**
13101          * Parse a value into a formatted date using the specified format pattern.
13102          * @param {Mixed} value The value to format
13103          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13104          * @return {String} The formatted date string
13105          */
13106         date : function(v, format){
13107             if(!v){
13108                 return "";
13109             }
13110             if(!(v instanceof Date)){
13111                 v = new Date(Date.parse(v));
13112             }
13113             return v.dateFormat(format || "m/d/Y");
13114         },
13115
13116         /**
13117          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13118          * @param {String} format Any valid date format string
13119          * @return {Function} The date formatting function
13120          */
13121         dateRenderer : function(format){
13122             return function(v){
13123                 return Roo.util.Format.date(v, format);  
13124             };
13125         },
13126
13127         // private
13128         stripTagsRE : /<\/?[^>]+>/gi,
13129         
13130         /**
13131          * Strips all HTML tags
13132          * @param {Mixed} value The text from which to strip tags
13133          * @return {String} The stripped text
13134          */
13135         stripTags : function(v){
13136             return !v ? v : String(v).replace(this.stripTagsRE, "");
13137         }
13138     };
13139 }();/*
13140  * Based on:
13141  * Ext JS Library 1.1.1
13142  * Copyright(c) 2006-2007, Ext JS, LLC.
13143  *
13144  * Originally Released Under LGPL - original licence link has changed is not relivant.
13145  *
13146  * Fork - LGPL
13147  * <script type="text/javascript">
13148  */
13149
13150
13151  
13152
13153 /**
13154  * @class Roo.MasterTemplate
13155  * @extends Roo.Template
13156  * Provides a template that can have child templates. The syntax is:
13157 <pre><code>
13158 var t = new Roo.MasterTemplate(
13159         '&lt;select name="{name}"&gt;',
13160                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13161         '&lt;/select&gt;'
13162 );
13163 t.add('options', {value: 'foo', text: 'bar'});
13164 // or you can add multiple child elements in one shot
13165 t.addAll('options', [
13166     {value: 'foo', text: 'bar'},
13167     {value: 'foo2', text: 'bar2'},
13168     {value: 'foo3', text: 'bar3'}
13169 ]);
13170 // then append, applying the master template values
13171 t.append('my-form', {name: 'my-select'});
13172 </code></pre>
13173 * A name attribute for the child template is not required if you have only one child
13174 * template or you want to refer to them by index.
13175  */
13176 Roo.MasterTemplate = function(){
13177     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13178     this.originalHtml = this.html;
13179     var st = {};
13180     var m, re = this.subTemplateRe;
13181     re.lastIndex = 0;
13182     var subIndex = 0;
13183     while(m = re.exec(this.html)){
13184         var name = m[1], content = m[2];
13185         st[subIndex] = {
13186             name: name,
13187             index: subIndex,
13188             buffer: [],
13189             tpl : new Roo.Template(content)
13190         };
13191         if(name){
13192             st[name] = st[subIndex];
13193         }
13194         st[subIndex].tpl.compile();
13195         st[subIndex].tpl.call = this.call.createDelegate(this);
13196         subIndex++;
13197     }
13198     this.subCount = subIndex;
13199     this.subs = st;
13200 };
13201 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13202     /**
13203     * The regular expression used to match sub templates
13204     * @type RegExp
13205     * @property
13206     */
13207     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13208
13209     /**
13210      * Applies the passed values to a child template.
13211      * @param {String/Number} name (optional) The name or index of the child template
13212      * @param {Array/Object} values The values to be applied to the template
13213      * @return {MasterTemplate} this
13214      */
13215      add : function(name, values){
13216         if(arguments.length == 1){
13217             values = arguments[0];
13218             name = 0;
13219         }
13220         var s = this.subs[name];
13221         s.buffer[s.buffer.length] = s.tpl.apply(values);
13222         return this;
13223     },
13224
13225     /**
13226      * Applies all the passed values to a child template.
13227      * @param {String/Number} name (optional) The name or index of the child template
13228      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13229      * @param {Boolean} reset (optional) True to reset the template first
13230      * @return {MasterTemplate} this
13231      */
13232     fill : function(name, values, reset){
13233         var a = arguments;
13234         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13235             values = a[0];
13236             name = 0;
13237             reset = a[1];
13238         }
13239         if(reset){
13240             this.reset();
13241         }
13242         for(var i = 0, len = values.length; i < len; i++){
13243             this.add(name, values[i]);
13244         }
13245         return this;
13246     },
13247
13248     /**
13249      * Resets the template for reuse
13250      * @return {MasterTemplate} this
13251      */
13252      reset : function(){
13253         var s = this.subs;
13254         for(var i = 0; i < this.subCount; i++){
13255             s[i].buffer = [];
13256         }
13257         return this;
13258     },
13259
13260     applyTemplate : function(values){
13261         var s = this.subs;
13262         var replaceIndex = -1;
13263         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13264             return s[++replaceIndex].buffer.join("");
13265         });
13266         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13267     },
13268
13269     apply : function(){
13270         return this.applyTemplate.apply(this, arguments);
13271     },
13272
13273     compile : function(){return this;}
13274 });
13275
13276 /**
13277  * Alias for fill().
13278  * @method
13279  */
13280 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13281  /**
13282  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13283  * var tpl = Roo.MasterTemplate.from('element-id');
13284  * @param {String/HTMLElement} el
13285  * @param {Object} config
13286  * @static
13287  */
13288 Roo.MasterTemplate.from = function(el, config){
13289     el = Roo.getDom(el);
13290     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13291 };/*
13292  * Based on:
13293  * Ext JS Library 1.1.1
13294  * Copyright(c) 2006-2007, Ext JS, LLC.
13295  *
13296  * Originally Released Under LGPL - original licence link has changed is not relivant.
13297  *
13298  * Fork - LGPL
13299  * <script type="text/javascript">
13300  */
13301
13302  
13303 /**
13304  * @class Roo.util.CSS
13305  * Utility class for manipulating CSS rules
13306  * @singleton
13307  */
13308 Roo.util.CSS = function(){
13309         var rules = null;
13310         var doc = document;
13311
13312     var camelRe = /(-[a-z])/gi;
13313     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13314
13315    return {
13316    /**
13317     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13318     * tag and appended to the HEAD of the document.
13319     * @param {String|Object} cssText The text containing the css rules
13320     * @param {String} id An id to add to the stylesheet for later removal
13321     * @return {StyleSheet}
13322     */
13323     createStyleSheet : function(cssText, id){
13324         var ss;
13325         var head = doc.getElementsByTagName("head")[0];
13326         var nrules = doc.createElement("style");
13327         nrules.setAttribute("type", "text/css");
13328         if(id){
13329             nrules.setAttribute("id", id);
13330         }
13331         if (typeof(cssText) != 'string') {
13332             // support object maps..
13333             // not sure if this a good idea.. 
13334             // perhaps it should be merged with the general css handling
13335             // and handle js style props.
13336             var cssTextNew = [];
13337             for(var n in cssText) {
13338                 var citems = [];
13339                 for(var k in cssText[n]) {
13340                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13341                 }
13342                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13343                 
13344             }
13345             cssText = cssTextNew.join("\n");
13346             
13347         }
13348        
13349        
13350        if(Roo.isIE){
13351            head.appendChild(nrules);
13352            ss = nrules.styleSheet;
13353            ss.cssText = cssText;
13354        }else{
13355            try{
13356                 nrules.appendChild(doc.createTextNode(cssText));
13357            }catch(e){
13358                nrules.cssText = cssText; 
13359            }
13360            head.appendChild(nrules);
13361            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13362        }
13363        this.cacheStyleSheet(ss);
13364        return ss;
13365    },
13366
13367    /**
13368     * Removes a style or link tag by id
13369     * @param {String} id The id of the tag
13370     */
13371    removeStyleSheet : function(id){
13372        var existing = doc.getElementById(id);
13373        if(existing){
13374            existing.parentNode.removeChild(existing);
13375        }
13376    },
13377
13378    /**
13379     * Dynamically swaps an existing stylesheet reference for a new one
13380     * @param {String} id The id of an existing link tag to remove
13381     * @param {String} url The href of the new stylesheet to include
13382     */
13383    swapStyleSheet : function(id, url){
13384        this.removeStyleSheet(id);
13385        var ss = doc.createElement("link");
13386        ss.setAttribute("rel", "stylesheet");
13387        ss.setAttribute("type", "text/css");
13388        ss.setAttribute("id", id);
13389        ss.setAttribute("href", url);
13390        doc.getElementsByTagName("head")[0].appendChild(ss);
13391    },
13392    
13393    /**
13394     * Refresh the rule cache if you have dynamically added stylesheets
13395     * @return {Object} An object (hash) of rules indexed by selector
13396     */
13397    refreshCache : function(){
13398        return this.getRules(true);
13399    },
13400
13401    // private
13402    cacheStyleSheet : function(stylesheet){
13403        if(!rules){
13404            rules = {};
13405        }
13406        try{// try catch for cross domain access issue
13407            var ssRules = stylesheet.cssRules || stylesheet.rules;
13408            for(var j = ssRules.length-1; j >= 0; --j){
13409                rules[ssRules[j].selectorText] = ssRules[j];
13410            }
13411        }catch(e){}
13412    },
13413    
13414    /**
13415     * Gets all css rules for the document
13416     * @param {Boolean} refreshCache true to refresh the internal cache
13417     * @return {Object} An object (hash) of rules indexed by selector
13418     */
13419    getRules : function(refreshCache){
13420                 if(rules == null || refreshCache){
13421                         rules = {};
13422                         var ds = doc.styleSheets;
13423                         for(var i =0, len = ds.length; i < len; i++){
13424                             try{
13425                         this.cacheStyleSheet(ds[i]);
13426                     }catch(e){} 
13427                 }
13428                 }
13429                 return rules;
13430         },
13431         
13432         /**
13433     * Gets an an individual CSS rule by selector(s)
13434     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13435     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13436     * @return {CSSRule} The CSS rule or null if one is not found
13437     */
13438    getRule : function(selector, refreshCache){
13439                 var rs = this.getRules(refreshCache);
13440                 if(!(selector instanceof Array)){
13441                     return rs[selector];
13442                 }
13443                 for(var i = 0; i < selector.length; i++){
13444                         if(rs[selector[i]]){
13445                                 return rs[selector[i]];
13446                         }
13447                 }
13448                 return null;
13449         },
13450         
13451         
13452         /**
13453     * Updates a rule property
13454     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13455     * @param {String} property The css property
13456     * @param {String} value The new value for the property
13457     * @return {Boolean} true If a rule was found and updated
13458     */
13459    updateRule : function(selector, property, value){
13460                 if(!(selector instanceof Array)){
13461                         var rule = this.getRule(selector);
13462                         if(rule){
13463                                 rule.style[property.replace(camelRe, camelFn)] = value;
13464                                 return true;
13465                         }
13466                 }else{
13467                         for(var i = 0; i < selector.length; i++){
13468                                 if(this.updateRule(selector[i], property, value)){
13469                                         return true;
13470                                 }
13471                         }
13472                 }
13473                 return false;
13474         }
13475    };   
13476 }();/*
13477  * Based on:
13478  * Ext JS Library 1.1.1
13479  * Copyright(c) 2006-2007, Ext JS, LLC.
13480  *
13481  * Originally Released Under LGPL - original licence link has changed is not relivant.
13482  *
13483  * Fork - LGPL
13484  * <script type="text/javascript">
13485  */
13486
13487  
13488
13489 /**
13490  * @class Roo.util.ClickRepeater
13491  * @extends Roo.util.Observable
13492  * 
13493  * A wrapper class which can be applied to any element. Fires a "click" event while the
13494  * mouse is pressed. The interval between firings may be specified in the config but
13495  * defaults to 10 milliseconds.
13496  * 
13497  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13498  * 
13499  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13500  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13501  * Similar to an autorepeat key delay.
13502  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13503  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13504  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13505  *           "interval" and "delay" are ignored. "immediate" is honored.
13506  * @cfg {Boolean} preventDefault True to prevent the default click event
13507  * @cfg {Boolean} stopDefault True to stop the default click event
13508  * 
13509  * @history
13510  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13511  *     2007-02-02 jvs Renamed to ClickRepeater
13512  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13513  *
13514  *  @constructor
13515  * @param {String/HTMLElement/Element} el The element to listen on
13516  * @param {Object} config
13517  **/
13518 Roo.util.ClickRepeater = function(el, config)
13519 {
13520     this.el = Roo.get(el);
13521     this.el.unselectable();
13522
13523     Roo.apply(this, config);
13524
13525     this.addEvents({
13526     /**
13527      * @event mousedown
13528      * Fires when the mouse button is depressed.
13529      * @param {Roo.util.ClickRepeater} this
13530      */
13531         "mousedown" : true,
13532     /**
13533      * @event click
13534      * Fires on a specified interval during the time the element is pressed.
13535      * @param {Roo.util.ClickRepeater} this
13536      */
13537         "click" : true,
13538     /**
13539      * @event mouseup
13540      * Fires when the mouse key is released.
13541      * @param {Roo.util.ClickRepeater} this
13542      */
13543         "mouseup" : true
13544     });
13545
13546     this.el.on("mousedown", this.handleMouseDown, this);
13547     if(this.preventDefault || this.stopDefault){
13548         this.el.on("click", function(e){
13549             if(this.preventDefault){
13550                 e.preventDefault();
13551             }
13552             if(this.stopDefault){
13553                 e.stopEvent();
13554             }
13555         }, this);
13556     }
13557
13558     // allow inline handler
13559     if(this.handler){
13560         this.on("click", this.handler,  this.scope || this);
13561     }
13562
13563     Roo.util.ClickRepeater.superclass.constructor.call(this);
13564 };
13565
13566 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13567     interval : 20,
13568     delay: 250,
13569     preventDefault : true,
13570     stopDefault : false,
13571     timer : 0,
13572
13573     // private
13574     handleMouseDown : function(){
13575         clearTimeout(this.timer);
13576         this.el.blur();
13577         if(this.pressClass){
13578             this.el.addClass(this.pressClass);
13579         }
13580         this.mousedownTime = new Date();
13581
13582         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13583         this.el.on("mouseout", this.handleMouseOut, this);
13584
13585         this.fireEvent("mousedown", this);
13586         this.fireEvent("click", this);
13587         
13588         this.timer = this.click.defer(this.delay || this.interval, this);
13589     },
13590
13591     // private
13592     click : function(){
13593         this.fireEvent("click", this);
13594         this.timer = this.click.defer(this.getInterval(), this);
13595     },
13596
13597     // private
13598     getInterval: function(){
13599         if(!this.accelerate){
13600             return this.interval;
13601         }
13602         var pressTime = this.mousedownTime.getElapsed();
13603         if(pressTime < 500){
13604             return 400;
13605         }else if(pressTime < 1700){
13606             return 320;
13607         }else if(pressTime < 2600){
13608             return 250;
13609         }else if(pressTime < 3500){
13610             return 180;
13611         }else if(pressTime < 4400){
13612             return 140;
13613         }else if(pressTime < 5300){
13614             return 80;
13615         }else if(pressTime < 6200){
13616             return 50;
13617         }else{
13618             return 10;
13619         }
13620     },
13621
13622     // private
13623     handleMouseOut : function(){
13624         clearTimeout(this.timer);
13625         if(this.pressClass){
13626             this.el.removeClass(this.pressClass);
13627         }
13628         this.el.on("mouseover", this.handleMouseReturn, this);
13629     },
13630
13631     // private
13632     handleMouseReturn : function(){
13633         this.el.un("mouseover", this.handleMouseReturn);
13634         if(this.pressClass){
13635             this.el.addClass(this.pressClass);
13636         }
13637         this.click();
13638     },
13639
13640     // private
13641     handleMouseUp : function(){
13642         clearTimeout(this.timer);
13643         this.el.un("mouseover", this.handleMouseReturn);
13644         this.el.un("mouseout", this.handleMouseOut);
13645         Roo.get(document).un("mouseup", this.handleMouseUp);
13646         this.el.removeClass(this.pressClass);
13647         this.fireEvent("mouseup", this);
13648     }
13649 });/*
13650  * Based on:
13651  * Ext JS Library 1.1.1
13652  * Copyright(c) 2006-2007, Ext JS, LLC.
13653  *
13654  * Originally Released Under LGPL - original licence link has changed is not relivant.
13655  *
13656  * Fork - LGPL
13657  * <script type="text/javascript">
13658  */
13659
13660  
13661 /**
13662  * @class Roo.KeyNav
13663  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13664  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13665  * way to implement custom navigation schemes for any UI component.</p>
13666  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13667  * pageUp, pageDown, del, home, end.  Usage:</p>
13668  <pre><code>
13669 var nav = new Roo.KeyNav("my-element", {
13670     "left" : function(e){
13671         this.moveLeft(e.ctrlKey);
13672     },
13673     "right" : function(e){
13674         this.moveRight(e.ctrlKey);
13675     },
13676     "enter" : function(e){
13677         this.save();
13678     },
13679     scope : this
13680 });
13681 </code></pre>
13682  * @constructor
13683  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13684  * @param {Object} config The config
13685  */
13686 Roo.KeyNav = function(el, config){
13687     this.el = Roo.get(el);
13688     Roo.apply(this, config);
13689     if(!this.disabled){
13690         this.disabled = true;
13691         this.enable();
13692     }
13693 };
13694
13695 Roo.KeyNav.prototype = {
13696     /**
13697      * @cfg {Boolean} disabled
13698      * True to disable this KeyNav instance (defaults to false)
13699      */
13700     disabled : false,
13701     /**
13702      * @cfg {String} defaultEventAction
13703      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13704      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13705      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13706      */
13707     defaultEventAction: "stopEvent",
13708     /**
13709      * @cfg {Boolean} forceKeyDown
13710      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13711      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13712      * handle keydown instead of keypress.
13713      */
13714     forceKeyDown : false,
13715
13716     // private
13717     prepareEvent : function(e){
13718         var k = e.getKey();
13719         var h = this.keyToHandler[k];
13720         //if(h && this[h]){
13721         //    e.stopPropagation();
13722         //}
13723         if(Roo.isSafari && h && k >= 37 && k <= 40){
13724             e.stopEvent();
13725         }
13726     },
13727
13728     // private
13729     relay : function(e){
13730         var k = e.getKey();
13731         var h = this.keyToHandler[k];
13732         if(h && this[h]){
13733             if(this.doRelay(e, this[h], h) !== true){
13734                 e[this.defaultEventAction]();
13735             }
13736         }
13737     },
13738
13739     // private
13740     doRelay : function(e, h, hname){
13741         return h.call(this.scope || this, e);
13742     },
13743
13744     // possible handlers
13745     enter : false,
13746     left : false,
13747     right : false,
13748     up : false,
13749     down : false,
13750     tab : false,
13751     esc : false,
13752     pageUp : false,
13753     pageDown : false,
13754     del : false,
13755     home : false,
13756     end : false,
13757
13758     // quick lookup hash
13759     keyToHandler : {
13760         37 : "left",
13761         39 : "right",
13762         38 : "up",
13763         40 : "down",
13764         33 : "pageUp",
13765         34 : "pageDown",
13766         46 : "del",
13767         36 : "home",
13768         35 : "end",
13769         13 : "enter",
13770         27 : "esc",
13771         9  : "tab"
13772     },
13773
13774         /**
13775          * Enable this KeyNav
13776          */
13777         enable: function(){
13778                 if(this.disabled){
13779             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13780             // the EventObject will normalize Safari automatically
13781             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13782                 this.el.on("keydown", this.relay,  this);
13783             }else{
13784                 this.el.on("keydown", this.prepareEvent,  this);
13785                 this.el.on("keypress", this.relay,  this);
13786             }
13787                     this.disabled = false;
13788                 }
13789         },
13790
13791         /**
13792          * Disable this KeyNav
13793          */
13794         disable: function(){
13795                 if(!this.disabled){
13796                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13797                 this.el.un("keydown", this.relay);
13798             }else{
13799                 this.el.un("keydown", this.prepareEvent);
13800                 this.el.un("keypress", this.relay);
13801             }
13802                     this.disabled = true;
13803                 }
13804         }
13805 };/*
13806  * Based on:
13807  * Ext JS Library 1.1.1
13808  * Copyright(c) 2006-2007, Ext JS, LLC.
13809  *
13810  * Originally Released Under LGPL - original licence link has changed is not relivant.
13811  *
13812  * Fork - LGPL
13813  * <script type="text/javascript">
13814  */
13815
13816  
13817 /**
13818  * @class Roo.KeyMap
13819  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13820  * The constructor accepts the same config object as defined by {@link #addBinding}.
13821  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13822  * combination it will call the function with this signature (if the match is a multi-key
13823  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13824  * A KeyMap can also handle a string representation of keys.<br />
13825  * Usage:
13826  <pre><code>
13827 // map one key by key code
13828 var map = new Roo.KeyMap("my-element", {
13829     key: 13, // or Roo.EventObject.ENTER
13830     fn: myHandler,
13831     scope: myObject
13832 });
13833
13834 // map multiple keys to one action by string
13835 var map = new Roo.KeyMap("my-element", {
13836     key: "a\r\n\t",
13837     fn: myHandler,
13838     scope: myObject
13839 });
13840
13841 // map multiple keys to multiple actions by strings and array of codes
13842 var map = new Roo.KeyMap("my-element", [
13843     {
13844         key: [10,13],
13845         fn: function(){ alert("Return was pressed"); }
13846     }, {
13847         key: "abc",
13848         fn: function(){ alert('a, b or c was pressed'); }
13849     }, {
13850         key: "\t",
13851         ctrl:true,
13852         shift:true,
13853         fn: function(){ alert('Control + shift + tab was pressed.'); }
13854     }
13855 ]);
13856 </code></pre>
13857  * <b>Note: A KeyMap starts enabled</b>
13858  * @constructor
13859  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13860  * @param {Object} config The config (see {@link #addBinding})
13861  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13862  */
13863 Roo.KeyMap = function(el, config, eventName){
13864     this.el  = Roo.get(el);
13865     this.eventName = eventName || "keydown";
13866     this.bindings = [];
13867     if(config){
13868         this.addBinding(config);
13869     }
13870     this.enable();
13871 };
13872
13873 Roo.KeyMap.prototype = {
13874     /**
13875      * True to stop the event from bubbling and prevent the default browser action if the
13876      * key was handled by the KeyMap (defaults to false)
13877      * @type Boolean
13878      */
13879     stopEvent : false,
13880
13881     /**
13882      * Add a new binding to this KeyMap. The following config object properties are supported:
13883      * <pre>
13884 Property    Type             Description
13885 ----------  ---------------  ----------------------------------------------------------------------
13886 key         String/Array     A single keycode or an array of keycodes to handle
13887 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13888 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13889 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13890 fn          Function         The function to call when KeyMap finds the expected key combination
13891 scope       Object           The scope of the callback function
13892 </pre>
13893      *
13894      * Usage:
13895      * <pre><code>
13896 // Create a KeyMap
13897 var map = new Roo.KeyMap(document, {
13898     key: Roo.EventObject.ENTER,
13899     fn: handleKey,
13900     scope: this
13901 });
13902
13903 //Add a new binding to the existing KeyMap later
13904 map.addBinding({
13905     key: 'abc',
13906     shift: true,
13907     fn: handleKey,
13908     scope: this
13909 });
13910 </code></pre>
13911      * @param {Object/Array} config A single KeyMap config or an array of configs
13912      */
13913         addBinding : function(config){
13914         if(config instanceof Array){
13915             for(var i = 0, len = config.length; i < len; i++){
13916                 this.addBinding(config[i]);
13917             }
13918             return;
13919         }
13920         var keyCode = config.key,
13921             shift = config.shift, 
13922             ctrl = config.ctrl, 
13923             alt = config.alt,
13924             fn = config.fn,
13925             scope = config.scope;
13926         if(typeof keyCode == "string"){
13927             var ks = [];
13928             var keyString = keyCode.toUpperCase();
13929             for(var j = 0, len = keyString.length; j < len; j++){
13930                 ks.push(keyString.charCodeAt(j));
13931             }
13932             keyCode = ks;
13933         }
13934         var keyArray = keyCode instanceof Array;
13935         var handler = function(e){
13936             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13937                 var k = e.getKey();
13938                 if(keyArray){
13939                     for(var i = 0, len = keyCode.length; i < len; i++){
13940                         if(keyCode[i] == k){
13941                           if(this.stopEvent){
13942                               e.stopEvent();
13943                           }
13944                           fn.call(scope || window, k, e);
13945                           return;
13946                         }
13947                     }
13948                 }else{
13949                     if(k == keyCode){
13950                         if(this.stopEvent){
13951                            e.stopEvent();
13952                         }
13953                         fn.call(scope || window, k, e);
13954                     }
13955                 }
13956             }
13957         };
13958         this.bindings.push(handler);  
13959         },
13960
13961     /**
13962      * Shorthand for adding a single key listener
13963      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13964      * following options:
13965      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13966      * @param {Function} fn The function to call
13967      * @param {Object} scope (optional) The scope of the function
13968      */
13969     on : function(key, fn, scope){
13970         var keyCode, shift, ctrl, alt;
13971         if(typeof key == "object" && !(key instanceof Array)){
13972             keyCode = key.key;
13973             shift = key.shift;
13974             ctrl = key.ctrl;
13975             alt = key.alt;
13976         }else{
13977             keyCode = key;
13978         }
13979         this.addBinding({
13980             key: keyCode,
13981             shift: shift,
13982             ctrl: ctrl,
13983             alt: alt,
13984             fn: fn,
13985             scope: scope
13986         })
13987     },
13988
13989     // private
13990     handleKeyDown : function(e){
13991             if(this.enabled){ //just in case
13992             var b = this.bindings;
13993             for(var i = 0, len = b.length; i < len; i++){
13994                 b[i].call(this, e);
13995             }
13996             }
13997         },
13998         
13999         /**
14000          * Returns true if this KeyMap is enabled
14001          * @return {Boolean} 
14002          */
14003         isEnabled : function(){
14004             return this.enabled;  
14005         },
14006         
14007         /**
14008          * Enables this KeyMap
14009          */
14010         enable: function(){
14011                 if(!this.enabled){
14012                     this.el.on(this.eventName, this.handleKeyDown, this);
14013                     this.enabled = true;
14014                 }
14015         },
14016
14017         /**
14018          * Disable this KeyMap
14019          */
14020         disable: function(){
14021                 if(this.enabled){
14022                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14023                     this.enabled = false;
14024                 }
14025         }
14026 };/*
14027  * Based on:
14028  * Ext JS Library 1.1.1
14029  * Copyright(c) 2006-2007, Ext JS, LLC.
14030  *
14031  * Originally Released Under LGPL - original licence link has changed is not relivant.
14032  *
14033  * Fork - LGPL
14034  * <script type="text/javascript">
14035  */
14036
14037  
14038 /**
14039  * @class Roo.util.TextMetrics
14040  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14041  * wide, in pixels, a given block of text will be.
14042  * @singleton
14043  */
14044 Roo.util.TextMetrics = function(){
14045     var shared;
14046     return {
14047         /**
14048          * Measures the size of the specified text
14049          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14050          * that can affect the size of the rendered text
14051          * @param {String} text The text to measure
14052          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14053          * in order to accurately measure the text height
14054          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14055          */
14056         measure : function(el, text, fixedWidth){
14057             if(!shared){
14058                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14059             }
14060             shared.bind(el);
14061             shared.setFixedWidth(fixedWidth || 'auto');
14062             return shared.getSize(text);
14063         },
14064
14065         /**
14066          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14067          * the overhead of multiple calls to initialize the style properties on each measurement.
14068          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14069          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14070          * in order to accurately measure the text height
14071          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14072          */
14073         createInstance : function(el, fixedWidth){
14074             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14075         }
14076     };
14077 }();
14078
14079  
14080
14081 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14082     var ml = new Roo.Element(document.createElement('div'));
14083     document.body.appendChild(ml.dom);
14084     ml.position('absolute');
14085     ml.setLeftTop(-1000, -1000);
14086     ml.hide();
14087
14088     if(fixedWidth){
14089         ml.setWidth(fixedWidth);
14090     }
14091      
14092     var instance = {
14093         /**
14094          * Returns the size of the specified text based on the internal element's style and width properties
14095          * @memberOf Roo.util.TextMetrics.Instance#
14096          * @param {String} text The text to measure
14097          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14098          */
14099         getSize : function(text){
14100             ml.update(text);
14101             var s = ml.getSize();
14102             ml.update('');
14103             return s;
14104         },
14105
14106         /**
14107          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14108          * that can affect the size of the rendered text
14109          * @memberOf Roo.util.TextMetrics.Instance#
14110          * @param {String/HTMLElement} el The element, dom node or id
14111          */
14112         bind : function(el){
14113             ml.setStyle(
14114                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14115             );
14116         },
14117
14118         /**
14119          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14120          * to set a fixed width in order to accurately measure the text height.
14121          * @memberOf Roo.util.TextMetrics.Instance#
14122          * @param {Number} width The width to set on the element
14123          */
14124         setFixedWidth : function(width){
14125             ml.setWidth(width);
14126         },
14127
14128         /**
14129          * Returns the measured width of the specified text
14130          * @memberOf Roo.util.TextMetrics.Instance#
14131          * @param {String} text The text to measure
14132          * @return {Number} width The width in pixels
14133          */
14134         getWidth : function(text){
14135             ml.dom.style.width = 'auto';
14136             return this.getSize(text).width;
14137         },
14138
14139         /**
14140          * Returns the measured height of the specified text.  For multiline text, be sure to call
14141          * {@link #setFixedWidth} if necessary.
14142          * @memberOf Roo.util.TextMetrics.Instance#
14143          * @param {String} text The text to measure
14144          * @return {Number} height The height in pixels
14145          */
14146         getHeight : function(text){
14147             return this.getSize(text).height;
14148         }
14149     };
14150
14151     instance.bind(bindTo);
14152
14153     return instance;
14154 };
14155
14156 // backwards compat
14157 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14158  * Based on:
14159  * Ext JS Library 1.1.1
14160  * Copyright(c) 2006-2007, Ext JS, LLC.
14161  *
14162  * Originally Released Under LGPL - original licence link has changed is not relivant.
14163  *
14164  * Fork - LGPL
14165  * <script type="text/javascript">
14166  */
14167
14168 /**
14169  * @class Roo.state.Provider
14170  * Abstract base class for state provider implementations. This class provides methods
14171  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14172  * Provider interface.
14173  */
14174 Roo.state.Provider = function(){
14175     /**
14176      * @event statechange
14177      * Fires when a state change occurs.
14178      * @param {Provider} this This state provider
14179      * @param {String} key The state key which was changed
14180      * @param {String} value The encoded value for the state
14181      */
14182     this.addEvents({
14183         "statechange": true
14184     });
14185     this.state = {};
14186     Roo.state.Provider.superclass.constructor.call(this);
14187 };
14188 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14189     /**
14190      * Returns the current value for a key
14191      * @param {String} name The key name
14192      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14193      * @return {Mixed} The state data
14194      */
14195     get : function(name, defaultValue){
14196         return typeof this.state[name] == "undefined" ?
14197             defaultValue : this.state[name];
14198     },
14199     
14200     /**
14201      * Clears a value from the state
14202      * @param {String} name The key name
14203      */
14204     clear : function(name){
14205         delete this.state[name];
14206         this.fireEvent("statechange", this, name, null);
14207     },
14208     
14209     /**
14210      * Sets the value for a key
14211      * @param {String} name The key name
14212      * @param {Mixed} value The value to set
14213      */
14214     set : function(name, value){
14215         this.state[name] = value;
14216         this.fireEvent("statechange", this, name, value);
14217     },
14218     
14219     /**
14220      * Decodes a string previously encoded with {@link #encodeValue}.
14221      * @param {String} value The value to decode
14222      * @return {Mixed} The decoded value
14223      */
14224     decodeValue : function(cookie){
14225         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14226         var matches = re.exec(unescape(cookie));
14227         if(!matches || !matches[1]) return; // non state cookie
14228         var type = matches[1];
14229         var v = matches[2];
14230         switch(type){
14231             case "n":
14232                 return parseFloat(v);
14233             case "d":
14234                 return new Date(Date.parse(v));
14235             case "b":
14236                 return (v == "1");
14237             case "a":
14238                 var all = [];
14239                 var values = v.split("^");
14240                 for(var i = 0, len = values.length; i < len; i++){
14241                     all.push(this.decodeValue(values[i]));
14242                 }
14243                 return all;
14244            case "o":
14245                 var all = {};
14246                 var values = v.split("^");
14247                 for(var i = 0, len = values.length; i < len; i++){
14248                     var kv = values[i].split("=");
14249                     all[kv[0]] = this.decodeValue(kv[1]);
14250                 }
14251                 return all;
14252            default:
14253                 return v;
14254         }
14255     },
14256     
14257     /**
14258      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14259      * @param {Mixed} value The value to encode
14260      * @return {String} The encoded value
14261      */
14262     encodeValue : function(v){
14263         var enc;
14264         if(typeof v == "number"){
14265             enc = "n:" + v;
14266         }else if(typeof v == "boolean"){
14267             enc = "b:" + (v ? "1" : "0");
14268         }else if(v instanceof Date){
14269             enc = "d:" + v.toGMTString();
14270         }else if(v instanceof Array){
14271             var flat = "";
14272             for(var i = 0, len = v.length; i < len; i++){
14273                 flat += this.encodeValue(v[i]);
14274                 if(i != len-1) flat += "^";
14275             }
14276             enc = "a:" + flat;
14277         }else if(typeof v == "object"){
14278             var flat = "";
14279             for(var key in v){
14280                 if(typeof v[key] != "function"){
14281                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14282                 }
14283             }
14284             enc = "o:" + flat.substring(0, flat.length-1);
14285         }else{
14286             enc = "s:" + v;
14287         }
14288         return escape(enc);        
14289     }
14290 });
14291
14292 /*
14293  * Based on:
14294  * Ext JS Library 1.1.1
14295  * Copyright(c) 2006-2007, Ext JS, LLC.
14296  *
14297  * Originally Released Under LGPL - original licence link has changed is not relivant.
14298  *
14299  * Fork - LGPL
14300  * <script type="text/javascript">
14301  */
14302 /**
14303  * @class Roo.state.Manager
14304  * This is the global state manager. By default all components that are "state aware" check this class
14305  * for state information if you don't pass them a custom state provider. In order for this class
14306  * to be useful, it must be initialized with a provider when your application initializes.
14307  <pre><code>
14308 // in your initialization function
14309 init : function(){
14310    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14311    ...
14312    // supposed you have a {@link Roo.BorderLayout}
14313    var layout = new Roo.BorderLayout(...);
14314    layout.restoreState();
14315    // or a {Roo.BasicDialog}
14316    var dialog = new Roo.BasicDialog(...);
14317    dialog.restoreState();
14318  </code></pre>
14319  * @singleton
14320  */
14321 Roo.state.Manager = function(){
14322     var provider = new Roo.state.Provider();
14323     
14324     return {
14325         /**
14326          * Configures the default state provider for your application
14327          * @param {Provider} stateProvider The state provider to set
14328          */
14329         setProvider : function(stateProvider){
14330             provider = stateProvider;
14331         },
14332         
14333         /**
14334          * Returns the current value for a key
14335          * @param {String} name The key name
14336          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14337          * @return {Mixed} The state data
14338          */
14339         get : function(key, defaultValue){
14340             return provider.get(key, defaultValue);
14341         },
14342         
14343         /**
14344          * Sets the value for a key
14345          * @param {String} name The key name
14346          * @param {Mixed} value The state data
14347          */
14348          set : function(key, value){
14349             provider.set(key, value);
14350         },
14351         
14352         /**
14353          * Clears a value from the state
14354          * @param {String} name The key name
14355          */
14356         clear : function(key){
14357             provider.clear(key);
14358         },
14359         
14360         /**
14361          * Gets the currently configured state provider
14362          * @return {Provider} The state provider
14363          */
14364         getProvider : function(){
14365             return provider;
14366         }
14367     };
14368 }();
14369 /*
14370  * Based on:
14371  * Ext JS Library 1.1.1
14372  * Copyright(c) 2006-2007, Ext JS, LLC.
14373  *
14374  * Originally Released Under LGPL - original licence link has changed is not relivant.
14375  *
14376  * Fork - LGPL
14377  * <script type="text/javascript">
14378  */
14379 /**
14380  * @class Roo.state.CookieProvider
14381  * @extends Roo.state.Provider
14382  * The default Provider implementation which saves state via cookies.
14383  * <br />Usage:
14384  <pre><code>
14385    var cp = new Roo.state.CookieProvider({
14386        path: "/cgi-bin/",
14387        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14388        domain: "roojs.com"
14389    })
14390    Roo.state.Manager.setProvider(cp);
14391  </code></pre>
14392  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14393  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14394  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14395  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14396  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14397  * domain the page is running on including the 'www' like 'www.roojs.com')
14398  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14399  * @constructor
14400  * Create a new CookieProvider
14401  * @param {Object} config The configuration object
14402  */
14403 Roo.state.CookieProvider = function(config){
14404     Roo.state.CookieProvider.superclass.constructor.call(this);
14405     this.path = "/";
14406     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14407     this.domain = null;
14408     this.secure = false;
14409     Roo.apply(this, config);
14410     this.state = this.readCookies();
14411 };
14412
14413 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14414     // private
14415     set : function(name, value){
14416         if(typeof value == "undefined" || value === null){
14417             this.clear(name);
14418             return;
14419         }
14420         this.setCookie(name, value);
14421         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14422     },
14423
14424     // private
14425     clear : function(name){
14426         this.clearCookie(name);
14427         Roo.state.CookieProvider.superclass.clear.call(this, name);
14428     },
14429
14430     // private
14431     readCookies : function(){
14432         var cookies = {};
14433         var c = document.cookie + ";";
14434         var re = /\s?(.*?)=(.*?);/g;
14435         var matches;
14436         while((matches = re.exec(c)) != null){
14437             var name = matches[1];
14438             var value = matches[2];
14439             if(name && name.substring(0,3) == "ys-"){
14440                 cookies[name.substr(3)] = this.decodeValue(value);
14441             }
14442         }
14443         return cookies;
14444     },
14445
14446     // private
14447     setCookie : function(name, value){
14448         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14449            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14450            ((this.path == null) ? "" : ("; path=" + this.path)) +
14451            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14452            ((this.secure == true) ? "; secure" : "");
14453     },
14454
14455     // private
14456     clearCookie : function(name){
14457         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14458            ((this.path == null) ? "" : ("; path=" + this.path)) +
14459            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14460            ((this.secure == true) ? "; secure" : "");
14461     }
14462 });