roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * 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             var p = this.getPositioning();
8874             if(typeof msg == 'string'){
8875                 if(!this._maskMsg){
8876                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8877                 }
8878                 var mm = this._maskMsg;
8879                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8880                 mm.dom.firstChild.innerHTML = msg;
8881                 mm.setDisplayed(true);
8882                 mm.center(this);
8883                 mm.setStyle('z-index', parseInt(p['z-index']) + 102);
8884             }
8885             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8886                 this._mask.setHeight(this.getHeight());
8887             }
8888             this_mask.setStyle('z-index', parseInt(p['z-index']) + 100);
8889             
8890             return this._mask;
8891         },
8892
8893         /**
8894          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8895          * it is cached for reuse.
8896          */
8897         unmask : function(removeEl){
8898             if(this._mask){
8899                 if(removeEl === true){
8900                     this._mask.remove();
8901                     delete this._mask;
8902                     if(this._maskMsg){
8903                         this._maskMsg.remove();
8904                         delete this._maskMsg;
8905                     }
8906                 }else{
8907                     this._mask.setDisplayed(false);
8908                     if(this._maskMsg){
8909                         this._maskMsg.setDisplayed(false);
8910                     }
8911                 }
8912             }
8913             this.removeClass("x-masked");
8914         },
8915
8916         /**
8917          * Returns true if this element is masked
8918          * @return {Boolean}
8919          */
8920         isMasked : function(){
8921             return this._mask && this._mask.isVisible();
8922         },
8923
8924         /**
8925          * Creates an iframe shim for this element to keep selects and other windowed objects from
8926          * showing through.
8927          * @return {Roo.Element} The new shim element
8928          */
8929         createShim : function(){
8930             var el = document.createElement('iframe');
8931             el.frameBorder = 'no';
8932             el.className = 'roo-shim';
8933             if(Roo.isIE && Roo.isSecure){
8934                 el.src = Roo.SSL_SECURE_URL;
8935             }
8936             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8937             shim.autoBoxAdjust = false;
8938             return shim;
8939         },
8940
8941         /**
8942          * Removes this element from the DOM and deletes it from the cache
8943          */
8944         remove : function(){
8945             if(this.dom.parentNode){
8946                 this.dom.parentNode.removeChild(this.dom);
8947             }
8948             delete El.cache[this.dom.id];
8949         },
8950
8951         /**
8952          * Sets up event handlers to add and remove a css class when the mouse is over this element
8953          * @param {String} className
8954          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8955          * mouseout events for children elements
8956          * @return {Roo.Element} this
8957          */
8958         addClassOnOver : function(className, preventFlicker){
8959             this.on("mouseover", function(){
8960                 Roo.fly(this, '_internal').addClass(className);
8961             }, this.dom);
8962             var removeFn = function(e){
8963                 if(preventFlicker !== true || !e.within(this, true)){
8964                     Roo.fly(this, '_internal').removeClass(className);
8965                 }
8966             };
8967             this.on("mouseout", removeFn, this.dom);
8968             return this;
8969         },
8970
8971         /**
8972          * Sets up event handlers to add and remove a css class when this element has the focus
8973          * @param {String} className
8974          * @return {Roo.Element} this
8975          */
8976         addClassOnFocus : function(className){
8977             this.on("focus", function(){
8978                 Roo.fly(this, '_internal').addClass(className);
8979             }, this.dom);
8980             this.on("blur", function(){
8981                 Roo.fly(this, '_internal').removeClass(className);
8982             }, this.dom);
8983             return this;
8984         },
8985         /**
8986          * 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)
8987          * @param {String} className
8988          * @return {Roo.Element} this
8989          */
8990         addClassOnClick : function(className){
8991             var dom = this.dom;
8992             this.on("mousedown", function(){
8993                 Roo.fly(dom, '_internal').addClass(className);
8994                 var d = Roo.get(document);
8995                 var fn = function(){
8996                     Roo.fly(dom, '_internal').removeClass(className);
8997                     d.removeListener("mouseup", fn);
8998                 };
8999                 d.on("mouseup", fn);
9000             });
9001             return this;
9002         },
9003
9004         /**
9005          * Stops the specified event from bubbling and optionally prevents the default action
9006          * @param {String} eventName
9007          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9008          * @return {Roo.Element} this
9009          */
9010         swallowEvent : function(eventName, preventDefault){
9011             var fn = function(e){
9012                 e.stopPropagation();
9013                 if(preventDefault){
9014                     e.preventDefault();
9015                 }
9016             };
9017             if(eventName instanceof Array){
9018                 for(var i = 0, len = eventName.length; i < len; i++){
9019                      this.on(eventName[i], fn);
9020                 }
9021                 return this;
9022             }
9023             this.on(eventName, fn);
9024             return this;
9025         },
9026
9027         /**
9028          * @private
9029          */
9030       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9031
9032         /**
9033          * Sizes this element to its parent element's dimensions performing
9034          * neccessary box adjustments.
9035          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9036          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9037          * @return {Roo.Element} this
9038          */
9039         fitToParent : function(monitorResize, targetParent) {
9040           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9041           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9042           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9043             return;
9044           }
9045           var p = Roo.get(targetParent || this.dom.parentNode);
9046           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9047           if (monitorResize === true) {
9048             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9049             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9050           }
9051           return this;
9052         },
9053
9054         /**
9055          * Gets the next sibling, skipping text nodes
9056          * @return {HTMLElement} The next sibling or null
9057          */
9058         getNextSibling : function(){
9059             var n = this.dom.nextSibling;
9060             while(n && n.nodeType != 1){
9061                 n = n.nextSibling;
9062             }
9063             return n;
9064         },
9065
9066         /**
9067          * Gets the previous sibling, skipping text nodes
9068          * @return {HTMLElement} The previous sibling or null
9069          */
9070         getPrevSibling : function(){
9071             var n = this.dom.previousSibling;
9072             while(n && n.nodeType != 1){
9073                 n = n.previousSibling;
9074             }
9075             return n;
9076         },
9077
9078
9079         /**
9080          * Appends the passed element(s) to this element
9081          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9082          * @return {Roo.Element} this
9083          */
9084         appendChild: function(el){
9085             el = Roo.get(el);
9086             el.appendTo(this);
9087             return this;
9088         },
9089
9090         /**
9091          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9092          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9093          * automatically generated with the specified attributes.
9094          * @param {HTMLElement} insertBefore (optional) a child element of this element
9095          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9096          * @return {Roo.Element} The new child element
9097          */
9098         createChild: function(config, insertBefore, returnDom){
9099             config = config || {tag:'div'};
9100             if(insertBefore){
9101                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9102             }
9103             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9104         },
9105
9106         /**
9107          * Appends this element to the passed element
9108          * @param {String/HTMLElement/Element} el The new parent element
9109          * @return {Roo.Element} this
9110          */
9111         appendTo: function(el){
9112             el = Roo.getDom(el);
9113             el.appendChild(this.dom);
9114             return this;
9115         },
9116
9117         /**
9118          * Inserts this element before the passed element in the DOM
9119          * @param {String/HTMLElement/Element} el The element to insert before
9120          * @return {Roo.Element} this
9121          */
9122         insertBefore: function(el){
9123             el = Roo.getDom(el);
9124             el.parentNode.insertBefore(this.dom, el);
9125             return this;
9126         },
9127
9128         /**
9129          * Inserts this element after the passed element in the DOM
9130          * @param {String/HTMLElement/Element} el The element to insert after
9131          * @return {Roo.Element} this
9132          */
9133         insertAfter: function(el){
9134             el = Roo.getDom(el);
9135             el.parentNode.insertBefore(this.dom, el.nextSibling);
9136             return this;
9137         },
9138
9139         /**
9140          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9141          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9142          * @return {Roo.Element} The new child
9143          */
9144         insertFirst: function(el, returnDom){
9145             el = el || {};
9146             if(typeof el == 'object' && !el.nodeType){ // dh config
9147                 return this.createChild(el, this.dom.firstChild, returnDom);
9148             }else{
9149                 el = Roo.getDom(el);
9150                 this.dom.insertBefore(el, this.dom.firstChild);
9151                 return !returnDom ? Roo.get(el) : el;
9152             }
9153         },
9154
9155         /**
9156          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9157          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9158          * @param {String} where (optional) 'before' or 'after' defaults to before
9159          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9160          * @return {Roo.Element} the inserted Element
9161          */
9162         insertSibling: function(el, where, returnDom){
9163             where = where ? where.toLowerCase() : 'before';
9164             el = el || {};
9165             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9166
9167             if(typeof el == 'object' && !el.nodeType){ // dh config
9168                 if(where == 'after' && !this.dom.nextSibling){
9169                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9170                 }else{
9171                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9172                 }
9173
9174             }else{
9175                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9176                             where == 'before' ? this.dom : this.dom.nextSibling);
9177                 if(!returnDom){
9178                     rt = Roo.get(rt);
9179                 }
9180             }
9181             return rt;
9182         },
9183
9184         /**
9185          * Creates and wraps this element with another element
9186          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9187          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9188          * @return {HTMLElement/Element} The newly created wrapper element
9189          */
9190         wrap: function(config, returnDom){
9191             if(!config){
9192                 config = {tag: "div"};
9193             }
9194             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9195             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9196             return newEl;
9197         },
9198
9199         /**
9200          * Replaces the passed element with this element
9201          * @param {String/HTMLElement/Element} el The element to replace
9202          * @return {Roo.Element} this
9203          */
9204         replace: function(el){
9205             el = Roo.get(el);
9206             this.insertBefore(el);
9207             el.remove();
9208             return this;
9209         },
9210
9211         /**
9212          * Inserts an html fragment into this element
9213          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9214          * @param {String} html The HTML fragment
9215          * @param {Boolean} returnEl True to return an Roo.Element
9216          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9217          */
9218         insertHtml : function(where, html, returnEl){
9219             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9220             return returnEl ? Roo.get(el) : el;
9221         },
9222
9223         /**
9224          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9225          * @param {Object} o The object with the attributes
9226          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9227          * @return {Roo.Element} this
9228          */
9229         set : function(o, useSet){
9230             var el = this.dom;
9231             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9232             for(var attr in o){
9233                 if(attr == "style" || typeof o[attr] == "function") continue;
9234                 if(attr=="cls"){
9235                     el.className = o["cls"];
9236                 }else{
9237                     if(useSet) el.setAttribute(attr, o[attr]);
9238                     else el[attr] = o[attr];
9239                 }
9240             }
9241             if(o.style){
9242                 Roo.DomHelper.applyStyles(el, o.style);
9243             }
9244             return this;
9245         },
9246
9247         /**
9248          * Convenience method for constructing a KeyMap
9249          * @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:
9250          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9251          * @param {Function} fn The function to call
9252          * @param {Object} scope (optional) The scope of the function
9253          * @return {Roo.KeyMap} The KeyMap created
9254          */
9255         addKeyListener : function(key, fn, scope){
9256             var config;
9257             if(typeof key != "object" || key instanceof Array){
9258                 config = {
9259                     key: key,
9260                     fn: fn,
9261                     scope: scope
9262                 };
9263             }else{
9264                 config = {
9265                     key : key.key,
9266                     shift : key.shift,
9267                     ctrl : key.ctrl,
9268                     alt : key.alt,
9269                     fn: fn,
9270                     scope: scope
9271                 };
9272             }
9273             return new Roo.KeyMap(this, config);
9274         },
9275
9276         /**
9277          * Creates a KeyMap for this element
9278          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9279          * @return {Roo.KeyMap} The KeyMap created
9280          */
9281         addKeyMap : function(config){
9282             return new Roo.KeyMap(this, config);
9283         },
9284
9285         /**
9286          * Returns true if this element is scrollable.
9287          * @return {Boolean}
9288          */
9289          isScrollable : function(){
9290             var dom = this.dom;
9291             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9292         },
9293
9294         /**
9295          * 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().
9296          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9297          * @param {Number} value The new scroll value
9298          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9299          * @return {Element} this
9300          */
9301
9302         scrollTo : function(side, value, animate){
9303             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9304             if(!animate || !A){
9305                 this.dom[prop] = value;
9306             }else{
9307                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9308                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9309             }
9310             return this;
9311         },
9312
9313         /**
9314          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9315          * within this element's scrollable range.
9316          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9317          * @param {Number} distance How far to scroll the element in pixels
9318          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9319          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9320          * was scrolled as far as it could go.
9321          */
9322          scroll : function(direction, distance, animate){
9323              if(!this.isScrollable()){
9324                  return;
9325              }
9326              var el = this.dom;
9327              var l = el.scrollLeft, t = el.scrollTop;
9328              var w = el.scrollWidth, h = el.scrollHeight;
9329              var cw = el.clientWidth, ch = el.clientHeight;
9330              direction = direction.toLowerCase();
9331              var scrolled = false;
9332              var a = this.preanim(arguments, 2);
9333              switch(direction){
9334                  case "l":
9335                  case "left":
9336                      if(w - l > cw){
9337                          var v = Math.min(l + distance, w-cw);
9338                          this.scrollTo("left", v, a);
9339                          scrolled = true;
9340                      }
9341                      break;
9342                 case "r":
9343                 case "right":
9344                      if(l > 0){
9345                          var v = Math.max(l - distance, 0);
9346                          this.scrollTo("left", v, a);
9347                          scrolled = true;
9348                      }
9349                      break;
9350                 case "t":
9351                 case "top":
9352                 case "up":
9353                      if(t > 0){
9354                          var v = Math.max(t - distance, 0);
9355                          this.scrollTo("top", v, a);
9356                          scrolled = true;
9357                      }
9358                      break;
9359                 case "b":
9360                 case "bottom":
9361                 case "down":
9362                      if(h - t > ch){
9363                          var v = Math.min(t + distance, h-ch);
9364                          this.scrollTo("top", v, a);
9365                          scrolled = true;
9366                      }
9367                      break;
9368              }
9369              return scrolled;
9370         },
9371
9372         /**
9373          * Translates the passed page coordinates into left/top css values for this element
9374          * @param {Number/Array} x The page x or an array containing [x, y]
9375          * @param {Number} y The page y
9376          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9377          */
9378         translatePoints : function(x, y){
9379             if(typeof x == 'object' || x instanceof Array){
9380                 y = x[1]; x = x[0];
9381             }
9382             var p = this.getStyle('position');
9383             var o = this.getXY();
9384
9385             var l = parseInt(this.getStyle('left'), 10);
9386             var t = parseInt(this.getStyle('top'), 10);
9387
9388             if(isNaN(l)){
9389                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9390             }
9391             if(isNaN(t)){
9392                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9393             }
9394
9395             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9396         },
9397
9398         /**
9399          * Returns the current scroll position of the element.
9400          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9401          */
9402         getScroll : function(){
9403             var d = this.dom, doc = document;
9404             if(d == doc || d == doc.body){
9405                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9406                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9407                 return {left: l, top: t};
9408             }else{
9409                 return {left: d.scrollLeft, top: d.scrollTop};
9410             }
9411         },
9412
9413         /**
9414          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9415          * are convert to standard 6 digit hex color.
9416          * @param {String} attr The css attribute
9417          * @param {String} defaultValue The default value to use when a valid color isn't found
9418          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9419          * YUI color anims.
9420          */
9421         getColor : function(attr, defaultValue, prefix){
9422             var v = this.getStyle(attr);
9423             if(!v || v == "transparent" || v == "inherit") {
9424                 return defaultValue;
9425             }
9426             var color = typeof prefix == "undefined" ? "#" : prefix;
9427             if(v.substr(0, 4) == "rgb("){
9428                 var rvs = v.slice(4, v.length -1).split(",");
9429                 for(var i = 0; i < 3; i++){
9430                     var h = parseInt(rvs[i]).toString(16);
9431                     if(h < 16){
9432                         h = "0" + h;
9433                     }
9434                     color += h;
9435                 }
9436             } else {
9437                 if(v.substr(0, 1) == "#"){
9438                     if(v.length == 4) {
9439                         for(var i = 1; i < 4; i++){
9440                             var c = v.charAt(i);
9441                             color +=  c + c;
9442                         }
9443                     }else if(v.length == 7){
9444                         color += v.substr(1);
9445                     }
9446                 }
9447             }
9448             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9449         },
9450
9451         /**
9452          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9453          * gradient background, rounded corners and a 4-way shadow.
9454          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9455          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9456          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9457          * @return {Roo.Element} this
9458          */
9459         boxWrap : function(cls){
9460             cls = cls || 'x-box';
9461             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9462             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9463             return el;
9464         },
9465
9466         /**
9467          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9468          * @param {String} namespace The namespace in which to look for the attribute
9469          * @param {String} name The attribute name
9470          * @return {String} The attribute value
9471          */
9472         getAttributeNS : Roo.isIE ? function(ns, name){
9473             var d = this.dom;
9474             var type = typeof d[ns+":"+name];
9475             if(type != 'undefined' && type != 'unknown'){
9476                 return d[ns+":"+name];
9477             }
9478             return d[name];
9479         } : function(ns, name){
9480             var d = this.dom;
9481             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9482         }
9483     };
9484
9485     var ep = El.prototype;
9486
9487     /**
9488      * Appends an event handler (Shorthand for addListener)
9489      * @param {String}   eventName     The type of event to append
9490      * @param {Function} fn        The method the event invokes
9491      * @param {Object} scope       (optional) The scope (this object) of the fn
9492      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9493      * @method
9494      */
9495     ep.on = ep.addListener;
9496         // backwards compat
9497     ep.mon = ep.addListener;
9498
9499     /**
9500      * Removes an event handler from this element (shorthand for removeListener)
9501      * @param {String} eventName the type of event to remove
9502      * @param {Function} fn the method the event invokes
9503      * @return {Roo.Element} this
9504      * @method
9505      */
9506     ep.un = ep.removeListener;
9507
9508     /**
9509      * true to automatically adjust width and height settings for box-model issues (default to true)
9510      */
9511     ep.autoBoxAdjust = true;
9512
9513     // private
9514     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9515
9516     // private
9517     El.addUnits = function(v, defaultUnit){
9518         if(v === "" || v == "auto"){
9519             return v;
9520         }
9521         if(v === undefined){
9522             return '';
9523         }
9524         if(typeof v == "number" || !El.unitPattern.test(v)){
9525             return v + (defaultUnit || 'px');
9526         }
9527         return v;
9528     };
9529
9530     // special markup used throughout Roo when box wrapping elements
9531     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>';
9532     /**
9533      * Visibility mode constant - Use visibility to hide element
9534      * @static
9535      * @type Number
9536      */
9537     El.VISIBILITY = 1;
9538     /**
9539      * Visibility mode constant - Use display to hide element
9540      * @static
9541      * @type Number
9542      */
9543     El.DISPLAY = 2;
9544
9545     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9546     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9547     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9548
9549
9550
9551     /**
9552      * @private
9553      */
9554     El.cache = {};
9555
9556     var docEl;
9557
9558     /**
9559      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9560      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9561      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9562      * @return {Element} The Element object
9563      * @static
9564      */
9565     El.get = function(el){
9566         var ex, elm, id;
9567         if(!el){ return null; }
9568         if(typeof el == "string"){ // element id
9569             if(!(elm = document.getElementById(el))){
9570                 return null;
9571             }
9572             if(ex = El.cache[el]){
9573                 ex.dom = elm;
9574             }else{
9575                 ex = El.cache[el] = new El(elm);
9576             }
9577             return ex;
9578         }else if(el.tagName){ // dom element
9579             if(!(id = el.id)){
9580                 id = Roo.id(el);
9581             }
9582             if(ex = El.cache[id]){
9583                 ex.dom = el;
9584             }else{
9585                 ex = El.cache[id] = new El(el);
9586             }
9587             return ex;
9588         }else if(el instanceof El){
9589             if(el != docEl){
9590                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9591                                                               // catch case where it hasn't been appended
9592                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9593             }
9594             return el;
9595         }else if(el.isComposite){
9596             return el;
9597         }else if(el instanceof Array){
9598             return El.select(el);
9599         }else if(el == document){
9600             // create a bogus element object representing the document object
9601             if(!docEl){
9602                 var f = function(){};
9603                 f.prototype = El.prototype;
9604                 docEl = new f();
9605                 docEl.dom = document;
9606             }
9607             return docEl;
9608         }
9609         return null;
9610     };
9611
9612     // private
9613     El.uncache = function(el){
9614         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9615             if(a[i]){
9616                 delete El.cache[a[i].id || a[i]];
9617             }
9618         }
9619     };
9620
9621     // private
9622     // Garbage collection - uncache elements/purge listeners on orphaned elements
9623     // so we don't hold a reference and cause the browser to retain them
9624     El.garbageCollect = function(){
9625         if(!Roo.enableGarbageCollector){
9626             clearInterval(El.collectorThread);
9627             return;
9628         }
9629         for(var eid in El.cache){
9630             var el = El.cache[eid], d = el.dom;
9631             // -------------------------------------------------------
9632             // Determining what is garbage:
9633             // -------------------------------------------------------
9634             // !d
9635             // dom node is null, definitely garbage
9636             // -------------------------------------------------------
9637             // !d.parentNode
9638             // no parentNode == direct orphan, definitely garbage
9639             // -------------------------------------------------------
9640             // !d.offsetParent && !document.getElementById(eid)
9641             // display none elements have no offsetParent so we will
9642             // also try to look it up by it's id. However, check
9643             // offsetParent first so we don't do unneeded lookups.
9644             // This enables collection of elements that are not orphans
9645             // directly, but somewhere up the line they have an orphan
9646             // parent.
9647             // -------------------------------------------------------
9648             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9649                 delete El.cache[eid];
9650                 if(d && Roo.enableListenerCollection){
9651                     E.purgeElement(d);
9652                 }
9653             }
9654         }
9655     }
9656     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9657
9658
9659     // dom is optional
9660     El.Flyweight = function(dom){
9661         this.dom = dom;
9662     };
9663     El.Flyweight.prototype = El.prototype;
9664
9665     El._flyweights = {};
9666     /**
9667      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9668      * the dom node can be overwritten by other code.
9669      * @param {String/HTMLElement} el The dom node or id
9670      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9671      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9672      * @static
9673      * @return {Element} The shared Element object
9674      */
9675     El.fly = function(el, named){
9676         named = named || '_global';
9677         el = Roo.getDom(el);
9678         if(!el){
9679             return null;
9680         }
9681         if(!El._flyweights[named]){
9682             El._flyweights[named] = new El.Flyweight();
9683         }
9684         El._flyweights[named].dom = el;
9685         return El._flyweights[named];
9686     };
9687
9688     /**
9689      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9690      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9691      * Shorthand of {@link Roo.Element#get}
9692      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9693      * @return {Element} The Element object
9694      * @member Roo
9695      * @method get
9696      */
9697     Roo.get = El.get;
9698     /**
9699      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9700      * the dom node can be overwritten by other code.
9701      * Shorthand of {@link Roo.Element#fly}
9702      * @param {String/HTMLElement} el The dom node or id
9703      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9704      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9705      * @static
9706      * @return {Element} The shared Element object
9707      * @member Roo
9708      * @method fly
9709      */
9710     Roo.fly = El.fly;
9711
9712     // speedy lookup for elements never to box adjust
9713     var noBoxAdjust = Roo.isStrict ? {
9714         select:1
9715     } : {
9716         input:1, select:1, textarea:1
9717     };
9718     if(Roo.isIE || Roo.isGecko){
9719         noBoxAdjust['button'] = 1;
9720     }
9721
9722
9723     Roo.EventManager.on(window, 'unload', function(){
9724         delete El.cache;
9725         delete El._flyweights;
9726     });
9727 })();
9728
9729
9730
9731
9732 if(Roo.DomQuery){
9733     Roo.Element.selectorFunction = Roo.DomQuery.select;
9734 }
9735
9736 Roo.Element.select = function(selector, unique, root){
9737     var els;
9738     if(typeof selector == "string"){
9739         els = Roo.Element.selectorFunction(selector, root);
9740     }else if(selector.length !== undefined){
9741         els = selector;
9742     }else{
9743         throw "Invalid selector";
9744     }
9745     if(unique === true){
9746         return new Roo.CompositeElement(els);
9747     }else{
9748         return new Roo.CompositeElementLite(els);
9749     }
9750 };
9751 /**
9752  * Selects elements based on the passed CSS selector to enable working on them as 1.
9753  * @param {String/Array} selector The CSS selector or an array of elements
9754  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9755  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9756  * @return {CompositeElementLite/CompositeElement}
9757  * @member Roo
9758  * @method select
9759  */
9760 Roo.select = Roo.Element.select;
9761
9762
9763
9764
9765
9766
9767
9768
9769
9770
9771
9772
9773
9774
9775 /*
9776  * Based on:
9777  * Ext JS Library 1.1.1
9778  * Copyright(c) 2006-2007, Ext JS, LLC.
9779  *
9780  * Originally Released Under LGPL - original licence link has changed is not relivant.
9781  *
9782  * Fork - LGPL
9783  * <script type="text/javascript">
9784  */
9785
9786
9787
9788 //Notifies Element that fx methods are available
9789 Roo.enableFx = true;
9790
9791 /**
9792  * @class Roo.Fx
9793  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9794  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9795  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9796  * Element effects to work.</p><br/>
9797  *
9798  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9799  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9800  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9801  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9802  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9803  * expected results and should be done with care.</p><br/>
9804  *
9805  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9806  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9807 <pre>
9808 Value  Description
9809 -----  -----------------------------
9810 tl     The top left corner
9811 t      The center of the top edge
9812 tr     The top right corner
9813 l      The center of the left edge
9814 r      The center of the right edge
9815 bl     The bottom left corner
9816 b      The center of the bottom edge
9817 br     The bottom right corner
9818 </pre>
9819  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9820  * below are common options that can be passed to any Fx method.</b>
9821  * @cfg {Function} callback A function called when the effect is finished
9822  * @cfg {Object} scope The scope of the effect function
9823  * @cfg {String} easing A valid Easing value for the effect
9824  * @cfg {String} afterCls A css class to apply after the effect
9825  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9826  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9827  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9828  * effects that end with the element being visually hidden, ignored otherwise)
9829  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9830  * a function which returns such a specification that will be applied to the Element after the effect finishes
9831  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9832  * @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
9833  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9834  */
9835 Roo.Fx = {
9836         /**
9837          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9838          * origin for the slide effect.  This function automatically handles wrapping the element with
9839          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9840          * Usage:
9841          *<pre><code>
9842 // default: slide the element in from the top
9843 el.slideIn();
9844
9845 // custom: slide the element in from the right with a 2-second duration
9846 el.slideIn('r', { duration: 2 });
9847
9848 // common config options shown with default values
9849 el.slideIn('t', {
9850     easing: 'easeOut',
9851     duration: .5
9852 });
9853 </code></pre>
9854          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9855          * @param {Object} options (optional) Object literal with any of the Fx config options
9856          * @return {Roo.Element} The Element
9857          */
9858     slideIn : function(anchor, o){
9859         var el = this.getFxEl();
9860         o = o || {};
9861
9862         el.queueFx(o, function(){
9863
9864             anchor = anchor || "t";
9865
9866             // fix display to visibility
9867             this.fixDisplay();
9868
9869             // restore values after effect
9870             var r = this.getFxRestore();
9871             var b = this.getBox();
9872             // fixed size for slide
9873             this.setSize(b);
9874
9875             // wrap if needed
9876             var wrap = this.fxWrap(r.pos, o, "hidden");
9877
9878             var st = this.dom.style;
9879             st.visibility = "visible";
9880             st.position = "absolute";
9881
9882             // clear out temp styles after slide and unwrap
9883             var after = function(){
9884                 el.fxUnwrap(wrap, r.pos, o);
9885                 st.width = r.width;
9886                 st.height = r.height;
9887                 el.afterFx(o);
9888             };
9889             // time to calc the positions
9890             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9891
9892             switch(anchor.toLowerCase()){
9893                 case "t":
9894                     wrap.setSize(b.width, 0);
9895                     st.left = st.bottom = "0";
9896                     a = {height: bh};
9897                 break;
9898                 case "l":
9899                     wrap.setSize(0, b.height);
9900                     st.right = st.top = "0";
9901                     a = {width: bw};
9902                 break;
9903                 case "r":
9904                     wrap.setSize(0, b.height);
9905                     wrap.setX(b.right);
9906                     st.left = st.top = "0";
9907                     a = {width: bw, points: pt};
9908                 break;
9909                 case "b":
9910                     wrap.setSize(b.width, 0);
9911                     wrap.setY(b.bottom);
9912                     st.left = st.top = "0";
9913                     a = {height: bh, points: pt};
9914                 break;
9915                 case "tl":
9916                     wrap.setSize(0, 0);
9917                     st.right = st.bottom = "0";
9918                     a = {width: bw, height: bh};
9919                 break;
9920                 case "bl":
9921                     wrap.setSize(0, 0);
9922                     wrap.setY(b.y+b.height);
9923                     st.right = st.top = "0";
9924                     a = {width: bw, height: bh, points: pt};
9925                 break;
9926                 case "br":
9927                     wrap.setSize(0, 0);
9928                     wrap.setXY([b.right, b.bottom]);
9929                     st.left = st.top = "0";
9930                     a = {width: bw, height: bh, points: pt};
9931                 break;
9932                 case "tr":
9933                     wrap.setSize(0, 0);
9934                     wrap.setX(b.x+b.width);
9935                     st.left = st.bottom = "0";
9936                     a = {width: bw, height: bh, points: pt};
9937                 break;
9938             }
9939             this.dom.style.visibility = "visible";
9940             wrap.show();
9941
9942             arguments.callee.anim = wrap.fxanim(a,
9943                 o,
9944                 'motion',
9945                 .5,
9946                 'easeOut', after);
9947         });
9948         return this;
9949     },
9950     
9951         /**
9952          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9953          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9954          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9955          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9956          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9957          * Usage:
9958          *<pre><code>
9959 // default: slide the element out to the top
9960 el.slideOut();
9961
9962 // custom: slide the element out to the right with a 2-second duration
9963 el.slideOut('r', { duration: 2 });
9964
9965 // common config options shown with default values
9966 el.slideOut('t', {
9967     easing: 'easeOut',
9968     duration: .5,
9969     remove: false,
9970     useDisplay: false
9971 });
9972 </code></pre>
9973          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9974          * @param {Object} options (optional) Object literal with any of the Fx config options
9975          * @return {Roo.Element} The Element
9976          */
9977     slideOut : function(anchor, o){
9978         var el = this.getFxEl();
9979         o = o || {};
9980
9981         el.queueFx(o, function(){
9982
9983             anchor = anchor || "t";
9984
9985             // restore values after effect
9986             var r = this.getFxRestore();
9987             
9988             var b = this.getBox();
9989             // fixed size for slide
9990             this.setSize(b);
9991
9992             // wrap if needed
9993             var wrap = this.fxWrap(r.pos, o, "visible");
9994
9995             var st = this.dom.style;
9996             st.visibility = "visible";
9997             st.position = "absolute";
9998
9999             wrap.setSize(b);
10000
10001             var after = function(){
10002                 if(o.useDisplay){
10003                     el.setDisplayed(false);
10004                 }else{
10005                     el.hide();
10006                 }
10007
10008                 el.fxUnwrap(wrap, r.pos, o);
10009
10010                 st.width = r.width;
10011                 st.height = r.height;
10012
10013                 el.afterFx(o);
10014             };
10015
10016             var a, zero = {to: 0};
10017             switch(anchor.toLowerCase()){
10018                 case "t":
10019                     st.left = st.bottom = "0";
10020                     a = {height: zero};
10021                 break;
10022                 case "l":
10023                     st.right = st.top = "0";
10024                     a = {width: zero};
10025                 break;
10026                 case "r":
10027                     st.left = st.top = "0";
10028                     a = {width: zero, points: {to:[b.right, b.y]}};
10029                 break;
10030                 case "b":
10031                     st.left = st.top = "0";
10032                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10033                 break;
10034                 case "tl":
10035                     st.right = st.bottom = "0";
10036                     a = {width: zero, height: zero};
10037                 break;
10038                 case "bl":
10039                     st.right = st.top = "0";
10040                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10041                 break;
10042                 case "br":
10043                     st.left = st.top = "0";
10044                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10045                 break;
10046                 case "tr":
10047                     st.left = st.bottom = "0";
10048                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10049                 break;
10050             }
10051
10052             arguments.callee.anim = wrap.fxanim(a,
10053                 o,
10054                 'motion',
10055                 .5,
10056                 "easeOut", after);
10057         });
10058         return this;
10059     },
10060
10061         /**
10062          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10063          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10064          * The element must be removed from the DOM using the 'remove' config option if desired.
10065          * Usage:
10066          *<pre><code>
10067 // default
10068 el.puff();
10069
10070 // common config options shown with default values
10071 el.puff({
10072     easing: 'easeOut',
10073     duration: .5,
10074     remove: false,
10075     useDisplay: false
10076 });
10077 </code></pre>
10078          * @param {Object} options (optional) Object literal with any of the Fx config options
10079          * @return {Roo.Element} The Element
10080          */
10081     puff : function(o){
10082         var el = this.getFxEl();
10083         o = o || {};
10084
10085         el.queueFx(o, function(){
10086             this.clearOpacity();
10087             this.show();
10088
10089             // restore values after effect
10090             var r = this.getFxRestore();
10091             var st = this.dom.style;
10092
10093             var after = function(){
10094                 if(o.useDisplay){
10095                     el.setDisplayed(false);
10096                 }else{
10097                     el.hide();
10098                 }
10099
10100                 el.clearOpacity();
10101
10102                 el.setPositioning(r.pos);
10103                 st.width = r.width;
10104                 st.height = r.height;
10105                 st.fontSize = '';
10106                 el.afterFx(o);
10107             };
10108
10109             var width = this.getWidth();
10110             var height = this.getHeight();
10111
10112             arguments.callee.anim = this.fxanim({
10113                     width : {to: this.adjustWidth(width * 2)},
10114                     height : {to: this.adjustHeight(height * 2)},
10115                     points : {by: [-(width * .5), -(height * .5)]},
10116                     opacity : {to: 0},
10117                     fontSize: {to:200, unit: "%"}
10118                 },
10119                 o,
10120                 'motion',
10121                 .5,
10122                 "easeOut", after);
10123         });
10124         return this;
10125     },
10126
10127         /**
10128          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10129          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10130          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10131          * Usage:
10132          *<pre><code>
10133 // default
10134 el.switchOff();
10135
10136 // all config options shown with default values
10137 el.switchOff({
10138     easing: 'easeIn',
10139     duration: .3,
10140     remove: false,
10141     useDisplay: false
10142 });
10143 </code></pre>
10144          * @param {Object} options (optional) Object literal with any of the Fx config options
10145          * @return {Roo.Element} The Element
10146          */
10147     switchOff : function(o){
10148         var el = this.getFxEl();
10149         o = o || {};
10150
10151         el.queueFx(o, function(){
10152             this.clearOpacity();
10153             this.clip();
10154
10155             // restore values after effect
10156             var r = this.getFxRestore();
10157             var st = this.dom.style;
10158
10159             var after = function(){
10160                 if(o.useDisplay){
10161                     el.setDisplayed(false);
10162                 }else{
10163                     el.hide();
10164                 }
10165
10166                 el.clearOpacity();
10167                 el.setPositioning(r.pos);
10168                 st.width = r.width;
10169                 st.height = r.height;
10170
10171                 el.afterFx(o);
10172             };
10173
10174             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10175                 this.clearOpacity();
10176                 (function(){
10177                     this.fxanim({
10178                         height:{to:1},
10179                         points:{by:[0, this.getHeight() * .5]}
10180                     }, o, 'motion', 0.3, 'easeIn', after);
10181                 }).defer(100, this);
10182             });
10183         });
10184         return this;
10185     },
10186
10187     /**
10188      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10189      * changed using the "attr" config option) and then fading back to the original color. If no original
10190      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10191      * Usage:
10192 <pre><code>
10193 // default: highlight background to yellow
10194 el.highlight();
10195
10196 // custom: highlight foreground text to blue for 2 seconds
10197 el.highlight("0000ff", { attr: 'color', duration: 2 });
10198
10199 // common config options shown with default values
10200 el.highlight("ffff9c", {
10201     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10202     endColor: (current color) or "ffffff",
10203     easing: 'easeIn',
10204     duration: 1
10205 });
10206 </code></pre>
10207      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10208      * @param {Object} options (optional) Object literal with any of the Fx config options
10209      * @return {Roo.Element} The Element
10210      */ 
10211     highlight : function(color, o){
10212         var el = this.getFxEl();
10213         o = o || {};
10214
10215         el.queueFx(o, function(){
10216             color = color || "ffff9c";
10217             attr = o.attr || "backgroundColor";
10218
10219             this.clearOpacity();
10220             this.show();
10221
10222             var origColor = this.getColor(attr);
10223             var restoreColor = this.dom.style[attr];
10224             endColor = (o.endColor || origColor) || "ffffff";
10225
10226             var after = function(){
10227                 el.dom.style[attr] = restoreColor;
10228                 el.afterFx(o);
10229             };
10230
10231             var a = {};
10232             a[attr] = {from: color, to: endColor};
10233             arguments.callee.anim = this.fxanim(a,
10234                 o,
10235                 'color',
10236                 1,
10237                 'easeIn', after);
10238         });
10239         return this;
10240     },
10241
10242    /**
10243     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10244     * Usage:
10245 <pre><code>
10246 // default: a single light blue ripple
10247 el.frame();
10248
10249 // custom: 3 red ripples lasting 3 seconds total
10250 el.frame("ff0000", 3, { duration: 3 });
10251
10252 // common config options shown with default values
10253 el.frame("C3DAF9", 1, {
10254     duration: 1 //duration of entire animation (not each individual ripple)
10255     // Note: Easing is not configurable and will be ignored if included
10256 });
10257 </code></pre>
10258     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10259     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10260     * @param {Object} options (optional) Object literal with any of the Fx config options
10261     * @return {Roo.Element} The Element
10262     */
10263     frame : function(color, count, o){
10264         var el = this.getFxEl();
10265         o = o || {};
10266
10267         el.queueFx(o, function(){
10268             color = color || "#C3DAF9";
10269             if(color.length == 6){
10270                 color = "#" + color;
10271             }
10272             count = count || 1;
10273             duration = o.duration || 1;
10274             this.show();
10275
10276             var b = this.getBox();
10277             var animFn = function(){
10278                 var proxy = this.createProxy({
10279
10280                      style:{
10281                         visbility:"hidden",
10282                         position:"absolute",
10283                         "z-index":"35000", // yee haw
10284                         border:"0px solid " + color
10285                      }
10286                   });
10287                 var scale = Roo.isBorderBox ? 2 : 1;
10288                 proxy.animate({
10289                     top:{from:b.y, to:b.y - 20},
10290                     left:{from:b.x, to:b.x - 20},
10291                     borderWidth:{from:0, to:10},
10292                     opacity:{from:1, to:0},
10293                     height:{from:b.height, to:(b.height + (20*scale))},
10294                     width:{from:b.width, to:(b.width + (20*scale))}
10295                 }, duration, function(){
10296                     proxy.remove();
10297                 });
10298                 if(--count > 0){
10299                      animFn.defer((duration/2)*1000, this);
10300                 }else{
10301                     el.afterFx(o);
10302                 }
10303             };
10304             animFn.call(this);
10305         });
10306         return this;
10307     },
10308
10309    /**
10310     * Creates a pause before any subsequent queued effects begin.  If there are
10311     * no effects queued after the pause it will have no effect.
10312     * Usage:
10313 <pre><code>
10314 el.pause(1);
10315 </code></pre>
10316     * @param {Number} seconds The length of time to pause (in seconds)
10317     * @return {Roo.Element} The Element
10318     */
10319     pause : function(seconds){
10320         var el = this.getFxEl();
10321         var o = {};
10322
10323         el.queueFx(o, function(){
10324             setTimeout(function(){
10325                 el.afterFx(o);
10326             }, seconds * 1000);
10327         });
10328         return this;
10329     },
10330
10331    /**
10332     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10333     * using the "endOpacity" config option.
10334     * Usage:
10335 <pre><code>
10336 // default: fade in from opacity 0 to 100%
10337 el.fadeIn();
10338
10339 // custom: fade in from opacity 0 to 75% over 2 seconds
10340 el.fadeIn({ endOpacity: .75, duration: 2});
10341
10342 // common config options shown with default values
10343 el.fadeIn({
10344     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10345     easing: 'easeOut',
10346     duration: .5
10347 });
10348 </code></pre>
10349     * @param {Object} options (optional) Object literal with any of the Fx config options
10350     * @return {Roo.Element} The Element
10351     */
10352     fadeIn : function(o){
10353         var el = this.getFxEl();
10354         o = o || {};
10355         el.queueFx(o, function(){
10356             this.setOpacity(0);
10357             this.fixDisplay();
10358             this.dom.style.visibility = 'visible';
10359             var to = o.endOpacity || 1;
10360             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10361                 o, null, .5, "easeOut", function(){
10362                 if(to == 1){
10363                     this.clearOpacity();
10364                 }
10365                 el.afterFx(o);
10366             });
10367         });
10368         return this;
10369     },
10370
10371    /**
10372     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10373     * using the "endOpacity" config option.
10374     * Usage:
10375 <pre><code>
10376 // default: fade out from the element's current opacity to 0
10377 el.fadeOut();
10378
10379 // custom: fade out from the element's current opacity to 25% over 2 seconds
10380 el.fadeOut({ endOpacity: .25, duration: 2});
10381
10382 // common config options shown with default values
10383 el.fadeOut({
10384     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10385     easing: 'easeOut',
10386     duration: .5
10387     remove: false,
10388     useDisplay: false
10389 });
10390 </code></pre>
10391     * @param {Object} options (optional) Object literal with any of the Fx config options
10392     * @return {Roo.Element} The Element
10393     */
10394     fadeOut : function(o){
10395         var el = this.getFxEl();
10396         o = o || {};
10397         el.queueFx(o, function(){
10398             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10399                 o, null, .5, "easeOut", function(){
10400                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10401                      this.dom.style.display = "none";
10402                 }else{
10403                      this.dom.style.visibility = "hidden";
10404                 }
10405                 this.clearOpacity();
10406                 el.afterFx(o);
10407             });
10408         });
10409         return this;
10410     },
10411
10412    /**
10413     * Animates the transition of an element's dimensions from a starting height/width
10414     * to an ending height/width.
10415     * Usage:
10416 <pre><code>
10417 // change height and width to 100x100 pixels
10418 el.scale(100, 100);
10419
10420 // common config options shown with default values.  The height and width will default to
10421 // the element's existing values if passed as null.
10422 el.scale(
10423     [element's width],
10424     [element's height], {
10425     easing: 'easeOut',
10426     duration: .35
10427 });
10428 </code></pre>
10429     * @param {Number} width  The new width (pass undefined to keep the original width)
10430     * @param {Number} height  The new height (pass undefined to keep the original height)
10431     * @param {Object} options (optional) Object literal with any of the Fx config options
10432     * @return {Roo.Element} The Element
10433     */
10434     scale : function(w, h, o){
10435         this.shift(Roo.apply({}, o, {
10436             width: w,
10437             height: h
10438         }));
10439         return this;
10440     },
10441
10442    /**
10443     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10444     * Any of these properties not specified in the config object will not be changed.  This effect 
10445     * requires that at least one new dimension, position or opacity setting must be passed in on
10446     * the config object in order for the function to have any effect.
10447     * Usage:
10448 <pre><code>
10449 // slide the element horizontally to x position 200 while changing the height and opacity
10450 el.shift({ x: 200, height: 50, opacity: .8 });
10451
10452 // common config options shown with default values.
10453 el.shift({
10454     width: [element's width],
10455     height: [element's height],
10456     x: [element's x position],
10457     y: [element's y position],
10458     opacity: [element's opacity],
10459     easing: 'easeOut',
10460     duration: .35
10461 });
10462 </code></pre>
10463     * @param {Object} options  Object literal with any of the Fx config options
10464     * @return {Roo.Element} The Element
10465     */
10466     shift : function(o){
10467         var el = this.getFxEl();
10468         o = o || {};
10469         el.queueFx(o, function(){
10470             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10471             if(w !== undefined){
10472                 a.width = {to: this.adjustWidth(w)};
10473             }
10474             if(h !== undefined){
10475                 a.height = {to: this.adjustHeight(h)};
10476             }
10477             if(x !== undefined || y !== undefined){
10478                 a.points = {to: [
10479                     x !== undefined ? x : this.getX(),
10480                     y !== undefined ? y : this.getY()
10481                 ]};
10482             }
10483             if(op !== undefined){
10484                 a.opacity = {to: op};
10485             }
10486             if(o.xy !== undefined){
10487                 a.points = {to: o.xy};
10488             }
10489             arguments.callee.anim = this.fxanim(a,
10490                 o, 'motion', .35, "easeOut", function(){
10491                 el.afterFx(o);
10492             });
10493         });
10494         return this;
10495     },
10496
10497         /**
10498          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10499          * ending point of the effect.
10500          * Usage:
10501          *<pre><code>
10502 // default: slide the element downward while fading out
10503 el.ghost();
10504
10505 // custom: slide the element out to the right with a 2-second duration
10506 el.ghost('r', { duration: 2 });
10507
10508 // common config options shown with default values
10509 el.ghost('b', {
10510     easing: 'easeOut',
10511     duration: .5
10512     remove: false,
10513     useDisplay: false
10514 });
10515 </code></pre>
10516          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10517          * @param {Object} options (optional) Object literal with any of the Fx config options
10518          * @return {Roo.Element} The Element
10519          */
10520     ghost : function(anchor, o){
10521         var el = this.getFxEl();
10522         o = o || {};
10523
10524         el.queueFx(o, function(){
10525             anchor = anchor || "b";
10526
10527             // restore values after effect
10528             var r = this.getFxRestore();
10529             var w = this.getWidth(),
10530                 h = this.getHeight();
10531
10532             var st = this.dom.style;
10533
10534             var after = function(){
10535                 if(o.useDisplay){
10536                     el.setDisplayed(false);
10537                 }else{
10538                     el.hide();
10539                 }
10540
10541                 el.clearOpacity();
10542                 el.setPositioning(r.pos);
10543                 st.width = r.width;
10544                 st.height = r.height;
10545
10546                 el.afterFx(o);
10547             };
10548
10549             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10550             switch(anchor.toLowerCase()){
10551                 case "t":
10552                     pt.by = [0, -h];
10553                 break;
10554                 case "l":
10555                     pt.by = [-w, 0];
10556                 break;
10557                 case "r":
10558                     pt.by = [w, 0];
10559                 break;
10560                 case "b":
10561                     pt.by = [0, h];
10562                 break;
10563                 case "tl":
10564                     pt.by = [-w, -h];
10565                 break;
10566                 case "bl":
10567                     pt.by = [-w, h];
10568                 break;
10569                 case "br":
10570                     pt.by = [w, h];
10571                 break;
10572                 case "tr":
10573                     pt.by = [w, -h];
10574                 break;
10575             }
10576
10577             arguments.callee.anim = this.fxanim(a,
10578                 o,
10579                 'motion',
10580                 .5,
10581                 "easeOut", after);
10582         });
10583         return this;
10584     },
10585
10586         /**
10587          * Ensures that all effects queued after syncFx is called on the element are
10588          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10589          * @return {Roo.Element} The Element
10590          */
10591     syncFx : function(){
10592         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10593             block : false,
10594             concurrent : true,
10595             stopFx : false
10596         });
10597         return this;
10598     },
10599
10600         /**
10601          * Ensures that all effects queued after sequenceFx is called on the element are
10602          * run in sequence.  This is the opposite of {@link #syncFx}.
10603          * @return {Roo.Element} The Element
10604          */
10605     sequenceFx : function(){
10606         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10607             block : false,
10608             concurrent : false,
10609             stopFx : false
10610         });
10611         return this;
10612     },
10613
10614         /* @private */
10615     nextFx : function(){
10616         var ef = this.fxQueue[0];
10617         if(ef){
10618             ef.call(this);
10619         }
10620     },
10621
10622         /**
10623          * Returns true if the element has any effects actively running or queued, else returns false.
10624          * @return {Boolean} True if element has active effects, else false
10625          */
10626     hasActiveFx : function(){
10627         return this.fxQueue && this.fxQueue[0];
10628     },
10629
10630         /**
10631          * Stops any running effects and clears the element's internal effects queue if it contains
10632          * any additional effects that haven't started yet.
10633          * @return {Roo.Element} The Element
10634          */
10635     stopFx : function(){
10636         if(this.hasActiveFx()){
10637             var cur = this.fxQueue[0];
10638             if(cur && cur.anim && cur.anim.isAnimated()){
10639                 this.fxQueue = [cur]; // clear out others
10640                 cur.anim.stop(true);
10641             }
10642         }
10643         return this;
10644     },
10645
10646         /* @private */
10647     beforeFx : function(o){
10648         if(this.hasActiveFx() && !o.concurrent){
10649            if(o.stopFx){
10650                this.stopFx();
10651                return true;
10652            }
10653            return false;
10654         }
10655         return true;
10656     },
10657
10658         /**
10659          * Returns true if the element is currently blocking so that no other effect can be queued
10660          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10661          * used to ensure that an effect initiated by a user action runs to completion prior to the
10662          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10663          * @return {Boolean} True if blocking, else false
10664          */
10665     hasFxBlock : function(){
10666         var q = this.fxQueue;
10667         return q && q[0] && q[0].block;
10668     },
10669
10670         /* @private */
10671     queueFx : function(o, fn){
10672         if(!this.fxQueue){
10673             this.fxQueue = [];
10674         }
10675         if(!this.hasFxBlock()){
10676             Roo.applyIf(o, this.fxDefaults);
10677             if(!o.concurrent){
10678                 var run = this.beforeFx(o);
10679                 fn.block = o.block;
10680                 this.fxQueue.push(fn);
10681                 if(run){
10682                     this.nextFx();
10683                 }
10684             }else{
10685                 fn.call(this);
10686             }
10687         }
10688         return this;
10689     },
10690
10691         /* @private */
10692     fxWrap : function(pos, o, vis){
10693         var wrap;
10694         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10695             var wrapXY;
10696             if(o.fixPosition){
10697                 wrapXY = this.getXY();
10698             }
10699             var div = document.createElement("div");
10700             div.style.visibility = vis;
10701             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10702             wrap.setPositioning(pos);
10703             if(wrap.getStyle("position") == "static"){
10704                 wrap.position("relative");
10705             }
10706             this.clearPositioning('auto');
10707             wrap.clip();
10708             wrap.dom.appendChild(this.dom);
10709             if(wrapXY){
10710                 wrap.setXY(wrapXY);
10711             }
10712         }
10713         return wrap;
10714     },
10715
10716         /* @private */
10717     fxUnwrap : function(wrap, pos, o){
10718         this.clearPositioning();
10719         this.setPositioning(pos);
10720         if(!o.wrap){
10721             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10722             wrap.remove();
10723         }
10724     },
10725
10726         /* @private */
10727     getFxRestore : function(){
10728         var st = this.dom.style;
10729         return {pos: this.getPositioning(), width: st.width, height : st.height};
10730     },
10731
10732         /* @private */
10733     afterFx : function(o){
10734         if(o.afterStyle){
10735             this.applyStyles(o.afterStyle);
10736         }
10737         if(o.afterCls){
10738             this.addClass(o.afterCls);
10739         }
10740         if(o.remove === true){
10741             this.remove();
10742         }
10743         Roo.callback(o.callback, o.scope, [this]);
10744         if(!o.concurrent){
10745             this.fxQueue.shift();
10746             this.nextFx();
10747         }
10748     },
10749
10750         /* @private */
10751     getFxEl : function(){ // support for composite element fx
10752         return Roo.get(this.dom);
10753     },
10754
10755         /* @private */
10756     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10757         animType = animType || 'run';
10758         opt = opt || {};
10759         var anim = Roo.lib.Anim[animType](
10760             this.dom, args,
10761             (opt.duration || defaultDur) || .35,
10762             (opt.easing || defaultEase) || 'easeOut',
10763             function(){
10764                 Roo.callback(cb, this);
10765             },
10766             this
10767         );
10768         opt.anim = anim;
10769         return anim;
10770     }
10771 };
10772
10773 // backwords compat
10774 Roo.Fx.resize = Roo.Fx.scale;
10775
10776 //When included, Roo.Fx is automatically applied to Element so that all basic
10777 //effects are available directly via the Element API
10778 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10779  * Based on:
10780  * Ext JS Library 1.1.1
10781  * Copyright(c) 2006-2007, Ext JS, LLC.
10782  *
10783  * Originally Released Under LGPL - original licence link has changed is not relivant.
10784  *
10785  * Fork - LGPL
10786  * <script type="text/javascript">
10787  */
10788
10789
10790 /**
10791  * @class Roo.CompositeElement
10792  * Standard composite class. Creates a Roo.Element for every element in the collection.
10793  * <br><br>
10794  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10795  * actions will be performed on all the elements in this collection.</b>
10796  * <br><br>
10797  * All methods return <i>this</i> and can be chained.
10798  <pre><code>
10799  var els = Roo.select("#some-el div.some-class", true);
10800  // or select directly from an existing element
10801  var el = Roo.get('some-el');
10802  el.select('div.some-class', true);
10803
10804  els.setWidth(100); // all elements become 100 width
10805  els.hide(true); // all elements fade out and hide
10806  // or
10807  els.setWidth(100).hide(true);
10808  </code></pre>
10809  */
10810 Roo.CompositeElement = function(els){
10811     this.elements = [];
10812     this.addElements(els);
10813 };
10814 Roo.CompositeElement.prototype = {
10815     isComposite: true,
10816     addElements : function(els){
10817         if(!els) return this;
10818         if(typeof els == "string"){
10819             els = Roo.Element.selectorFunction(els);
10820         }
10821         var yels = this.elements;
10822         var index = yels.length-1;
10823         for(var i = 0, len = els.length; i < len; i++) {
10824                 yels[++index] = Roo.get(els[i]);
10825         }
10826         return this;
10827     },
10828
10829     /**
10830     * Clears this composite and adds the elements returned by the passed selector.
10831     * @param {String/Array} els A string CSS selector, an array of elements or an element
10832     * @return {CompositeElement} this
10833     */
10834     fill : function(els){
10835         this.elements = [];
10836         this.add(els);
10837         return this;
10838     },
10839
10840     /**
10841     * Filters this composite to only elements that match the passed selector.
10842     * @param {String} selector A string CSS selector
10843     * @return {CompositeElement} this
10844     */
10845     filter : function(selector){
10846         var els = [];
10847         this.each(function(el){
10848             if(el.is(selector)){
10849                 els[els.length] = el.dom;
10850             }
10851         });
10852         this.fill(els);
10853         return this;
10854     },
10855
10856     invoke : function(fn, args){
10857         var els = this.elements;
10858         for(var i = 0, len = els.length; i < len; i++) {
10859                 Roo.Element.prototype[fn].apply(els[i], args);
10860         }
10861         return this;
10862     },
10863     /**
10864     * Adds elements to this composite.
10865     * @param {String/Array} els A string CSS selector, an array of elements or an element
10866     * @return {CompositeElement} this
10867     */
10868     add : function(els){
10869         if(typeof els == "string"){
10870             this.addElements(Roo.Element.selectorFunction(els));
10871         }else if(els.length !== undefined){
10872             this.addElements(els);
10873         }else{
10874             this.addElements([els]);
10875         }
10876         return this;
10877     },
10878     /**
10879     * Calls the passed function passing (el, this, index) for each element in this composite.
10880     * @param {Function} fn The function to call
10881     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10882     * @return {CompositeElement} this
10883     */
10884     each : function(fn, scope){
10885         var els = this.elements;
10886         for(var i = 0, len = els.length; i < len; i++){
10887             if(fn.call(scope || els[i], els[i], this, i) === false) {
10888                 break;
10889             }
10890         }
10891         return this;
10892     },
10893
10894     /**
10895      * Returns the Element object at the specified index
10896      * @param {Number} index
10897      * @return {Roo.Element}
10898      */
10899     item : function(index){
10900         return this.elements[index] || null;
10901     },
10902
10903     /**
10904      * Returns the first Element
10905      * @return {Roo.Element}
10906      */
10907     first : function(){
10908         return this.item(0);
10909     },
10910
10911     /**
10912      * Returns the last Element
10913      * @return {Roo.Element}
10914      */
10915     last : function(){
10916         return this.item(this.elements.length-1);
10917     },
10918
10919     /**
10920      * Returns the number of elements in this composite
10921      * @return Number
10922      */
10923     getCount : function(){
10924         return this.elements.length;
10925     },
10926
10927     /**
10928      * Returns true if this composite contains the passed element
10929      * @return Boolean
10930      */
10931     contains : function(el){
10932         return this.indexOf(el) !== -1;
10933     },
10934
10935     /**
10936      * Returns true if this composite contains the passed element
10937      * @return Boolean
10938      */
10939     indexOf : function(el){
10940         return this.elements.indexOf(Roo.get(el));
10941     },
10942
10943
10944     /**
10945     * Removes the specified element(s).
10946     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10947     * or an array of any of those.
10948     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10949     * @return {CompositeElement} this
10950     */
10951     removeElement : function(el, removeDom){
10952         if(el instanceof Array){
10953             for(var i = 0, len = el.length; i < len; i++){
10954                 this.removeElement(el[i]);
10955             }
10956             return this;
10957         }
10958         var index = typeof el == 'number' ? el : this.indexOf(el);
10959         if(index !== -1){
10960             if(removeDom){
10961                 var d = this.elements[index];
10962                 if(d.dom){
10963                     d.remove();
10964                 }else{
10965                     d.parentNode.removeChild(d);
10966                 }
10967             }
10968             this.elements.splice(index, 1);
10969         }
10970         return this;
10971     },
10972
10973     /**
10974     * Replaces the specified element with the passed element.
10975     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10976     * to replace.
10977     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10978     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10979     * @return {CompositeElement} this
10980     */
10981     replaceElement : function(el, replacement, domReplace){
10982         var index = typeof el == 'number' ? el : this.indexOf(el);
10983         if(index !== -1){
10984             if(domReplace){
10985                 this.elements[index].replaceWith(replacement);
10986             }else{
10987                 this.elements.splice(index, 1, Roo.get(replacement))
10988             }
10989         }
10990         return this;
10991     },
10992
10993     /**
10994      * Removes all elements.
10995      */
10996     clear : function(){
10997         this.elements = [];
10998     }
10999 };
11000 (function(){
11001     Roo.CompositeElement.createCall = function(proto, fnName){
11002         if(!proto[fnName]){
11003             proto[fnName] = function(){
11004                 return this.invoke(fnName, arguments);
11005             };
11006         }
11007     };
11008     for(var fnName in Roo.Element.prototype){
11009         if(typeof Roo.Element.prototype[fnName] == "function"){
11010             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11011         }
11012     };
11013 })();
11014 /*
11015  * Based on:
11016  * Ext JS Library 1.1.1
11017  * Copyright(c) 2006-2007, Ext JS, LLC.
11018  *
11019  * Originally Released Under LGPL - original licence link has changed is not relivant.
11020  *
11021  * Fork - LGPL
11022  * <script type="text/javascript">
11023  */
11024
11025 /**
11026  * @class Roo.CompositeElementLite
11027  * @extends Roo.CompositeElement
11028  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11029  <pre><code>
11030  var els = Roo.select("#some-el div.some-class");
11031  // or select directly from an existing element
11032  var el = Roo.get('some-el');
11033  el.select('div.some-class');
11034
11035  els.setWidth(100); // all elements become 100 width
11036  els.hide(true); // all elements fade out and hide
11037  // or
11038  els.setWidth(100).hide(true);
11039  </code></pre><br><br>
11040  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11041  * actions will be performed on all the elements in this collection.</b>
11042  */
11043 Roo.CompositeElementLite = function(els){
11044     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11045     this.el = new Roo.Element.Flyweight();
11046 };
11047 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11048     addElements : function(els){
11049         if(els){
11050             if(els instanceof Array){
11051                 this.elements = this.elements.concat(els);
11052             }else{
11053                 var yels = this.elements;
11054                 var index = yels.length-1;
11055                 for(var i = 0, len = els.length; i < len; i++) {
11056                     yels[++index] = els[i];
11057                 }
11058             }
11059         }
11060         return this;
11061     },
11062     invoke : function(fn, args){
11063         var els = this.elements;
11064         var el = this.el;
11065         for(var i = 0, len = els.length; i < len; i++) {
11066             el.dom = els[i];
11067                 Roo.Element.prototype[fn].apply(el, args);
11068         }
11069         return this;
11070     },
11071     /**
11072      * Returns a flyweight Element of the dom element object at the specified index
11073      * @param {Number} index
11074      * @return {Roo.Element}
11075      */
11076     item : function(index){
11077         if(!this.elements[index]){
11078             return null;
11079         }
11080         this.el.dom = this.elements[index];
11081         return this.el;
11082     },
11083
11084     // fixes scope with flyweight
11085     addListener : function(eventName, handler, scope, opt){
11086         var els = this.elements;
11087         for(var i = 0, len = els.length; i < len; i++) {
11088             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11089         }
11090         return this;
11091     },
11092
11093     /**
11094     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11095     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11096     * a reference to the dom node, use el.dom.</b>
11097     * @param {Function} fn The function to call
11098     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11099     * @return {CompositeElement} this
11100     */
11101     each : function(fn, scope){
11102         var els = this.elements;
11103         var el = this.el;
11104         for(var i = 0, len = els.length; i < len; i++){
11105             el.dom = els[i];
11106                 if(fn.call(scope || el, el, this, i) === false){
11107                 break;
11108             }
11109         }
11110         return this;
11111     },
11112
11113     indexOf : function(el){
11114         return this.elements.indexOf(Roo.getDom(el));
11115     },
11116
11117     replaceElement : function(el, replacement, domReplace){
11118         var index = typeof el == 'number' ? el : this.indexOf(el);
11119         if(index !== -1){
11120             replacement = Roo.getDom(replacement);
11121             if(domReplace){
11122                 var d = this.elements[index];
11123                 d.parentNode.insertBefore(replacement, d);
11124                 d.parentNode.removeChild(d);
11125             }
11126             this.elements.splice(index, 1, replacement);
11127         }
11128         return this;
11129     }
11130 });
11131 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11132
11133 /*
11134  * Based on:
11135  * Ext JS Library 1.1.1
11136  * Copyright(c) 2006-2007, Ext JS, LLC.
11137  *
11138  * Originally Released Under LGPL - original licence link has changed is not relivant.
11139  *
11140  * Fork - LGPL
11141  * <script type="text/javascript">
11142  */
11143
11144  
11145
11146 /**
11147  * @class Roo.data.Connection
11148  * @extends Roo.util.Observable
11149  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11150  * either to a configured URL, or to a URL specified at request time.<br><br>
11151  * <p>
11152  * Requests made by this class are asynchronous, and will return immediately. No data from
11153  * the server will be available to the statement immediately following the {@link #request} call.
11154  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11155  * <p>
11156  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11157  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11158  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11159  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11160  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11161  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11162  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11163  * standard DOM methods.
11164  * @constructor
11165  * @param {Object} config a configuration object.
11166  */
11167 Roo.data.Connection = function(config){
11168     Roo.apply(this, config);
11169     this.addEvents({
11170         /**
11171          * @event beforerequest
11172          * Fires before a network request is made to retrieve a data object.
11173          * @param {Connection} conn This Connection object.
11174          * @param {Object} options The options config object passed to the {@link #request} method.
11175          */
11176         "beforerequest" : true,
11177         /**
11178          * @event requestcomplete
11179          * Fires if the request was successfully completed.
11180          * @param {Connection} conn This Connection object.
11181          * @param {Object} response The XHR object containing the response data.
11182          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11183          * @param {Object} options The options config object passed to the {@link #request} method.
11184          */
11185         "requestcomplete" : true,
11186         /**
11187          * @event requestexception
11188          * Fires if an error HTTP status was returned from the server.
11189          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11190          * @param {Connection} conn This Connection object.
11191          * @param {Object} response The XHR object containing the response data.
11192          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11193          * @param {Object} options The options config object passed to the {@link #request} method.
11194          */
11195         "requestexception" : true
11196     });
11197     Roo.data.Connection.superclass.constructor.call(this);
11198 };
11199
11200 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11201     /**
11202      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11203      */
11204     /**
11205      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11206      * extra parameters to each request made by this object. (defaults to undefined)
11207      */
11208     /**
11209      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11210      *  to each request made by this object. (defaults to undefined)
11211      */
11212     /**
11213      * @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)
11214      */
11215     /**
11216      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11217      */
11218     timeout : 30000,
11219     /**
11220      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11221      * @type Boolean
11222      */
11223     autoAbort:false,
11224
11225     /**
11226      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11227      * @type Boolean
11228      */
11229     disableCaching: true,
11230
11231     /**
11232      * Sends an HTTP request to a remote server.
11233      * @param {Object} options An object which may contain the following properties:<ul>
11234      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11235      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11236      * request, a url encoded string or a function to call to get either.</li>
11237      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11238      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11239      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11240      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11241      * <li>options {Object} The parameter to the request call.</li>
11242      * <li>success {Boolean} True if the request succeeded.</li>
11243      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11244      * </ul></li>
11245      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11246      * The callback is passed the following parameters:<ul>
11247      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11248      * <li>options {Object} The parameter to the request call.</li>
11249      * </ul></li>
11250      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11251      * The callback is passed the following parameters:<ul>
11252      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11253      * <li>options {Object} The parameter to the request call.</li>
11254      * </ul></li>
11255      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11256      * for the callback function. Defaults to the browser window.</li>
11257      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11258      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11259      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11260      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11261      * params for the post data. Any params will be appended to the URL.</li>
11262      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11263      * </ul>
11264      * @return {Number} transactionId
11265      */
11266     request : function(o){
11267         if(this.fireEvent("beforerequest", this, o) !== false){
11268             var p = o.params;
11269
11270             if(typeof p == "function"){
11271                 p = p.call(o.scope||window, o);
11272             }
11273             if(typeof p == "object"){
11274                 p = Roo.urlEncode(o.params);
11275             }
11276             if(this.extraParams){
11277                 var extras = Roo.urlEncode(this.extraParams);
11278                 p = p ? (p + '&' + extras) : extras;
11279             }
11280
11281             var url = o.url || this.url;
11282             if(typeof url == 'function'){
11283                 url = url.call(o.scope||window, o);
11284             }
11285
11286             if(o.form){
11287                 var form = Roo.getDom(o.form);
11288                 url = url || form.action;
11289
11290                 var enctype = form.getAttribute("enctype");
11291                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11292                     return this.doFormUpload(o, p, url);
11293                 }
11294                 var f = Roo.lib.Ajax.serializeForm(form);
11295                 p = p ? (p + '&' + f) : f;
11296             }
11297
11298             var hs = o.headers;
11299             if(this.defaultHeaders){
11300                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11301                 if(!o.headers){
11302                     o.headers = hs;
11303                 }
11304             }
11305
11306             var cb = {
11307                 success: this.handleResponse,
11308                 failure: this.handleFailure,
11309                 scope: this,
11310                 argument: {options: o},
11311                 timeout : this.timeout
11312             };
11313
11314             var method = o.method||this.method||(p ? "POST" : "GET");
11315
11316             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11317                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11318             }
11319
11320             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11321                 if(o.autoAbort){
11322                     this.abort();
11323                 }
11324             }else if(this.autoAbort !== false){
11325                 this.abort();
11326             }
11327
11328             if((method == 'GET' && p) || o.xmlData){
11329                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11330                 p = '';
11331             }
11332             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11333             return this.transId;
11334         }else{
11335             Roo.callback(o.callback, o.scope, [o, null, null]);
11336             return null;
11337         }
11338     },
11339
11340     /**
11341      * Determine whether this object has a request outstanding.
11342      * @param {Number} transactionId (Optional) defaults to the last transaction
11343      * @return {Boolean} True if there is an outstanding request.
11344      */
11345     isLoading : function(transId){
11346         if(transId){
11347             return Roo.lib.Ajax.isCallInProgress(transId);
11348         }else{
11349             return this.transId ? true : false;
11350         }
11351     },
11352
11353     /**
11354      * Aborts any outstanding request.
11355      * @param {Number} transactionId (Optional) defaults to the last transaction
11356      */
11357     abort : function(transId){
11358         if(transId || this.isLoading()){
11359             Roo.lib.Ajax.abort(transId || this.transId);
11360         }
11361     },
11362
11363     // private
11364     handleResponse : function(response){
11365         this.transId = false;
11366         var options = response.argument.options;
11367         response.argument = options ? options.argument : null;
11368         this.fireEvent("requestcomplete", this, response, options);
11369         Roo.callback(options.success, options.scope, [response, options]);
11370         Roo.callback(options.callback, options.scope, [options, true, response]);
11371     },
11372
11373     // private
11374     handleFailure : function(response, e){
11375         this.transId = false;
11376         var options = response.argument.options;
11377         response.argument = options ? options.argument : null;
11378         this.fireEvent("requestexception", this, response, options, e);
11379         Roo.callback(options.failure, options.scope, [response, options]);
11380         Roo.callback(options.callback, options.scope, [options, false, response]);
11381     },
11382
11383     // private
11384     doFormUpload : function(o, ps, url){
11385         var id = Roo.id();
11386         var frame = document.createElement('iframe');
11387         frame.id = id;
11388         frame.name = id;
11389         frame.className = 'x-hidden';
11390         if(Roo.isIE){
11391             frame.src = Roo.SSL_SECURE_URL;
11392         }
11393         document.body.appendChild(frame);
11394
11395         if(Roo.isIE){
11396            document.frames[id].name = id;
11397         }
11398
11399         var form = Roo.getDom(o.form);
11400         form.target = id;
11401         form.method = 'POST';
11402         form.enctype = form.encoding = 'multipart/form-data';
11403         if(url){
11404             form.action = url;
11405         }
11406
11407         var hiddens, hd;
11408         if(ps){ // add dynamic params
11409             hiddens = [];
11410             ps = Roo.urlDecode(ps, false);
11411             for(var k in ps){
11412                 if(ps.hasOwnProperty(k)){
11413                     hd = document.createElement('input');
11414                     hd.type = 'hidden';
11415                     hd.name = k;
11416                     hd.value = ps[k];
11417                     form.appendChild(hd);
11418                     hiddens.push(hd);
11419                 }
11420             }
11421         }
11422
11423         function cb(){
11424             var r = {  // bogus response object
11425                 responseText : '',
11426                 responseXML : null
11427             };
11428
11429             r.argument = o ? o.argument : null;
11430
11431             try { //
11432                 var doc;
11433                 if(Roo.isIE){
11434                     doc = frame.contentWindow.document;
11435                 }else {
11436                     doc = (frame.contentDocument || window.frames[id].document);
11437                 }
11438                 if(doc && doc.body){
11439                     r.responseText = doc.body.innerHTML;
11440                 }
11441                 if(doc && doc.XMLDocument){
11442                     r.responseXML = doc.XMLDocument;
11443                 }else {
11444                     r.responseXML = doc;
11445                 }
11446             }
11447             catch(e) {
11448                 // ignore
11449             }
11450
11451             Roo.EventManager.removeListener(frame, 'load', cb, this);
11452
11453             this.fireEvent("requestcomplete", this, r, o);
11454             Roo.callback(o.success, o.scope, [r, o]);
11455             Roo.callback(o.callback, o.scope, [o, true, r]);
11456
11457             setTimeout(function(){document.body.removeChild(frame);}, 100);
11458         }
11459
11460         Roo.EventManager.on(frame, 'load', cb, this);
11461         form.submit();
11462
11463         if(hiddens){ // remove dynamic params
11464             for(var i = 0, len = hiddens.length; i < len; i++){
11465                 form.removeChild(hiddens[i]);
11466             }
11467         }
11468     }
11469 });
11470
11471 /**
11472  * @class Roo.Ajax
11473  * @extends Roo.data.Connection
11474  * Global Ajax request class.
11475  *
11476  * @singleton
11477  */
11478 Roo.Ajax = new Roo.data.Connection({
11479     // fix up the docs
11480    /**
11481      * @cfg {String} url @hide
11482      */
11483     /**
11484      * @cfg {Object} extraParams @hide
11485      */
11486     /**
11487      * @cfg {Object} defaultHeaders @hide
11488      */
11489     /**
11490      * @cfg {String} method (Optional) @hide
11491      */
11492     /**
11493      * @cfg {Number} timeout (Optional) @hide
11494      */
11495     /**
11496      * @cfg {Boolean} autoAbort (Optional) @hide
11497      */
11498
11499     /**
11500      * @cfg {Boolean} disableCaching (Optional) @hide
11501      */
11502
11503     /**
11504      * @property  disableCaching
11505      * True to add a unique cache-buster param to GET requests. (defaults to true)
11506      * @type Boolean
11507      */
11508     /**
11509      * @property  url
11510      * The default URL to be used for requests to the server. (defaults to undefined)
11511      * @type String
11512      */
11513     /**
11514      * @property  extraParams
11515      * An object containing properties which are used as
11516      * extra parameters to each request made by this object. (defaults to undefined)
11517      * @type Object
11518      */
11519     /**
11520      * @property  defaultHeaders
11521      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11522      * @type Object
11523      */
11524     /**
11525      * @property  method
11526      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11527      * @type String
11528      */
11529     /**
11530      * @property  timeout
11531      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11532      * @type Number
11533      */
11534
11535     /**
11536      * @property  autoAbort
11537      * Whether a new request should abort any pending requests. (defaults to false)
11538      * @type Boolean
11539      */
11540     autoAbort : false,
11541
11542     /**
11543      * Serialize the passed form into a url encoded string
11544      * @param {String/HTMLElement} form
11545      * @return {String}
11546      */
11547     serializeForm : function(form){
11548         return Roo.lib.Ajax.serializeForm(form);
11549     }
11550 });/*
11551  * Based on:
11552  * Ext JS Library 1.1.1
11553  * Copyright(c) 2006-2007, Ext JS, LLC.
11554  *
11555  * Originally Released Under LGPL - original licence link has changed is not relivant.
11556  *
11557  * Fork - LGPL
11558  * <script type="text/javascript">
11559  */
11560  
11561 /**
11562  * Global Ajax request class.
11563  * 
11564  * @class Roo.Ajax
11565  * @extends Roo.data.Connection
11566  * @static
11567  * 
11568  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11569  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11570  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11571  * @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)
11572  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11573  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11574  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11575  */
11576 Roo.Ajax = new Roo.data.Connection({
11577     // fix up the docs
11578     /**
11579      * @scope Roo.Ajax
11580      * @type {Boolear} 
11581      */
11582     autoAbort : false,
11583
11584     /**
11585      * Serialize the passed form into a url encoded string
11586      * @scope Roo.Ajax
11587      * @param {String/HTMLElement} form
11588      * @return {String}
11589      */
11590     serializeForm : function(form){
11591         return Roo.lib.Ajax.serializeForm(form);
11592     }
11593 });/*
11594  * Based on:
11595  * Ext JS Library 1.1.1
11596  * Copyright(c) 2006-2007, Ext JS, LLC.
11597  *
11598  * Originally Released Under LGPL - original licence link has changed is not relivant.
11599  *
11600  * Fork - LGPL
11601  * <script type="text/javascript">
11602  */
11603
11604  
11605 /**
11606  * @class Roo.UpdateManager
11607  * @extends Roo.util.Observable
11608  * Provides AJAX-style update for Element object.<br><br>
11609  * Usage:<br>
11610  * <pre><code>
11611  * // Get it from a Roo.Element object
11612  * var el = Roo.get("foo");
11613  * var mgr = el.getUpdateManager();
11614  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11615  * ...
11616  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11617  * <br>
11618  * // or directly (returns the same UpdateManager instance)
11619  * var mgr = new Roo.UpdateManager("myElementId");
11620  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11621  * mgr.on("update", myFcnNeedsToKnow);
11622  * <br>
11623    // short handed call directly from the element object
11624    Roo.get("foo").load({
11625         url: "bar.php",
11626         scripts:true,
11627         params: "for=bar",
11628         text: "Loading Foo..."
11629    });
11630  * </code></pre>
11631  * @constructor
11632  * Create new UpdateManager directly.
11633  * @param {String/HTMLElement/Roo.Element} el The element to update
11634  * @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).
11635  */
11636 Roo.UpdateManager = function(el, forceNew){
11637     el = Roo.get(el);
11638     if(!forceNew && el.updateManager){
11639         return el.updateManager;
11640     }
11641     /**
11642      * The Element object
11643      * @type Roo.Element
11644      */
11645     this.el = el;
11646     /**
11647      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11648      * @type String
11649      */
11650     this.defaultUrl = null;
11651
11652     this.addEvents({
11653         /**
11654          * @event beforeupdate
11655          * Fired before an update is made, return false from your handler and the update is cancelled.
11656          * @param {Roo.Element} el
11657          * @param {String/Object/Function} url
11658          * @param {String/Object} params
11659          */
11660         "beforeupdate": true,
11661         /**
11662          * @event update
11663          * Fired after successful update is made.
11664          * @param {Roo.Element} el
11665          * @param {Object} oResponseObject The response Object
11666          */
11667         "update": true,
11668         /**
11669          * @event failure
11670          * Fired on update failure.
11671          * @param {Roo.Element} el
11672          * @param {Object} oResponseObject The response Object
11673          */
11674         "failure": true
11675     });
11676     var d = Roo.UpdateManager.defaults;
11677     /**
11678      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11679      * @type String
11680      */
11681     this.sslBlankUrl = d.sslBlankUrl;
11682     /**
11683      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11684      * @type Boolean
11685      */
11686     this.disableCaching = d.disableCaching;
11687     /**
11688      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11689      * @type String
11690      */
11691     this.indicatorText = d.indicatorText;
11692     /**
11693      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11694      * @type String
11695      */
11696     this.showLoadIndicator = d.showLoadIndicator;
11697     /**
11698      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11699      * @type Number
11700      */
11701     this.timeout = d.timeout;
11702
11703     /**
11704      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11705      * @type Boolean
11706      */
11707     this.loadScripts = d.loadScripts;
11708
11709     /**
11710      * Transaction object of current executing transaction
11711      */
11712     this.transaction = null;
11713
11714     /**
11715      * @private
11716      */
11717     this.autoRefreshProcId = null;
11718     /**
11719      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11720      * @type Function
11721      */
11722     this.refreshDelegate = this.refresh.createDelegate(this);
11723     /**
11724      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11725      * @type Function
11726      */
11727     this.updateDelegate = this.update.createDelegate(this);
11728     /**
11729      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11730      * @type Function
11731      */
11732     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11733     /**
11734      * @private
11735      */
11736     this.successDelegate = this.processSuccess.createDelegate(this);
11737     /**
11738      * @private
11739      */
11740     this.failureDelegate = this.processFailure.createDelegate(this);
11741
11742     if(!this.renderer){
11743      /**
11744       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11745       */
11746     this.renderer = new Roo.UpdateManager.BasicRenderer();
11747     }
11748     
11749     Roo.UpdateManager.superclass.constructor.call(this);
11750 };
11751
11752 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11753     /**
11754      * Get the Element this UpdateManager is bound to
11755      * @return {Roo.Element} The element
11756      */
11757     getEl : function(){
11758         return this.el;
11759     },
11760     /**
11761      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11762      * @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:
11763 <pre><code>
11764 um.update({<br/>
11765     url: "your-url.php",<br/>
11766     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11767     callback: yourFunction,<br/>
11768     scope: yourObject, //(optional scope)  <br/>
11769     discardUrl: false, <br/>
11770     nocache: false,<br/>
11771     text: "Loading...",<br/>
11772     timeout: 30,<br/>
11773     scripts: false<br/>
11774 });
11775 </code></pre>
11776      * The only required property is url. The optional properties nocache, text and scripts
11777      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11778      * @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}
11779      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11780      * @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.
11781      */
11782     update : function(url, params, callback, discardUrl){
11783         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11784             var method = this.method, cfg;
11785             if(typeof url == "object"){ // must be config object
11786                 cfg = url;
11787                 url = cfg.url;
11788                 params = params || cfg.params;
11789                 callback = callback || cfg.callback;
11790                 discardUrl = discardUrl || cfg.discardUrl;
11791                 if(callback && cfg.scope){
11792                     callback = callback.createDelegate(cfg.scope);
11793                 }
11794                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11795                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11796                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11797                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11798                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11799             }
11800             this.showLoading();
11801             if(!discardUrl){
11802                 this.defaultUrl = url;
11803             }
11804             if(typeof url == "function"){
11805                 url = url.call(this);
11806             }
11807
11808             method = method || (params ? "POST" : "GET");
11809             if(method == "GET"){
11810                 url = this.prepareUrl(url);
11811             }
11812
11813             var o = Roo.apply(cfg ||{}, {
11814                 url : url,
11815                 params: params,
11816                 success: this.successDelegate,
11817                 failure: this.failureDelegate,
11818                 callback: undefined,
11819                 timeout: (this.timeout*1000),
11820                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11821             });
11822
11823             this.transaction = Roo.Ajax.request(o);
11824         }
11825     },
11826
11827     /**
11828      * 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.
11829      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11830      * @param {String/HTMLElement} form The form Id or form element
11831      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11832      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11833      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11834      */
11835     formUpdate : function(form, url, reset, callback){
11836         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11837             if(typeof url == "function"){
11838                 url = url.call(this);
11839             }
11840             form = Roo.getDom(form);
11841             this.transaction = Roo.Ajax.request({
11842                 form: form,
11843                 url:url,
11844                 success: this.successDelegate,
11845                 failure: this.failureDelegate,
11846                 timeout: (this.timeout*1000),
11847                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11848             });
11849             this.showLoading.defer(1, this);
11850         }
11851     },
11852
11853     /**
11854      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11855      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11856      */
11857     refresh : function(callback){
11858         if(this.defaultUrl == null){
11859             return;
11860         }
11861         this.update(this.defaultUrl, null, callback, true);
11862     },
11863
11864     /**
11865      * Set this element to auto refresh.
11866      * @param {Number} interval How often to update (in seconds).
11867      * @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)
11868      * @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}
11869      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11870      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11871      */
11872     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11873         if(refreshNow){
11874             this.update(url || this.defaultUrl, params, callback, true);
11875         }
11876         if(this.autoRefreshProcId){
11877             clearInterval(this.autoRefreshProcId);
11878         }
11879         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11880     },
11881
11882     /**
11883      * Stop auto refresh on this element.
11884      */
11885      stopAutoRefresh : function(){
11886         if(this.autoRefreshProcId){
11887             clearInterval(this.autoRefreshProcId);
11888             delete this.autoRefreshProcId;
11889         }
11890     },
11891
11892     isAutoRefreshing : function(){
11893        return this.autoRefreshProcId ? true : false;
11894     },
11895     /**
11896      * Called to update the element to "Loading" state. Override to perform custom action.
11897      */
11898     showLoading : function(){
11899         if(this.showLoadIndicator){
11900             this.el.update(this.indicatorText);
11901         }
11902     },
11903
11904     /**
11905      * Adds unique parameter to query string if disableCaching = true
11906      * @private
11907      */
11908     prepareUrl : function(url){
11909         if(this.disableCaching){
11910             var append = "_dc=" + (new Date().getTime());
11911             if(url.indexOf("?") !== -1){
11912                 url += "&" + append;
11913             }else{
11914                 url += "?" + append;
11915             }
11916         }
11917         return url;
11918     },
11919
11920     /**
11921      * @private
11922      */
11923     processSuccess : function(response){
11924         this.transaction = null;
11925         if(response.argument.form && response.argument.reset){
11926             try{ // put in try/catch since some older FF releases had problems with this
11927                 response.argument.form.reset();
11928             }catch(e){}
11929         }
11930         if(this.loadScripts){
11931             this.renderer.render(this.el, response, this,
11932                 this.updateComplete.createDelegate(this, [response]));
11933         }else{
11934             this.renderer.render(this.el, response, this);
11935             this.updateComplete(response);
11936         }
11937     },
11938
11939     updateComplete : function(response){
11940         this.fireEvent("update", this.el, response);
11941         if(typeof response.argument.callback == "function"){
11942             response.argument.callback(this.el, true, response);
11943         }
11944     },
11945
11946     /**
11947      * @private
11948      */
11949     processFailure : function(response){
11950         this.transaction = null;
11951         this.fireEvent("failure", this.el, response);
11952         if(typeof response.argument.callback == "function"){
11953             response.argument.callback(this.el, false, response);
11954         }
11955     },
11956
11957     /**
11958      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11959      * @param {Object} renderer The object implementing the render() method
11960      */
11961     setRenderer : function(renderer){
11962         this.renderer = renderer;
11963     },
11964
11965     getRenderer : function(){
11966        return this.renderer;
11967     },
11968
11969     /**
11970      * Set the defaultUrl used for updates
11971      * @param {String/Function} defaultUrl The url or a function to call to get the url
11972      */
11973     setDefaultUrl : function(defaultUrl){
11974         this.defaultUrl = defaultUrl;
11975     },
11976
11977     /**
11978      * Aborts the executing transaction
11979      */
11980     abort : function(){
11981         if(this.transaction){
11982             Roo.Ajax.abort(this.transaction);
11983         }
11984     },
11985
11986     /**
11987      * Returns true if an update is in progress
11988      * @return {Boolean}
11989      */
11990     isUpdating : function(){
11991         if(this.transaction){
11992             return Roo.Ajax.isLoading(this.transaction);
11993         }
11994         return false;
11995     }
11996 });
11997
11998 /**
11999  * @class Roo.UpdateManager.defaults
12000  * @static (not really - but it helps the doc tool)
12001  * The defaults collection enables customizing the default properties of UpdateManager
12002  */
12003    Roo.UpdateManager.defaults = {
12004        /**
12005          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12006          * @type Number
12007          */
12008          timeout : 30,
12009
12010          /**
12011          * True to process scripts by default (Defaults to false).
12012          * @type Boolean
12013          */
12014         loadScripts : false,
12015
12016         /**
12017         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12018         * @type String
12019         */
12020         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12021         /**
12022          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12023          * @type Boolean
12024          */
12025         disableCaching : false,
12026         /**
12027          * Whether to show indicatorText when loading (Defaults to true).
12028          * @type Boolean
12029          */
12030         showLoadIndicator : true,
12031         /**
12032          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12033          * @type String
12034          */
12035         indicatorText : '<div class="loading-indicator">Loading...</div>'
12036    };
12037
12038 /**
12039  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12040  *Usage:
12041  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12042  * @param {String/HTMLElement/Roo.Element} el The element to update
12043  * @param {String} url The url
12044  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12045  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12046  * @static
12047  * @deprecated
12048  * @member Roo.UpdateManager
12049  */
12050 Roo.UpdateManager.updateElement = function(el, url, params, options){
12051     var um = Roo.get(el, true).getUpdateManager();
12052     Roo.apply(um, options);
12053     um.update(url, params, options ? options.callback : null);
12054 };
12055 // alias for backwards compat
12056 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12057 /**
12058  * @class Roo.UpdateManager.BasicRenderer
12059  * Default Content renderer. Updates the elements innerHTML with the responseText.
12060  */
12061 Roo.UpdateManager.BasicRenderer = function(){};
12062
12063 Roo.UpdateManager.BasicRenderer.prototype = {
12064     /**
12065      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12066      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12067      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12068      * @param {Roo.Element} el The element being rendered
12069      * @param {Object} response The YUI Connect response object
12070      * @param {UpdateManager} updateManager The calling update manager
12071      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12072      */
12073      render : function(el, response, updateManager, callback){
12074         el.update(response.responseText, updateManager.loadScripts, callback);
12075     }
12076 };
12077 /*
12078  * Based on:
12079  * Ext JS Library 1.1.1
12080  * Copyright(c) 2006-2007, Ext JS, LLC.
12081  *
12082  * Originally Released Under LGPL - original licence link has changed is not relivant.
12083  *
12084  * Fork - LGPL
12085  * <script type="text/javascript">
12086  */
12087
12088 /**
12089  * @class Roo.util.DelayedTask
12090  * Provides a convenient method of performing setTimeout where a new
12091  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12092  * You can use this class to buffer
12093  * the keypress events for a certain number of milliseconds, and perform only if they stop
12094  * for that amount of time.
12095  * @constructor The parameters to this constructor serve as defaults and are not required.
12096  * @param {Function} fn (optional) The default function to timeout
12097  * @param {Object} scope (optional) The default scope of that timeout
12098  * @param {Array} args (optional) The default Array of arguments
12099  */
12100 Roo.util.DelayedTask = function(fn, scope, args){
12101     var id = null, d, t;
12102
12103     var call = function(){
12104         var now = new Date().getTime();
12105         if(now - t >= d){
12106             clearInterval(id);
12107             id = null;
12108             fn.apply(scope, args || []);
12109         }
12110     };
12111     /**
12112      * Cancels any pending timeout and queues a new one
12113      * @param {Number} delay The milliseconds to delay
12114      * @param {Function} newFn (optional) Overrides function passed to constructor
12115      * @param {Object} newScope (optional) Overrides scope passed to constructor
12116      * @param {Array} newArgs (optional) Overrides args passed to constructor
12117      */
12118     this.delay = function(delay, newFn, newScope, newArgs){
12119         if(id && delay != d){
12120             this.cancel();
12121         }
12122         d = delay;
12123         t = new Date().getTime();
12124         fn = newFn || fn;
12125         scope = newScope || scope;
12126         args = newArgs || args;
12127         if(!id){
12128             id = setInterval(call, d);
12129         }
12130     };
12131
12132     /**
12133      * Cancel the last queued timeout
12134      */
12135     this.cancel = function(){
12136         if(id){
12137             clearInterval(id);
12138             id = null;
12139         }
12140     };
12141 };/*
12142  * Based on:
12143  * Ext JS Library 1.1.1
12144  * Copyright(c) 2006-2007, Ext JS, LLC.
12145  *
12146  * Originally Released Under LGPL - original licence link has changed is not relivant.
12147  *
12148  * Fork - LGPL
12149  * <script type="text/javascript">
12150  */
12151  
12152  
12153 Roo.util.TaskRunner = function(interval){
12154     interval = interval || 10;
12155     var tasks = [], removeQueue = [];
12156     var id = 0;
12157     var running = false;
12158
12159     var stopThread = function(){
12160         running = false;
12161         clearInterval(id);
12162         id = 0;
12163     };
12164
12165     var startThread = function(){
12166         if(!running){
12167             running = true;
12168             id = setInterval(runTasks, interval);
12169         }
12170     };
12171
12172     var removeTask = function(task){
12173         removeQueue.push(task);
12174         if(task.onStop){
12175             task.onStop();
12176         }
12177     };
12178
12179     var runTasks = function(){
12180         if(removeQueue.length > 0){
12181             for(var i = 0, len = removeQueue.length; i < len; i++){
12182                 tasks.remove(removeQueue[i]);
12183             }
12184             removeQueue = [];
12185             if(tasks.length < 1){
12186                 stopThread();
12187                 return;
12188             }
12189         }
12190         var now = new Date().getTime();
12191         for(var i = 0, len = tasks.length; i < len; ++i){
12192             var t = tasks[i];
12193             var itime = now - t.taskRunTime;
12194             if(t.interval <= itime){
12195                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12196                 t.taskRunTime = now;
12197                 if(rt === false || t.taskRunCount === t.repeat){
12198                     removeTask(t);
12199                     return;
12200                 }
12201             }
12202             if(t.duration && t.duration <= (now - t.taskStartTime)){
12203                 removeTask(t);
12204             }
12205         }
12206     };
12207
12208     /**
12209      * Queues a new task.
12210      * @param {Object} task
12211      */
12212     this.start = function(task){
12213         tasks.push(task);
12214         task.taskStartTime = new Date().getTime();
12215         task.taskRunTime = 0;
12216         task.taskRunCount = 0;
12217         startThread();
12218         return task;
12219     };
12220
12221     this.stop = function(task){
12222         removeTask(task);
12223         return task;
12224     };
12225
12226     this.stopAll = function(){
12227         stopThread();
12228         for(var i = 0, len = tasks.length; i < len; i++){
12229             if(tasks[i].onStop){
12230                 tasks[i].onStop();
12231             }
12232         }
12233         tasks = [];
12234         removeQueue = [];
12235     };
12236 };
12237
12238 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12239  * Based on:
12240  * Ext JS Library 1.1.1
12241  * Copyright(c) 2006-2007, Ext JS, LLC.
12242  *
12243  * Originally Released Under LGPL - original licence link has changed is not relivant.
12244  *
12245  * Fork - LGPL
12246  * <script type="text/javascript">
12247  */
12248
12249  
12250 /**
12251  * @class Roo.util.MixedCollection
12252  * @extends Roo.util.Observable
12253  * A Collection class that maintains both numeric indexes and keys and exposes events.
12254  * @constructor
12255  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12256  * collection (defaults to false)
12257  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12258  * and return the key value for that item.  This is used when available to look up the key on items that
12259  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12260  * equivalent to providing an implementation for the {@link #getKey} method.
12261  */
12262 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12263     this.items = [];
12264     this.map = {};
12265     this.keys = [];
12266     this.length = 0;
12267     this.addEvents({
12268         /**
12269          * @event clear
12270          * Fires when the collection is cleared.
12271          */
12272         "clear" : true,
12273         /**
12274          * @event add
12275          * Fires when an item is added to the collection.
12276          * @param {Number} index The index at which the item was added.
12277          * @param {Object} o The item added.
12278          * @param {String} key The key associated with the added item.
12279          */
12280         "add" : true,
12281         /**
12282          * @event replace
12283          * Fires when an item is replaced in the collection.
12284          * @param {String} key he key associated with the new added.
12285          * @param {Object} old The item being replaced.
12286          * @param {Object} new The new item.
12287          */
12288         "replace" : true,
12289         /**
12290          * @event remove
12291          * Fires when an item is removed from the collection.
12292          * @param {Object} o The item being removed.
12293          * @param {String} key (optional) The key associated with the removed item.
12294          */
12295         "remove" : true,
12296         "sort" : true
12297     });
12298     this.allowFunctions = allowFunctions === true;
12299     if(keyFn){
12300         this.getKey = keyFn;
12301     }
12302     Roo.util.MixedCollection.superclass.constructor.call(this);
12303 };
12304
12305 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12306     allowFunctions : false,
12307     
12308 /**
12309  * Adds an item to the collection.
12310  * @param {String} key The key to associate with the item
12311  * @param {Object} o The item to add.
12312  * @return {Object} The item added.
12313  */
12314     add : function(key, o){
12315         if(arguments.length == 1){
12316             o = arguments[0];
12317             key = this.getKey(o);
12318         }
12319         if(typeof key == "undefined" || key === null){
12320             this.length++;
12321             this.items.push(o);
12322             this.keys.push(null);
12323         }else{
12324             var old = this.map[key];
12325             if(old){
12326                 return this.replace(key, o);
12327             }
12328             this.length++;
12329             this.items.push(o);
12330             this.map[key] = o;
12331             this.keys.push(key);
12332         }
12333         this.fireEvent("add", this.length-1, o, key);
12334         return o;
12335     },
12336        
12337 /**
12338   * MixedCollection has a generic way to fetch keys if you implement getKey.
12339 <pre><code>
12340 // normal way
12341 var mc = new Roo.util.MixedCollection();
12342 mc.add(someEl.dom.id, someEl);
12343 mc.add(otherEl.dom.id, otherEl);
12344 //and so on
12345
12346 // using getKey
12347 var mc = new Roo.util.MixedCollection();
12348 mc.getKey = function(el){
12349    return el.dom.id;
12350 };
12351 mc.add(someEl);
12352 mc.add(otherEl);
12353
12354 // or via the constructor
12355 var mc = new Roo.util.MixedCollection(false, function(el){
12356    return el.dom.id;
12357 });
12358 mc.add(someEl);
12359 mc.add(otherEl);
12360 </code></pre>
12361  * @param o {Object} The item for which to find the key.
12362  * @return {Object} The key for the passed item.
12363  */
12364     getKey : function(o){
12365          return o.id; 
12366     },
12367    
12368 /**
12369  * Replaces an item in the collection.
12370  * @param {String} key The key associated with the item to replace, or the item to replace.
12371  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12372  * @return {Object}  The new item.
12373  */
12374     replace : function(key, o){
12375         if(arguments.length == 1){
12376             o = arguments[0];
12377             key = this.getKey(o);
12378         }
12379         var old = this.item(key);
12380         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12381              return this.add(key, o);
12382         }
12383         var index = this.indexOfKey(key);
12384         this.items[index] = o;
12385         this.map[key] = o;
12386         this.fireEvent("replace", key, old, o);
12387         return o;
12388     },
12389    
12390 /**
12391  * Adds all elements of an Array or an Object to the collection.
12392  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12393  * an Array of values, each of which are added to the collection.
12394  */
12395     addAll : function(objs){
12396         if(arguments.length > 1 || objs instanceof Array){
12397             var args = arguments.length > 1 ? arguments : objs;
12398             for(var i = 0, len = args.length; i < len; i++){
12399                 this.add(args[i]);
12400             }
12401         }else{
12402             for(var key in objs){
12403                 if(this.allowFunctions || typeof objs[key] != "function"){
12404                     this.add(key, objs[key]);
12405                 }
12406             }
12407         }
12408     },
12409    
12410 /**
12411  * Executes the specified function once for every item in the collection, passing each
12412  * item as the first and only parameter. returning false from the function will stop the iteration.
12413  * @param {Function} fn The function to execute for each item.
12414  * @param {Object} scope (optional) The scope in which to execute the function.
12415  */
12416     each : function(fn, scope){
12417         var items = [].concat(this.items); // each safe for removal
12418         for(var i = 0, len = items.length; i < len; i++){
12419             if(fn.call(scope || items[i], items[i], i, len) === false){
12420                 break;
12421             }
12422         }
12423     },
12424    
12425 /**
12426  * Executes the specified function once for every key in the collection, passing each
12427  * key, and its associated item as the first two parameters.
12428  * @param {Function} fn The function to execute for each item.
12429  * @param {Object} scope (optional) The scope in which to execute the function.
12430  */
12431     eachKey : function(fn, scope){
12432         for(var i = 0, len = this.keys.length; i < len; i++){
12433             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12434         }
12435     },
12436    
12437 /**
12438  * Returns the first item in the collection which elicits a true return value from the
12439  * passed selection function.
12440  * @param {Function} fn The selection function to execute for each item.
12441  * @param {Object} scope (optional) The scope in which to execute the function.
12442  * @return {Object} The first item in the collection which returned true from the selection function.
12443  */
12444     find : function(fn, scope){
12445         for(var i = 0, len = this.items.length; i < len; i++){
12446             if(fn.call(scope || window, this.items[i], this.keys[i])){
12447                 return this.items[i];
12448             }
12449         }
12450         return null;
12451     },
12452    
12453 /**
12454  * Inserts an item at the specified index in the collection.
12455  * @param {Number} index The index to insert the item at.
12456  * @param {String} key The key to associate with the new item, or the item itself.
12457  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12458  * @return {Object} The item inserted.
12459  */
12460     insert : function(index, key, o){
12461         if(arguments.length == 2){
12462             o = arguments[1];
12463             key = this.getKey(o);
12464         }
12465         if(index >= this.length){
12466             return this.add(key, o);
12467         }
12468         this.length++;
12469         this.items.splice(index, 0, o);
12470         if(typeof key != "undefined" && key != null){
12471             this.map[key] = o;
12472         }
12473         this.keys.splice(index, 0, key);
12474         this.fireEvent("add", index, o, key);
12475         return o;
12476     },
12477    
12478 /**
12479  * Removed an item from the collection.
12480  * @param {Object} o The item to remove.
12481  * @return {Object} The item removed.
12482  */
12483     remove : function(o){
12484         return this.removeAt(this.indexOf(o));
12485     },
12486    
12487 /**
12488  * Remove an item from a specified index in the collection.
12489  * @param {Number} index The index within the collection of the item to remove.
12490  */
12491     removeAt : function(index){
12492         if(index < this.length && index >= 0){
12493             this.length--;
12494             var o = this.items[index];
12495             this.items.splice(index, 1);
12496             var key = this.keys[index];
12497             if(typeof key != "undefined"){
12498                 delete this.map[key];
12499             }
12500             this.keys.splice(index, 1);
12501             this.fireEvent("remove", o, key);
12502         }
12503     },
12504    
12505 /**
12506  * Removed an item associated with the passed key fom the collection.
12507  * @param {String} key The key of the item to remove.
12508  */
12509     removeKey : function(key){
12510         return this.removeAt(this.indexOfKey(key));
12511     },
12512    
12513 /**
12514  * Returns the number of items in the collection.
12515  * @return {Number} the number of items in the collection.
12516  */
12517     getCount : function(){
12518         return this.length; 
12519     },
12520    
12521 /**
12522  * Returns index within the collection of the passed Object.
12523  * @param {Object} o The item to find the index of.
12524  * @return {Number} index of the item.
12525  */
12526     indexOf : function(o){
12527         if(!this.items.indexOf){
12528             for(var i = 0, len = this.items.length; i < len; i++){
12529                 if(this.items[i] == o) return i;
12530             }
12531             return -1;
12532         }else{
12533             return this.items.indexOf(o);
12534         }
12535     },
12536    
12537 /**
12538  * Returns index within the collection of the passed key.
12539  * @param {String} key The key to find the index of.
12540  * @return {Number} index of the key.
12541  */
12542     indexOfKey : function(key){
12543         if(!this.keys.indexOf){
12544             for(var i = 0, len = this.keys.length; i < len; i++){
12545                 if(this.keys[i] == key) return i;
12546             }
12547             return -1;
12548         }else{
12549             return this.keys.indexOf(key);
12550         }
12551     },
12552    
12553 /**
12554  * Returns the item associated with the passed key OR index. Key has priority over index.
12555  * @param {String/Number} key The key or index of the item.
12556  * @return {Object} The item associated with the passed key.
12557  */
12558     item : function(key){
12559         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12560         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12561     },
12562     
12563 /**
12564  * Returns the item at the specified index.
12565  * @param {Number} index The index of the item.
12566  * @return {Object}
12567  */
12568     itemAt : function(index){
12569         return this.items[index];
12570     },
12571     
12572 /**
12573  * Returns the item associated with the passed key.
12574  * @param {String/Number} key The key of the item.
12575  * @return {Object} The item associated with the passed key.
12576  */
12577     key : function(key){
12578         return this.map[key];
12579     },
12580    
12581 /**
12582  * Returns true if the collection contains the passed Object as an item.
12583  * @param {Object} o  The Object to look for in the collection.
12584  * @return {Boolean} True if the collection contains the Object as an item.
12585  */
12586     contains : function(o){
12587         return this.indexOf(o) != -1;
12588     },
12589    
12590 /**
12591  * Returns true if the collection contains the passed Object as a key.
12592  * @param {String} key The key to look for in the collection.
12593  * @return {Boolean} True if the collection contains the Object as a key.
12594  */
12595     containsKey : function(key){
12596         return typeof this.map[key] != "undefined";
12597     },
12598    
12599 /**
12600  * Removes all items from the collection.
12601  */
12602     clear : function(){
12603         this.length = 0;
12604         this.items = [];
12605         this.keys = [];
12606         this.map = {};
12607         this.fireEvent("clear");
12608     },
12609    
12610 /**
12611  * Returns the first item in the collection.
12612  * @return {Object} the first item in the collection..
12613  */
12614     first : function(){
12615         return this.items[0]; 
12616     },
12617    
12618 /**
12619  * Returns the last item in the collection.
12620  * @return {Object} the last item in the collection..
12621  */
12622     last : function(){
12623         return this.items[this.length-1];   
12624     },
12625     
12626     _sort : function(property, dir, fn){
12627         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12628         fn = fn || function(a, b){
12629             return a-b;
12630         };
12631         var c = [], k = this.keys, items = this.items;
12632         for(var i = 0, len = items.length; i < len; i++){
12633             c[c.length] = {key: k[i], value: items[i], index: i};
12634         }
12635         c.sort(function(a, b){
12636             var v = fn(a[property], b[property]) * dsc;
12637             if(v == 0){
12638                 v = (a.index < b.index ? -1 : 1);
12639             }
12640             return v;
12641         });
12642         for(var i = 0, len = c.length; i < len; i++){
12643             items[i] = c[i].value;
12644             k[i] = c[i].key;
12645         }
12646         this.fireEvent("sort", this);
12647     },
12648     
12649     /**
12650      * Sorts this collection with the passed comparison function
12651      * @param {String} direction (optional) "ASC" or "DESC"
12652      * @param {Function} fn (optional) comparison function
12653      */
12654     sort : function(dir, fn){
12655         this._sort("value", dir, fn);
12656     },
12657     
12658     /**
12659      * Sorts this collection by keys
12660      * @param {String} direction (optional) "ASC" or "DESC"
12661      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12662      */
12663     keySort : function(dir, fn){
12664         this._sort("key", dir, fn || function(a, b){
12665             return String(a).toUpperCase()-String(b).toUpperCase();
12666         });
12667     },
12668     
12669     /**
12670      * Returns a range of items in this collection
12671      * @param {Number} startIndex (optional) defaults to 0
12672      * @param {Number} endIndex (optional) default to the last item
12673      * @return {Array} An array of items
12674      */
12675     getRange : function(start, end){
12676         var items = this.items;
12677         if(items.length < 1){
12678             return [];
12679         }
12680         start = start || 0;
12681         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12682         var r = [];
12683         if(start <= end){
12684             for(var i = start; i <= end; i++) {
12685                     r[r.length] = items[i];
12686             }
12687         }else{
12688             for(var i = start; i >= end; i--) {
12689                     r[r.length] = items[i];
12690             }
12691         }
12692         return r;
12693     },
12694         
12695     /**
12696      * Filter the <i>objects</i> in this collection by a specific property. 
12697      * Returns a new collection that has been filtered.
12698      * @param {String} property A property on your objects
12699      * @param {String/RegExp} value Either string that the property values 
12700      * should start with or a RegExp to test against the property
12701      * @return {MixedCollection} The new filtered collection
12702      */
12703     filter : function(property, value){
12704         if(!value.exec){ // not a regex
12705             value = String(value);
12706             if(value.length == 0){
12707                 return this.clone();
12708             }
12709             value = new RegExp("^" + Roo.escapeRe(value), "i");
12710         }
12711         return this.filterBy(function(o){
12712             return o && value.test(o[property]);
12713         });
12714         },
12715     
12716     /**
12717      * Filter by a function. * Returns a new collection that has been filtered.
12718      * The passed function will be called with each 
12719      * object in the collection. If the function returns true, the value is included 
12720      * otherwise it is filtered.
12721      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12722      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12723      * @return {MixedCollection} The new filtered collection
12724      */
12725     filterBy : function(fn, scope){
12726         var r = new Roo.util.MixedCollection();
12727         r.getKey = this.getKey;
12728         var k = this.keys, it = this.items;
12729         for(var i = 0, len = it.length; i < len; i++){
12730             if(fn.call(scope||this, it[i], k[i])){
12731                                 r.add(k[i], it[i]);
12732                         }
12733         }
12734         return r;
12735     },
12736     
12737     /**
12738      * Creates a duplicate of this collection
12739      * @return {MixedCollection}
12740      */
12741     clone : function(){
12742         var r = new Roo.util.MixedCollection();
12743         var k = this.keys, it = this.items;
12744         for(var i = 0, len = it.length; i < len; i++){
12745             r.add(k[i], it[i]);
12746         }
12747         r.getKey = this.getKey;
12748         return r;
12749     }
12750 });
12751 /**
12752  * Returns the item associated with the passed key or index.
12753  * @method
12754  * @param {String/Number} key The key or index of the item.
12755  * @return {Object} The item associated with the passed key.
12756  */
12757 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12758  * Based on:
12759  * Ext JS Library 1.1.1
12760  * Copyright(c) 2006-2007, Ext JS, LLC.
12761  *
12762  * Originally Released Under LGPL - original licence link has changed is not relivant.
12763  *
12764  * Fork - LGPL
12765  * <script type="text/javascript">
12766  */
12767 /**
12768  * @class Roo.util.JSON
12769  * Modified version of Douglas Crockford"s json.js that doesn"t
12770  * mess with the Object prototype 
12771  * http://www.json.org/js.html
12772  * @singleton
12773  */
12774 Roo.util.JSON = new (function(){
12775     var useHasOwn = {}.hasOwnProperty ? true : false;
12776     
12777     // crashes Safari in some instances
12778     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12779     
12780     var pad = function(n) {
12781         return n < 10 ? "0" + n : n;
12782     };
12783     
12784     var m = {
12785         "\b": '\\b',
12786         "\t": '\\t',
12787         "\n": '\\n',
12788         "\f": '\\f',
12789         "\r": '\\r',
12790         '"' : '\\"',
12791         "\\": '\\\\'
12792     };
12793
12794     var encodeString = function(s){
12795         if (/["\\\x00-\x1f]/.test(s)) {
12796             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12797                 var c = m[b];
12798                 if(c){
12799                     return c;
12800                 }
12801                 c = b.charCodeAt();
12802                 return "\\u00" +
12803                     Math.floor(c / 16).toString(16) +
12804                     (c % 16).toString(16);
12805             }) + '"';
12806         }
12807         return '"' + s + '"';
12808     };
12809     
12810     var encodeArray = function(o){
12811         var a = ["["], b, i, l = o.length, v;
12812             for (i = 0; i < l; i += 1) {
12813                 v = o[i];
12814                 switch (typeof v) {
12815                     case "undefined":
12816                     case "function":
12817                     case "unknown":
12818                         break;
12819                     default:
12820                         if (b) {
12821                             a.push(',');
12822                         }
12823                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12824                         b = true;
12825                 }
12826             }
12827             a.push("]");
12828             return a.join("");
12829     };
12830     
12831     var encodeDate = function(o){
12832         return '"' + o.getFullYear() + "-" +
12833                 pad(o.getMonth() + 1) + "-" +
12834                 pad(o.getDate()) + "T" +
12835                 pad(o.getHours()) + ":" +
12836                 pad(o.getMinutes()) + ":" +
12837                 pad(o.getSeconds()) + '"';
12838     };
12839     
12840     /**
12841      * Encodes an Object, Array or other value
12842      * @param {Mixed} o The variable to encode
12843      * @return {String} The JSON string
12844      */
12845     this.encode = function(o)
12846     {
12847         // should this be extended to fully wrap stringify..
12848         
12849         if(typeof o == "undefined" || o === null){
12850             return "null";
12851         }else if(o instanceof Array){
12852             return encodeArray(o);
12853         }else if(o instanceof Date){
12854             return encodeDate(o);
12855         }else if(typeof o == "string"){
12856             return encodeString(o);
12857         }else if(typeof o == "number"){
12858             return isFinite(o) ? String(o) : "null";
12859         }else if(typeof o == "boolean"){
12860             return String(o);
12861         }else {
12862             var a = ["{"], b, i, v;
12863             for (i in o) {
12864                 if(!useHasOwn || o.hasOwnProperty(i)) {
12865                     v = o[i];
12866                     switch (typeof v) {
12867                     case "undefined":
12868                     case "function":
12869                     case "unknown":
12870                         break;
12871                     default:
12872                         if(b){
12873                             a.push(',');
12874                         }
12875                         a.push(this.encode(i), ":",
12876                                 v === null ? "null" : this.encode(v));
12877                         b = true;
12878                     }
12879                 }
12880             }
12881             a.push("}");
12882             return a.join("");
12883         }
12884     };
12885     
12886     /**
12887      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12888      * @param {String} json The JSON string
12889      * @return {Object} The resulting object
12890      */
12891     this.decode = function(json){
12892         
12893         return  /** eval:var:json */ eval("(" + json + ')');
12894     };
12895 })();
12896 /** 
12897  * Shorthand for {@link Roo.util.JSON#encode}
12898  * @member Roo encode 
12899  * @method */
12900 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12901 /** 
12902  * Shorthand for {@link Roo.util.JSON#decode}
12903  * @member Roo decode 
12904  * @method */
12905 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12906 /*
12907  * Based on:
12908  * Ext JS Library 1.1.1
12909  * Copyright(c) 2006-2007, Ext JS, LLC.
12910  *
12911  * Originally Released Under LGPL - original licence link has changed is not relivant.
12912  *
12913  * Fork - LGPL
12914  * <script type="text/javascript">
12915  */
12916  
12917 /**
12918  * @class Roo.util.Format
12919  * Reusable data formatting functions
12920  * @singleton
12921  */
12922 Roo.util.Format = function(){
12923     var trimRe = /^\s+|\s+$/g;
12924     return {
12925         /**
12926          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12927          * @param {String} value The string to truncate
12928          * @param {Number} length The maximum length to allow before truncating
12929          * @return {String} The converted text
12930          */
12931         ellipsis : function(value, len){
12932             if(value && value.length > len){
12933                 return value.substr(0, len-3)+"...";
12934             }
12935             return value;
12936         },
12937
12938         /**
12939          * Checks a reference and converts it to empty string if it is undefined
12940          * @param {Mixed} value Reference to check
12941          * @return {Mixed} Empty string if converted, otherwise the original value
12942          */
12943         undef : function(value){
12944             return typeof value != "undefined" ? value : "";
12945         },
12946
12947         /**
12948          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12949          * @param {String} value The string to encode
12950          * @return {String} The encoded text
12951          */
12952         htmlEncode : function(value){
12953             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12954         },
12955
12956         /**
12957          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12958          * @param {String} value The string to decode
12959          * @return {String} The decoded text
12960          */
12961         htmlDecode : function(value){
12962             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12963         },
12964
12965         /**
12966          * Trims any whitespace from either side of a string
12967          * @param {String} value The text to trim
12968          * @return {String} The trimmed text
12969          */
12970         trim : function(value){
12971             return String(value).replace(trimRe, "");
12972         },
12973
12974         /**
12975          * Returns a substring from within an original string
12976          * @param {String} value The original text
12977          * @param {Number} start The start index of the substring
12978          * @param {Number} length The length of the substring
12979          * @return {String} The substring
12980          */
12981         substr : function(value, start, length){
12982             return String(value).substr(start, length);
12983         },
12984
12985         /**
12986          * Converts a string to all lower case letters
12987          * @param {String} value The text to convert
12988          * @return {String} The converted text
12989          */
12990         lowercase : function(value){
12991             return String(value).toLowerCase();
12992         },
12993
12994         /**
12995          * Converts a string to all upper case letters
12996          * @param {String} value The text to convert
12997          * @return {String} The converted text
12998          */
12999         uppercase : function(value){
13000             return String(value).toUpperCase();
13001         },
13002
13003         /**
13004          * Converts the first character only of a string to upper case
13005          * @param {String} value The text to convert
13006          * @return {String} The converted text
13007          */
13008         capitalize : function(value){
13009             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13010         },
13011
13012         // private
13013         call : function(value, fn){
13014             if(arguments.length > 2){
13015                 var args = Array.prototype.slice.call(arguments, 2);
13016                 args.unshift(value);
13017                  
13018                 return /** eval:var:value */  eval(fn).apply(window, args);
13019             }else{
13020                 /** eval:var:value */
13021                 return /** eval:var:value */ eval(fn).call(window, value);
13022             }
13023         },
13024
13025        
13026         /**
13027          * safer version of Math.toFixed..??/
13028          * @param {Number/String} value The numeric value to format
13029          * @param {Number/String} value Decimal places 
13030          * @return {String} The formatted currency string
13031          */
13032         toFixed : function(v, n)
13033         {
13034             // why not use to fixed - precision is buggered???
13035             if (!n) {
13036                 return Math.round(v-0);
13037             }
13038             var fact = Math.pow(10,n+1);
13039             v = (Math.round((v-0)*fact))/fact;
13040             var z = (''+fact).substring(2);
13041             if (v == Math.floor(v)) {
13042                 return Math.floor(v) + '.' + z;
13043             }
13044             
13045             // now just padd decimals..
13046             var ps = String(v).split('.');
13047             var fd = (ps[1] + z);
13048             var r = fd.substring(0,n); 
13049             var rm = fd.substring(n); 
13050             if (rm < 5) {
13051                 return ps[0] + '.' + r;
13052             }
13053             r*=1; // turn it into a number;
13054             r++;
13055             if (String(r).length != n) {
13056                 ps[0]*=1;
13057                 ps[0]++;
13058                 r = String(r).substring(1); // chop the end off.
13059             }
13060             
13061             return ps[0] + '.' + r;
13062              
13063         },
13064         
13065         /**
13066          * Format a number as US currency
13067          * @param {Number/String} value The numeric value to format
13068          * @return {String} The formatted currency string
13069          */
13070         usMoney : function(v){
13071             v = (Math.round((v-0)*100))/100;
13072             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13073             v = String(v);
13074             var ps = v.split('.');
13075             var whole = ps[0];
13076             var sub = ps[1] ? '.'+ ps[1] : '.00';
13077             var r = /(\d+)(\d{3})/;
13078             while (r.test(whole)) {
13079                 whole = whole.replace(r, '$1' + ',' + '$2');
13080             }
13081             return "$" + whole + sub ;
13082         },
13083         
13084         /**
13085          * Parse a value into a formatted date using the specified format pattern.
13086          * @param {Mixed} value The value to format
13087          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13088          * @return {String} The formatted date string
13089          */
13090         date : function(v, format){
13091             if(!v){
13092                 return "";
13093             }
13094             if(!(v instanceof Date)){
13095                 v = new Date(Date.parse(v));
13096             }
13097             return v.dateFormat(format || "m/d/Y");
13098         },
13099
13100         /**
13101          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13102          * @param {String} format Any valid date format string
13103          * @return {Function} The date formatting function
13104          */
13105         dateRenderer : function(format){
13106             return function(v){
13107                 return Roo.util.Format.date(v, format);  
13108             };
13109         },
13110
13111         // private
13112         stripTagsRE : /<\/?[^>]+>/gi,
13113         
13114         /**
13115          * Strips all HTML tags
13116          * @param {Mixed} value The text from which to strip tags
13117          * @return {String} The stripped text
13118          */
13119         stripTags : function(v){
13120             return !v ? v : String(v).replace(this.stripTagsRE, "");
13121         }
13122     };
13123 }();/*
13124  * Based on:
13125  * Ext JS Library 1.1.1
13126  * Copyright(c) 2006-2007, Ext JS, LLC.
13127  *
13128  * Originally Released Under LGPL - original licence link has changed is not relivant.
13129  *
13130  * Fork - LGPL
13131  * <script type="text/javascript">
13132  */
13133
13134
13135  
13136
13137 /**
13138  * @class Roo.MasterTemplate
13139  * @extends Roo.Template
13140  * Provides a template that can have child templates. The syntax is:
13141 <pre><code>
13142 var t = new Roo.MasterTemplate(
13143         '&lt;select name="{name}"&gt;',
13144                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13145         '&lt;/select&gt;'
13146 );
13147 t.add('options', {value: 'foo', text: 'bar'});
13148 // or you can add multiple child elements in one shot
13149 t.addAll('options', [
13150     {value: 'foo', text: 'bar'},
13151     {value: 'foo2', text: 'bar2'},
13152     {value: 'foo3', text: 'bar3'}
13153 ]);
13154 // then append, applying the master template values
13155 t.append('my-form', {name: 'my-select'});
13156 </code></pre>
13157 * A name attribute for the child template is not required if you have only one child
13158 * template or you want to refer to them by index.
13159  */
13160 Roo.MasterTemplate = function(){
13161     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13162     this.originalHtml = this.html;
13163     var st = {};
13164     var m, re = this.subTemplateRe;
13165     re.lastIndex = 0;
13166     var subIndex = 0;
13167     while(m = re.exec(this.html)){
13168         var name = m[1], content = m[2];
13169         st[subIndex] = {
13170             name: name,
13171             index: subIndex,
13172             buffer: [],
13173             tpl : new Roo.Template(content)
13174         };
13175         if(name){
13176             st[name] = st[subIndex];
13177         }
13178         st[subIndex].tpl.compile();
13179         st[subIndex].tpl.call = this.call.createDelegate(this);
13180         subIndex++;
13181     }
13182     this.subCount = subIndex;
13183     this.subs = st;
13184 };
13185 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13186     /**
13187     * The regular expression used to match sub templates
13188     * @type RegExp
13189     * @property
13190     */
13191     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13192
13193     /**
13194      * Applies the passed values to a child template.
13195      * @param {String/Number} name (optional) The name or index of the child template
13196      * @param {Array/Object} values The values to be applied to the template
13197      * @return {MasterTemplate} this
13198      */
13199      add : function(name, values){
13200         if(arguments.length == 1){
13201             values = arguments[0];
13202             name = 0;
13203         }
13204         var s = this.subs[name];
13205         s.buffer[s.buffer.length] = s.tpl.apply(values);
13206         return this;
13207     },
13208
13209     /**
13210      * Applies all the passed values to a child template.
13211      * @param {String/Number} name (optional) The name or index of the child template
13212      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13213      * @param {Boolean} reset (optional) True to reset the template first
13214      * @return {MasterTemplate} this
13215      */
13216     fill : function(name, values, reset){
13217         var a = arguments;
13218         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13219             values = a[0];
13220             name = 0;
13221             reset = a[1];
13222         }
13223         if(reset){
13224             this.reset();
13225         }
13226         for(var i = 0, len = values.length; i < len; i++){
13227             this.add(name, values[i]);
13228         }
13229         return this;
13230     },
13231
13232     /**
13233      * Resets the template for reuse
13234      * @return {MasterTemplate} this
13235      */
13236      reset : function(){
13237         var s = this.subs;
13238         for(var i = 0; i < this.subCount; i++){
13239             s[i].buffer = [];
13240         }
13241         return this;
13242     },
13243
13244     applyTemplate : function(values){
13245         var s = this.subs;
13246         var replaceIndex = -1;
13247         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13248             return s[++replaceIndex].buffer.join("");
13249         });
13250         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13251     },
13252
13253     apply : function(){
13254         return this.applyTemplate.apply(this, arguments);
13255     },
13256
13257     compile : function(){return this;}
13258 });
13259
13260 /**
13261  * Alias for fill().
13262  * @method
13263  */
13264 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13265  /**
13266  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13267  * var tpl = Roo.MasterTemplate.from('element-id');
13268  * @param {String/HTMLElement} el
13269  * @param {Object} config
13270  * @static
13271  */
13272 Roo.MasterTemplate.from = function(el, config){
13273     el = Roo.getDom(el);
13274     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13275 };/*
13276  * Based on:
13277  * Ext JS Library 1.1.1
13278  * Copyright(c) 2006-2007, Ext JS, LLC.
13279  *
13280  * Originally Released Under LGPL - original licence link has changed is not relivant.
13281  *
13282  * Fork - LGPL
13283  * <script type="text/javascript">
13284  */
13285
13286  
13287 /**
13288  * @class Roo.util.CSS
13289  * Utility class for manipulating CSS rules
13290  * @singleton
13291  */
13292 Roo.util.CSS = function(){
13293         var rules = null;
13294         var doc = document;
13295
13296     var camelRe = /(-[a-z])/gi;
13297     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13298
13299    return {
13300    /**
13301     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13302     * tag and appended to the HEAD of the document.
13303     * @param {String|Object} cssText The text containing the css rules
13304     * @param {String} id An id to add to the stylesheet for later removal
13305     * @return {StyleSheet}
13306     */
13307     createStyleSheet : function(cssText, id){
13308         var ss;
13309         var head = doc.getElementsByTagName("head")[0];
13310         var nrules = doc.createElement("style");
13311         nrules.setAttribute("type", "text/css");
13312         if(id){
13313             nrules.setAttribute("id", id);
13314         }
13315         if (typeof(cssText) != 'string') {
13316             // support object maps..
13317             // not sure if this a good idea.. 
13318             // perhaps it should be merged with the general css handling
13319             // and handle js style props.
13320             var cssTextNew = [];
13321             for(var n in cssText) {
13322                 var citems = [];
13323                 for(var k in cssText[n]) {
13324                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13325                 }
13326                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13327                 
13328             }
13329             cssText = cssTextNew.join("\n");
13330             
13331         }
13332        
13333        
13334        if(Roo.isIE){
13335            head.appendChild(nrules);
13336            ss = nrules.styleSheet;
13337            ss.cssText = cssText;
13338        }else{
13339            try{
13340                 nrules.appendChild(doc.createTextNode(cssText));
13341            }catch(e){
13342                nrules.cssText = cssText; 
13343            }
13344            head.appendChild(nrules);
13345            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13346        }
13347        this.cacheStyleSheet(ss);
13348        return ss;
13349    },
13350
13351    /**
13352     * Removes a style or link tag by id
13353     * @param {String} id The id of the tag
13354     */
13355    removeStyleSheet : function(id){
13356        var existing = doc.getElementById(id);
13357        if(existing){
13358            existing.parentNode.removeChild(existing);
13359        }
13360    },
13361
13362    /**
13363     * Dynamically swaps an existing stylesheet reference for a new one
13364     * @param {String} id The id of an existing link tag to remove
13365     * @param {String} url The href of the new stylesheet to include
13366     */
13367    swapStyleSheet : function(id, url){
13368        this.removeStyleSheet(id);
13369        var ss = doc.createElement("link");
13370        ss.setAttribute("rel", "stylesheet");
13371        ss.setAttribute("type", "text/css");
13372        ss.setAttribute("id", id);
13373        ss.setAttribute("href", url);
13374        doc.getElementsByTagName("head")[0].appendChild(ss);
13375    },
13376    
13377    /**
13378     * Refresh the rule cache if you have dynamically added stylesheets
13379     * @return {Object} An object (hash) of rules indexed by selector
13380     */
13381    refreshCache : function(){
13382        return this.getRules(true);
13383    },
13384
13385    // private
13386    cacheStyleSheet : function(stylesheet){
13387        if(!rules){
13388            rules = {};
13389        }
13390        try{// try catch for cross domain access issue
13391            var ssRules = stylesheet.cssRules || stylesheet.rules;
13392            for(var j = ssRules.length-1; j >= 0; --j){
13393                rules[ssRules[j].selectorText] = ssRules[j];
13394            }
13395        }catch(e){}
13396    },
13397    
13398    /**
13399     * Gets all css rules for the document
13400     * @param {Boolean} refreshCache true to refresh the internal cache
13401     * @return {Object} An object (hash) of rules indexed by selector
13402     */
13403    getRules : function(refreshCache){
13404                 if(rules == null || refreshCache){
13405                         rules = {};
13406                         var ds = doc.styleSheets;
13407                         for(var i =0, len = ds.length; i < len; i++){
13408                             try{
13409                         this.cacheStyleSheet(ds[i]);
13410                     }catch(e){} 
13411                 }
13412                 }
13413                 return rules;
13414         },
13415         
13416         /**
13417     * Gets an an individual CSS rule by selector(s)
13418     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13419     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13420     * @return {CSSRule} The CSS rule or null if one is not found
13421     */
13422    getRule : function(selector, refreshCache){
13423                 var rs = this.getRules(refreshCache);
13424                 if(!(selector instanceof Array)){
13425                     return rs[selector];
13426                 }
13427                 for(var i = 0; i < selector.length; i++){
13428                         if(rs[selector[i]]){
13429                                 return rs[selector[i]];
13430                         }
13431                 }
13432                 return null;
13433         },
13434         
13435         
13436         /**
13437     * Updates a rule property
13438     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13439     * @param {String} property The css property
13440     * @param {String} value The new value for the property
13441     * @return {Boolean} true If a rule was found and updated
13442     */
13443    updateRule : function(selector, property, value){
13444                 if(!(selector instanceof Array)){
13445                         var rule = this.getRule(selector);
13446                         if(rule){
13447                                 rule.style[property.replace(camelRe, camelFn)] = value;
13448                                 return true;
13449                         }
13450                 }else{
13451                         for(var i = 0; i < selector.length; i++){
13452                                 if(this.updateRule(selector[i], property, value)){
13453                                         return true;
13454                                 }
13455                         }
13456                 }
13457                 return false;
13458         }
13459    };   
13460 }();/*
13461  * Based on:
13462  * Ext JS Library 1.1.1
13463  * Copyright(c) 2006-2007, Ext JS, LLC.
13464  *
13465  * Originally Released Under LGPL - original licence link has changed is not relivant.
13466  *
13467  * Fork - LGPL
13468  * <script type="text/javascript">
13469  */
13470
13471  
13472
13473 /**
13474  * @class Roo.util.ClickRepeater
13475  * @extends Roo.util.Observable
13476  * 
13477  * A wrapper class which can be applied to any element. Fires a "click" event while the
13478  * mouse is pressed. The interval between firings may be specified in the config but
13479  * defaults to 10 milliseconds.
13480  * 
13481  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13482  * 
13483  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13484  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13485  * Similar to an autorepeat key delay.
13486  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13487  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13488  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13489  *           "interval" and "delay" are ignored. "immediate" is honored.
13490  * @cfg {Boolean} preventDefault True to prevent the default click event
13491  * @cfg {Boolean} stopDefault True to stop the default click event
13492  * 
13493  * @history
13494  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13495  *     2007-02-02 jvs Renamed to ClickRepeater
13496  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13497  *
13498  *  @constructor
13499  * @param {String/HTMLElement/Element} el The element to listen on
13500  * @param {Object} config
13501  **/
13502 Roo.util.ClickRepeater = function(el, config)
13503 {
13504     this.el = Roo.get(el);
13505     this.el.unselectable();
13506
13507     Roo.apply(this, config);
13508
13509     this.addEvents({
13510     /**
13511      * @event mousedown
13512      * Fires when the mouse button is depressed.
13513      * @param {Roo.util.ClickRepeater} this
13514      */
13515         "mousedown" : true,
13516     /**
13517      * @event click
13518      * Fires on a specified interval during the time the element is pressed.
13519      * @param {Roo.util.ClickRepeater} this
13520      */
13521         "click" : true,
13522     /**
13523      * @event mouseup
13524      * Fires when the mouse key is released.
13525      * @param {Roo.util.ClickRepeater} this
13526      */
13527         "mouseup" : true
13528     });
13529
13530     this.el.on("mousedown", this.handleMouseDown, this);
13531     if(this.preventDefault || this.stopDefault){
13532         this.el.on("click", function(e){
13533             if(this.preventDefault){
13534                 e.preventDefault();
13535             }
13536             if(this.stopDefault){
13537                 e.stopEvent();
13538             }
13539         }, this);
13540     }
13541
13542     // allow inline handler
13543     if(this.handler){
13544         this.on("click", this.handler,  this.scope || this);
13545     }
13546
13547     Roo.util.ClickRepeater.superclass.constructor.call(this);
13548 };
13549
13550 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13551     interval : 20,
13552     delay: 250,
13553     preventDefault : true,
13554     stopDefault : false,
13555     timer : 0,
13556
13557     // private
13558     handleMouseDown : function(){
13559         clearTimeout(this.timer);
13560         this.el.blur();
13561         if(this.pressClass){
13562             this.el.addClass(this.pressClass);
13563         }
13564         this.mousedownTime = new Date();
13565
13566         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13567         this.el.on("mouseout", this.handleMouseOut, this);
13568
13569         this.fireEvent("mousedown", this);
13570         this.fireEvent("click", this);
13571         
13572         this.timer = this.click.defer(this.delay || this.interval, this);
13573     },
13574
13575     // private
13576     click : function(){
13577         this.fireEvent("click", this);
13578         this.timer = this.click.defer(this.getInterval(), this);
13579     },
13580
13581     // private
13582     getInterval: function(){
13583         if(!this.accelerate){
13584             return this.interval;
13585         }
13586         var pressTime = this.mousedownTime.getElapsed();
13587         if(pressTime < 500){
13588             return 400;
13589         }else if(pressTime < 1700){
13590             return 320;
13591         }else if(pressTime < 2600){
13592             return 250;
13593         }else if(pressTime < 3500){
13594             return 180;
13595         }else if(pressTime < 4400){
13596             return 140;
13597         }else if(pressTime < 5300){
13598             return 80;
13599         }else if(pressTime < 6200){
13600             return 50;
13601         }else{
13602             return 10;
13603         }
13604     },
13605
13606     // private
13607     handleMouseOut : function(){
13608         clearTimeout(this.timer);
13609         if(this.pressClass){
13610             this.el.removeClass(this.pressClass);
13611         }
13612         this.el.on("mouseover", this.handleMouseReturn, this);
13613     },
13614
13615     // private
13616     handleMouseReturn : function(){
13617         this.el.un("mouseover", this.handleMouseReturn);
13618         if(this.pressClass){
13619             this.el.addClass(this.pressClass);
13620         }
13621         this.click();
13622     },
13623
13624     // private
13625     handleMouseUp : function(){
13626         clearTimeout(this.timer);
13627         this.el.un("mouseover", this.handleMouseReturn);
13628         this.el.un("mouseout", this.handleMouseOut);
13629         Roo.get(document).un("mouseup", this.handleMouseUp);
13630         this.el.removeClass(this.pressClass);
13631         this.fireEvent("mouseup", this);
13632     }
13633 });/*
13634  * Based on:
13635  * Ext JS Library 1.1.1
13636  * Copyright(c) 2006-2007, Ext JS, LLC.
13637  *
13638  * Originally Released Under LGPL - original licence link has changed is not relivant.
13639  *
13640  * Fork - LGPL
13641  * <script type="text/javascript">
13642  */
13643
13644  
13645 /**
13646  * @class Roo.KeyNav
13647  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13648  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13649  * way to implement custom navigation schemes for any UI component.</p>
13650  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13651  * pageUp, pageDown, del, home, end.  Usage:</p>
13652  <pre><code>
13653 var nav = new Roo.KeyNav("my-element", {
13654     "left" : function(e){
13655         this.moveLeft(e.ctrlKey);
13656     },
13657     "right" : function(e){
13658         this.moveRight(e.ctrlKey);
13659     },
13660     "enter" : function(e){
13661         this.save();
13662     },
13663     scope : this
13664 });
13665 </code></pre>
13666  * @constructor
13667  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13668  * @param {Object} config The config
13669  */
13670 Roo.KeyNav = function(el, config){
13671     this.el = Roo.get(el);
13672     Roo.apply(this, config);
13673     if(!this.disabled){
13674         this.disabled = true;
13675         this.enable();
13676     }
13677 };
13678
13679 Roo.KeyNav.prototype = {
13680     /**
13681      * @cfg {Boolean} disabled
13682      * True to disable this KeyNav instance (defaults to false)
13683      */
13684     disabled : false,
13685     /**
13686      * @cfg {String} defaultEventAction
13687      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13688      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13689      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13690      */
13691     defaultEventAction: "stopEvent",
13692     /**
13693      * @cfg {Boolean} forceKeyDown
13694      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13695      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13696      * handle keydown instead of keypress.
13697      */
13698     forceKeyDown : false,
13699
13700     // private
13701     prepareEvent : function(e){
13702         var k = e.getKey();
13703         var h = this.keyToHandler[k];
13704         //if(h && this[h]){
13705         //    e.stopPropagation();
13706         //}
13707         if(Roo.isSafari && h && k >= 37 && k <= 40){
13708             e.stopEvent();
13709         }
13710     },
13711
13712     // private
13713     relay : function(e){
13714         var k = e.getKey();
13715         var h = this.keyToHandler[k];
13716         if(h && this[h]){
13717             if(this.doRelay(e, this[h], h) !== true){
13718                 e[this.defaultEventAction]();
13719             }
13720         }
13721     },
13722
13723     // private
13724     doRelay : function(e, h, hname){
13725         return h.call(this.scope || this, e);
13726     },
13727
13728     // possible handlers
13729     enter : false,
13730     left : false,
13731     right : false,
13732     up : false,
13733     down : false,
13734     tab : false,
13735     esc : false,
13736     pageUp : false,
13737     pageDown : false,
13738     del : false,
13739     home : false,
13740     end : false,
13741
13742     // quick lookup hash
13743     keyToHandler : {
13744         37 : "left",
13745         39 : "right",
13746         38 : "up",
13747         40 : "down",
13748         33 : "pageUp",
13749         34 : "pageDown",
13750         46 : "del",
13751         36 : "home",
13752         35 : "end",
13753         13 : "enter",
13754         27 : "esc",
13755         9  : "tab"
13756     },
13757
13758         /**
13759          * Enable this KeyNav
13760          */
13761         enable: function(){
13762                 if(this.disabled){
13763             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13764             // the EventObject will normalize Safari automatically
13765             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13766                 this.el.on("keydown", this.relay,  this);
13767             }else{
13768                 this.el.on("keydown", this.prepareEvent,  this);
13769                 this.el.on("keypress", this.relay,  this);
13770             }
13771                     this.disabled = false;
13772                 }
13773         },
13774
13775         /**
13776          * Disable this KeyNav
13777          */
13778         disable: function(){
13779                 if(!this.disabled){
13780                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13781                 this.el.un("keydown", this.relay);
13782             }else{
13783                 this.el.un("keydown", this.prepareEvent);
13784                 this.el.un("keypress", this.relay);
13785             }
13786                     this.disabled = true;
13787                 }
13788         }
13789 };/*
13790  * Based on:
13791  * Ext JS Library 1.1.1
13792  * Copyright(c) 2006-2007, Ext JS, LLC.
13793  *
13794  * Originally Released Under LGPL - original licence link has changed is not relivant.
13795  *
13796  * Fork - LGPL
13797  * <script type="text/javascript">
13798  */
13799
13800  
13801 /**
13802  * @class Roo.KeyMap
13803  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13804  * The constructor accepts the same config object as defined by {@link #addBinding}.
13805  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13806  * combination it will call the function with this signature (if the match is a multi-key
13807  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13808  * A KeyMap can also handle a string representation of keys.<br />
13809  * Usage:
13810  <pre><code>
13811 // map one key by key code
13812 var map = new Roo.KeyMap("my-element", {
13813     key: 13, // or Roo.EventObject.ENTER
13814     fn: myHandler,
13815     scope: myObject
13816 });
13817
13818 // map multiple keys to one action by string
13819 var map = new Roo.KeyMap("my-element", {
13820     key: "a\r\n\t",
13821     fn: myHandler,
13822     scope: myObject
13823 });
13824
13825 // map multiple keys to multiple actions by strings and array of codes
13826 var map = new Roo.KeyMap("my-element", [
13827     {
13828         key: [10,13],
13829         fn: function(){ alert("Return was pressed"); }
13830     }, {
13831         key: "abc",
13832         fn: function(){ alert('a, b or c was pressed'); }
13833     }, {
13834         key: "\t",
13835         ctrl:true,
13836         shift:true,
13837         fn: function(){ alert('Control + shift + tab was pressed.'); }
13838     }
13839 ]);
13840 </code></pre>
13841  * <b>Note: A KeyMap starts enabled</b>
13842  * @constructor
13843  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13844  * @param {Object} config The config (see {@link #addBinding})
13845  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13846  */
13847 Roo.KeyMap = function(el, config, eventName){
13848     this.el  = Roo.get(el);
13849     this.eventName = eventName || "keydown";
13850     this.bindings = [];
13851     if(config){
13852         this.addBinding(config);
13853     }
13854     this.enable();
13855 };
13856
13857 Roo.KeyMap.prototype = {
13858     /**
13859      * True to stop the event from bubbling and prevent the default browser action if the
13860      * key was handled by the KeyMap (defaults to false)
13861      * @type Boolean
13862      */
13863     stopEvent : false,
13864
13865     /**
13866      * Add a new binding to this KeyMap. The following config object properties are supported:
13867      * <pre>
13868 Property    Type             Description
13869 ----------  ---------------  ----------------------------------------------------------------------
13870 key         String/Array     A single keycode or an array of keycodes to handle
13871 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13872 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13873 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13874 fn          Function         The function to call when KeyMap finds the expected key combination
13875 scope       Object           The scope of the callback function
13876 </pre>
13877      *
13878      * Usage:
13879      * <pre><code>
13880 // Create a KeyMap
13881 var map = new Roo.KeyMap(document, {
13882     key: Roo.EventObject.ENTER,
13883     fn: handleKey,
13884     scope: this
13885 });
13886
13887 //Add a new binding to the existing KeyMap later
13888 map.addBinding({
13889     key: 'abc',
13890     shift: true,
13891     fn: handleKey,
13892     scope: this
13893 });
13894 </code></pre>
13895      * @param {Object/Array} config A single KeyMap config or an array of configs
13896      */
13897         addBinding : function(config){
13898         if(config instanceof Array){
13899             for(var i = 0, len = config.length; i < len; i++){
13900                 this.addBinding(config[i]);
13901             }
13902             return;
13903         }
13904         var keyCode = config.key,
13905             shift = config.shift, 
13906             ctrl = config.ctrl, 
13907             alt = config.alt,
13908             fn = config.fn,
13909             scope = config.scope;
13910         if(typeof keyCode == "string"){
13911             var ks = [];
13912             var keyString = keyCode.toUpperCase();
13913             for(var j = 0, len = keyString.length; j < len; j++){
13914                 ks.push(keyString.charCodeAt(j));
13915             }
13916             keyCode = ks;
13917         }
13918         var keyArray = keyCode instanceof Array;
13919         var handler = function(e){
13920             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13921                 var k = e.getKey();
13922                 if(keyArray){
13923                     for(var i = 0, len = keyCode.length; i < len; i++){
13924                         if(keyCode[i] == k){
13925                           if(this.stopEvent){
13926                               e.stopEvent();
13927                           }
13928                           fn.call(scope || window, k, e);
13929                           return;
13930                         }
13931                     }
13932                 }else{
13933                     if(k == keyCode){
13934                         if(this.stopEvent){
13935                            e.stopEvent();
13936                         }
13937                         fn.call(scope || window, k, e);
13938                     }
13939                 }
13940             }
13941         };
13942         this.bindings.push(handler);  
13943         },
13944
13945     /**
13946      * Shorthand for adding a single key listener
13947      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13948      * following options:
13949      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13950      * @param {Function} fn The function to call
13951      * @param {Object} scope (optional) The scope of the function
13952      */
13953     on : function(key, fn, scope){
13954         var keyCode, shift, ctrl, alt;
13955         if(typeof key == "object" && !(key instanceof Array)){
13956             keyCode = key.key;
13957             shift = key.shift;
13958             ctrl = key.ctrl;
13959             alt = key.alt;
13960         }else{
13961             keyCode = key;
13962         }
13963         this.addBinding({
13964             key: keyCode,
13965             shift: shift,
13966             ctrl: ctrl,
13967             alt: alt,
13968             fn: fn,
13969             scope: scope
13970         })
13971     },
13972
13973     // private
13974     handleKeyDown : function(e){
13975             if(this.enabled){ //just in case
13976             var b = this.bindings;
13977             for(var i = 0, len = b.length; i < len; i++){
13978                 b[i].call(this, e);
13979             }
13980             }
13981         },
13982         
13983         /**
13984          * Returns true if this KeyMap is enabled
13985          * @return {Boolean} 
13986          */
13987         isEnabled : function(){
13988             return this.enabled;  
13989         },
13990         
13991         /**
13992          * Enables this KeyMap
13993          */
13994         enable: function(){
13995                 if(!this.enabled){
13996                     this.el.on(this.eventName, this.handleKeyDown, this);
13997                     this.enabled = true;
13998                 }
13999         },
14000
14001         /**
14002          * Disable this KeyMap
14003          */
14004         disable: function(){
14005                 if(this.enabled){
14006                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14007                     this.enabled = false;
14008                 }
14009         }
14010 };/*
14011  * Based on:
14012  * Ext JS Library 1.1.1
14013  * Copyright(c) 2006-2007, Ext JS, LLC.
14014  *
14015  * Originally Released Under LGPL - original licence link has changed is not relivant.
14016  *
14017  * Fork - LGPL
14018  * <script type="text/javascript">
14019  */
14020
14021  
14022 /**
14023  * @class Roo.util.TextMetrics
14024  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14025  * wide, in pixels, a given block of text will be.
14026  * @singleton
14027  */
14028 Roo.util.TextMetrics = function(){
14029     var shared;
14030     return {
14031         /**
14032          * Measures the size of the specified text
14033          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14034          * that can affect the size of the rendered text
14035          * @param {String} text The text to measure
14036          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14037          * in order to accurately measure the text height
14038          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14039          */
14040         measure : function(el, text, fixedWidth){
14041             if(!shared){
14042                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14043             }
14044             shared.bind(el);
14045             shared.setFixedWidth(fixedWidth || 'auto');
14046             return shared.getSize(text);
14047         },
14048
14049         /**
14050          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14051          * the overhead of multiple calls to initialize the style properties on each measurement.
14052          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14053          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14054          * in order to accurately measure the text height
14055          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14056          */
14057         createInstance : function(el, fixedWidth){
14058             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14059         }
14060     };
14061 }();
14062
14063  
14064
14065 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14066     var ml = new Roo.Element(document.createElement('div'));
14067     document.body.appendChild(ml.dom);
14068     ml.position('absolute');
14069     ml.setLeftTop(-1000, -1000);
14070     ml.hide();
14071
14072     if(fixedWidth){
14073         ml.setWidth(fixedWidth);
14074     }
14075      
14076     var instance = {
14077         /**
14078          * Returns the size of the specified text based on the internal element's style and width properties
14079          * @memberOf Roo.util.TextMetrics.Instance#
14080          * @param {String} text The text to measure
14081          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14082          */
14083         getSize : function(text){
14084             ml.update(text);
14085             var s = ml.getSize();
14086             ml.update('');
14087             return s;
14088         },
14089
14090         /**
14091          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14092          * that can affect the size of the rendered text
14093          * @memberOf Roo.util.TextMetrics.Instance#
14094          * @param {String/HTMLElement} el The element, dom node or id
14095          */
14096         bind : function(el){
14097             ml.setStyle(
14098                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14099             );
14100         },
14101
14102         /**
14103          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14104          * to set a fixed width in order to accurately measure the text height.
14105          * @memberOf Roo.util.TextMetrics.Instance#
14106          * @param {Number} width The width to set on the element
14107          */
14108         setFixedWidth : function(width){
14109             ml.setWidth(width);
14110         },
14111
14112         /**
14113          * Returns the measured width of the specified text
14114          * @memberOf Roo.util.TextMetrics.Instance#
14115          * @param {String} text The text to measure
14116          * @return {Number} width The width in pixels
14117          */
14118         getWidth : function(text){
14119             ml.dom.style.width = 'auto';
14120             return this.getSize(text).width;
14121         },
14122
14123         /**
14124          * Returns the measured height of the specified text.  For multiline text, be sure to call
14125          * {@link #setFixedWidth} if necessary.
14126          * @memberOf Roo.util.TextMetrics.Instance#
14127          * @param {String} text The text to measure
14128          * @return {Number} height The height in pixels
14129          */
14130         getHeight : function(text){
14131             return this.getSize(text).height;
14132         }
14133     };
14134
14135     instance.bind(bindTo);
14136
14137     return instance;
14138 };
14139
14140 // backwards compat
14141 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14142  * Based on:
14143  * Ext JS Library 1.1.1
14144  * Copyright(c) 2006-2007, Ext JS, LLC.
14145  *
14146  * Originally Released Under LGPL - original licence link has changed is not relivant.
14147  *
14148  * Fork - LGPL
14149  * <script type="text/javascript">
14150  */
14151
14152 /**
14153  * @class Roo.state.Provider
14154  * Abstract base class for state provider implementations. This class provides methods
14155  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14156  * Provider interface.
14157  */
14158 Roo.state.Provider = function(){
14159     /**
14160      * @event statechange
14161      * Fires when a state change occurs.
14162      * @param {Provider} this This state provider
14163      * @param {String} key The state key which was changed
14164      * @param {String} value The encoded value for the state
14165      */
14166     this.addEvents({
14167         "statechange": true
14168     });
14169     this.state = {};
14170     Roo.state.Provider.superclass.constructor.call(this);
14171 };
14172 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14173     /**
14174      * Returns the current value for a key
14175      * @param {String} name The key name
14176      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14177      * @return {Mixed} The state data
14178      */
14179     get : function(name, defaultValue){
14180         return typeof this.state[name] == "undefined" ?
14181             defaultValue : this.state[name];
14182     },
14183     
14184     /**
14185      * Clears a value from the state
14186      * @param {String} name The key name
14187      */
14188     clear : function(name){
14189         delete this.state[name];
14190         this.fireEvent("statechange", this, name, null);
14191     },
14192     
14193     /**
14194      * Sets the value for a key
14195      * @param {String} name The key name
14196      * @param {Mixed} value The value to set
14197      */
14198     set : function(name, value){
14199         this.state[name] = value;
14200         this.fireEvent("statechange", this, name, value);
14201     },
14202     
14203     /**
14204      * Decodes a string previously encoded with {@link #encodeValue}.
14205      * @param {String} value The value to decode
14206      * @return {Mixed} The decoded value
14207      */
14208     decodeValue : function(cookie){
14209         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14210         var matches = re.exec(unescape(cookie));
14211         if(!matches || !matches[1]) return; // non state cookie
14212         var type = matches[1];
14213         var v = matches[2];
14214         switch(type){
14215             case "n":
14216                 return parseFloat(v);
14217             case "d":
14218                 return new Date(Date.parse(v));
14219             case "b":
14220                 return (v == "1");
14221             case "a":
14222                 var all = [];
14223                 var values = v.split("^");
14224                 for(var i = 0, len = values.length; i < len; i++){
14225                     all.push(this.decodeValue(values[i]));
14226                 }
14227                 return all;
14228            case "o":
14229                 var all = {};
14230                 var values = v.split("^");
14231                 for(var i = 0, len = values.length; i < len; i++){
14232                     var kv = values[i].split("=");
14233                     all[kv[0]] = this.decodeValue(kv[1]);
14234                 }
14235                 return all;
14236            default:
14237                 return v;
14238         }
14239     },
14240     
14241     /**
14242      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14243      * @param {Mixed} value The value to encode
14244      * @return {String} The encoded value
14245      */
14246     encodeValue : function(v){
14247         var enc;
14248         if(typeof v == "number"){
14249             enc = "n:" + v;
14250         }else if(typeof v == "boolean"){
14251             enc = "b:" + (v ? "1" : "0");
14252         }else if(v instanceof Date){
14253             enc = "d:" + v.toGMTString();
14254         }else if(v instanceof Array){
14255             var flat = "";
14256             for(var i = 0, len = v.length; i < len; i++){
14257                 flat += this.encodeValue(v[i]);
14258                 if(i != len-1) flat += "^";
14259             }
14260             enc = "a:" + flat;
14261         }else if(typeof v == "object"){
14262             var flat = "";
14263             for(var key in v){
14264                 if(typeof v[key] != "function"){
14265                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14266                 }
14267             }
14268             enc = "o:" + flat.substring(0, flat.length-1);
14269         }else{
14270             enc = "s:" + v;
14271         }
14272         return escape(enc);        
14273     }
14274 });
14275
14276 /*
14277  * Based on:
14278  * Ext JS Library 1.1.1
14279  * Copyright(c) 2006-2007, Ext JS, LLC.
14280  *
14281  * Originally Released Under LGPL - original licence link has changed is not relivant.
14282  *
14283  * Fork - LGPL
14284  * <script type="text/javascript">
14285  */
14286 /**
14287  * @class Roo.state.Manager
14288  * This is the global state manager. By default all components that are "state aware" check this class
14289  * for state information if you don't pass them a custom state provider. In order for this class
14290  * to be useful, it must be initialized with a provider when your application initializes.
14291  <pre><code>
14292 // in your initialization function
14293 init : function(){
14294    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14295    ...
14296    // supposed you have a {@link Roo.BorderLayout}
14297    var layout = new Roo.BorderLayout(...);
14298    layout.restoreState();
14299    // or a {Roo.BasicDialog}
14300    var dialog = new Roo.BasicDialog(...);
14301    dialog.restoreState();
14302  </code></pre>
14303  * @singleton
14304  */
14305 Roo.state.Manager = function(){
14306     var provider = new Roo.state.Provider();
14307     
14308     return {
14309         /**
14310          * Configures the default state provider for your application
14311          * @param {Provider} stateProvider The state provider to set
14312          */
14313         setProvider : function(stateProvider){
14314             provider = stateProvider;
14315         },
14316         
14317         /**
14318          * Returns the current value for a key
14319          * @param {String} name The key name
14320          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14321          * @return {Mixed} The state data
14322          */
14323         get : function(key, defaultValue){
14324             return provider.get(key, defaultValue);
14325         },
14326         
14327         /**
14328          * Sets the value for a key
14329          * @param {String} name The key name
14330          * @param {Mixed} value The state data
14331          */
14332          set : function(key, value){
14333             provider.set(key, value);
14334         },
14335         
14336         /**
14337          * Clears a value from the state
14338          * @param {String} name The key name
14339          */
14340         clear : function(key){
14341             provider.clear(key);
14342         },
14343         
14344         /**
14345          * Gets the currently configured state provider
14346          * @return {Provider} The state provider
14347          */
14348         getProvider : function(){
14349             return provider;
14350         }
14351     };
14352 }();
14353 /*
14354  * Based on:
14355  * Ext JS Library 1.1.1
14356  * Copyright(c) 2006-2007, Ext JS, LLC.
14357  *
14358  * Originally Released Under LGPL - original licence link has changed is not relivant.
14359  *
14360  * Fork - LGPL
14361  * <script type="text/javascript">
14362  */
14363 /**
14364  * @class Roo.state.CookieProvider
14365  * @extends Roo.state.Provider
14366  * The default Provider implementation which saves state via cookies.
14367  * <br />Usage:
14368  <pre><code>
14369    var cp = new Roo.state.CookieProvider({
14370        path: "/cgi-bin/",
14371        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14372        domain: "roojs.com"
14373    })
14374    Roo.state.Manager.setProvider(cp);
14375  </code></pre>
14376  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14377  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14378  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14379  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14380  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14381  * domain the page is running on including the 'www' like 'www.roojs.com')
14382  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14383  * @constructor
14384  * Create a new CookieProvider
14385  * @param {Object} config The configuration object
14386  */
14387 Roo.state.CookieProvider = function(config){
14388     Roo.state.CookieProvider.superclass.constructor.call(this);
14389     this.path = "/";
14390     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14391     this.domain = null;
14392     this.secure = false;
14393     Roo.apply(this, config);
14394     this.state = this.readCookies();
14395 };
14396
14397 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14398     // private
14399     set : function(name, value){
14400         if(typeof value == "undefined" || value === null){
14401             this.clear(name);
14402             return;
14403         }
14404         this.setCookie(name, value);
14405         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14406     },
14407
14408     // private
14409     clear : function(name){
14410         this.clearCookie(name);
14411         Roo.state.CookieProvider.superclass.clear.call(this, name);
14412     },
14413
14414     // private
14415     readCookies : function(){
14416         var cookies = {};
14417         var c = document.cookie + ";";
14418         var re = /\s?(.*?)=(.*?);/g;
14419         var matches;
14420         while((matches = re.exec(c)) != null){
14421             var name = matches[1];
14422             var value = matches[2];
14423             if(name && name.substring(0,3) == "ys-"){
14424                 cookies[name.substr(3)] = this.decodeValue(value);
14425             }
14426         }
14427         return cookies;
14428     },
14429
14430     // private
14431     setCookie : function(name, value){
14432         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14433            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14434            ((this.path == null) ? "" : ("; path=" + this.path)) +
14435            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14436            ((this.secure == true) ? "; secure" : "");
14437     },
14438
14439     // private
14440     clearCookie : function(name){
14441         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14442            ((this.path == null) ? "" : ("; path=" + this.path)) +
14443            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14444            ((this.secure == true) ? "; secure" : "");
14445     }
14446 });