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 (Allows +08, without minutes)
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{2,4})"};
1391     
1392     
1393     case "P":
1394         return {g:1,
1395                 c:[
1396                    "o = results[", currentGroup, "];\n",
1397                    "var sn = o.substring(0,1);\n",
1398                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1399                    "var mn = o.substring(4,6) % 60;\n",
1400                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1401                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1402             ].join(""),
1403             s:"([+\-]\\d{4})"};
1404     case "T":
1405         return {g:0,
1406             c:null,
1407             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1408     case "Z":
1409         return {g:1,
1410             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1411                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1412             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1413     default:
1414         return {g:0,
1415             c:null,
1416             s:String.escape(character)};
1417     }
1418 };
1419
1420 /**
1421  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1422  * @return {String} The abbreviated timezone name (e.g. 'CST')
1423  */
1424 Date.prototype.getTimezone = function() {
1425     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1426 };
1427
1428 /**
1429  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1430  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1431  */
1432 Date.prototype.getGMTOffset = function() {
1433     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1434         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1435         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1436 };
1437
1438 /**
1439  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1440  * @return {String} 2-characters representing hours and 2-characters representing minutes
1441  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1442  */
1443 Date.prototype.getGMTColonOffset = function() {
1444         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1445                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1446                 + ":"
1447                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1448 }
1449
1450 /**
1451  * Get the numeric day number of the year, adjusted for leap year.
1452  * @return {Number} 0 through 364 (365 in leap years)
1453  */
1454 Date.prototype.getDayOfYear = function() {
1455     var num = 0;
1456     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1457     for (var i = 0; i < this.getMonth(); ++i) {
1458         num += Date.daysInMonth[i];
1459     }
1460     return num + this.getDate() - 1;
1461 };
1462
1463 /**
1464  * Get the string representation of the numeric week number of the year
1465  * (equivalent to the format specifier 'W').
1466  * @return {String} '00' through '52'
1467  */
1468 Date.prototype.getWeekOfYear = function() {
1469     // Skip to Thursday of this week
1470     var now = this.getDayOfYear() + (4 - this.getDay());
1471     // Find the first Thursday of the year
1472     var jan1 = new Date(this.getFullYear(), 0, 1);
1473     var then = (7 - jan1.getDay() + 4);
1474     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1475 };
1476
1477 /**
1478  * Whether or not the current date is in a leap year.
1479  * @return {Boolean} True if the current date is in a leap year, else false
1480  */
1481 Date.prototype.isLeapYear = function() {
1482     var year = this.getFullYear();
1483     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1484 };
1485
1486 /**
1487  * Get the first day of the current month, adjusted for leap year.  The returned value
1488  * is the numeric day index within the week (0-6) which can be used in conjunction with
1489  * the {@link #monthNames} array to retrieve the textual day name.
1490  * Example:
1491  *<pre><code>
1492 var dt = new Date('1/10/2007');
1493 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1494 </code></pre>
1495  * @return {Number} The day number (0-6)
1496  */
1497 Date.prototype.getFirstDayOfMonth = function() {
1498     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1499     return (day < 0) ? (day + 7) : day;
1500 };
1501
1502 /**
1503  * Get the last day of the current month, adjusted for leap year.  The returned value
1504  * is the numeric day index within the week (0-6) which can be used in conjunction with
1505  * the {@link #monthNames} array to retrieve the textual day name.
1506  * Example:
1507  *<pre><code>
1508 var dt = new Date('1/10/2007');
1509 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1510 </code></pre>
1511  * @return {Number} The day number (0-6)
1512  */
1513 Date.prototype.getLastDayOfMonth = function() {
1514     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1515     return (day < 0) ? (day + 7) : day;
1516 };
1517
1518
1519 /**
1520  * Get the first date of this date's month
1521  * @return {Date}
1522  */
1523 Date.prototype.getFirstDateOfMonth = function() {
1524     return new Date(this.getFullYear(), this.getMonth(), 1);
1525 };
1526
1527 /**
1528  * Get the last date of this date's month
1529  * @return {Date}
1530  */
1531 Date.prototype.getLastDateOfMonth = function() {
1532     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1533 };
1534 /**
1535  * Get the number of days in the current month, adjusted for leap year.
1536  * @return {Number} The number of days in the month
1537  */
1538 Date.prototype.getDaysInMonth = function() {
1539     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1540     return Date.daysInMonth[this.getMonth()];
1541 };
1542
1543 /**
1544  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1545  * @return {String} 'st, 'nd', 'rd' or 'th'
1546  */
1547 Date.prototype.getSuffix = function() {
1548     switch (this.getDate()) {
1549         case 1:
1550         case 21:
1551         case 31:
1552             return "st";
1553         case 2:
1554         case 22:
1555             return "nd";
1556         case 3:
1557         case 23:
1558             return "rd";
1559         default:
1560             return "th";
1561     }
1562 };
1563
1564 // private
1565 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1566
1567 /**
1568  * An array of textual month names.
1569  * Override these values for international dates, for example...
1570  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1571  * @type Array
1572  * @static
1573  */
1574 Date.monthNames =
1575    ["January",
1576     "February",
1577     "March",
1578     "April",
1579     "May",
1580     "June",
1581     "July",
1582     "August",
1583     "September",
1584     "October",
1585     "November",
1586     "December"];
1587
1588 /**
1589  * An array of textual day names.
1590  * Override these values for international dates, for example...
1591  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1592  * @type Array
1593  * @static
1594  */
1595 Date.dayNames =
1596    ["Sunday",
1597     "Monday",
1598     "Tuesday",
1599     "Wednesday",
1600     "Thursday",
1601     "Friday",
1602     "Saturday"];
1603
1604 // private
1605 Date.y2kYear = 50;
1606 // private
1607 Date.monthNumbers = {
1608     Jan:0,
1609     Feb:1,
1610     Mar:2,
1611     Apr:3,
1612     May:4,
1613     Jun:5,
1614     Jul:6,
1615     Aug:7,
1616     Sep:8,
1617     Oct:9,
1618     Nov:10,
1619     Dec:11};
1620
1621 /**
1622  * Creates and returns a new Date instance with the exact same date value as the called instance.
1623  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1624  * variable will also be changed.  When the intention is to create a new variable that will not
1625  * modify the original instance, you should create a clone.
1626  *
1627  * Example of correctly cloning a date:
1628  * <pre><code>
1629 //wrong way:
1630 var orig = new Date('10/1/2006');
1631 var copy = orig;
1632 copy.setDate(5);
1633 document.write(orig);  //returns 'Thu Oct 05 2006'!
1634
1635 //correct way:
1636 var orig = new Date('10/1/2006');
1637 var copy = orig.clone();
1638 copy.setDate(5);
1639 document.write(orig);  //returns 'Thu Oct 01 2006'
1640 </code></pre>
1641  * @return {Date} The new Date instance
1642  */
1643 Date.prototype.clone = function() {
1644         return new Date(this.getTime());
1645 };
1646
1647 /**
1648  * Clears any time information from this date
1649  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1650  @return {Date} this or the clone
1651  */
1652 Date.prototype.clearTime = function(clone){
1653     if(clone){
1654         return this.clone().clearTime();
1655     }
1656     this.setHours(0);
1657     this.setMinutes(0);
1658     this.setSeconds(0);
1659     this.setMilliseconds(0);
1660     return this;
1661 };
1662
1663 // private
1664 // safari setMonth is broken
1665 if(Roo.isSafari){
1666     Date.brokenSetMonth = Date.prototype.setMonth;
1667         Date.prototype.setMonth = function(num){
1668                 if(num <= -1){
1669                         var n = Math.ceil(-num);
1670                         var back_year = Math.ceil(n/12);
1671                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1672                         this.setFullYear(this.getFullYear() - back_year);
1673                         return Date.brokenSetMonth.call(this, month);
1674                 } else {
1675                         return Date.brokenSetMonth.apply(this, arguments);
1676                 }
1677         };
1678 }
1679
1680 /** Date interval constant 
1681 * @static 
1682 * @type String */
1683 Date.MILLI = "ms";
1684 /** Date interval constant 
1685 * @static 
1686 * @type String */
1687 Date.SECOND = "s";
1688 /** Date interval constant 
1689 * @static 
1690 * @type String */
1691 Date.MINUTE = "mi";
1692 /** Date interval constant 
1693 * @static 
1694 * @type String */
1695 Date.HOUR = "h";
1696 /** Date interval constant 
1697 * @static 
1698 * @type String */
1699 Date.DAY = "d";
1700 /** Date interval constant 
1701 * @static 
1702 * @type String */
1703 Date.MONTH = "mo";
1704 /** Date interval constant 
1705 * @static 
1706 * @type String */
1707 Date.YEAR = "y";
1708
1709 /**
1710  * Provides a convenient method of performing basic date arithmetic.  This method
1711  * does not modify the Date instance being called - it creates and returns
1712  * a new Date instance containing the resulting date value.
1713  *
1714  * Examples:
1715  * <pre><code>
1716 //Basic usage:
1717 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1718 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1719
1720 //Negative values will subtract correctly:
1721 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1722 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1723
1724 //You can even chain several calls together in one line!
1725 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1726 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1727  </code></pre>
1728  *
1729  * @param {String} interval   A valid date interval enum value
1730  * @param {Number} value      The amount to add to the current date
1731  * @return {Date} The new Date instance
1732  */
1733 Date.prototype.add = function(interval, value){
1734   var d = this.clone();
1735   if (!interval || value === 0) return d;
1736   switch(interval.toLowerCase()){
1737     case Date.MILLI:
1738       d.setMilliseconds(this.getMilliseconds() + value);
1739       break;
1740     case Date.SECOND:
1741       d.setSeconds(this.getSeconds() + value);
1742       break;
1743     case Date.MINUTE:
1744       d.setMinutes(this.getMinutes() + value);
1745       break;
1746     case Date.HOUR:
1747       d.setHours(this.getHours() + value);
1748       break;
1749     case Date.DAY:
1750       d.setDate(this.getDate() + value);
1751       break;
1752     case Date.MONTH:
1753       var day = this.getDate();
1754       if(day > 28){
1755           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1756       }
1757       d.setDate(day);
1758       d.setMonth(this.getMonth() + value);
1759       break;
1760     case Date.YEAR:
1761       d.setFullYear(this.getFullYear() + value);
1762       break;
1763   }
1764   return d;
1765 };
1766 /*
1767  * Based on:
1768  * Ext JS Library 1.1.1
1769  * Copyright(c) 2006-2007, Ext JS, LLC.
1770  *
1771  * Originally Released Under LGPL - original licence link has changed is not relivant.
1772  *
1773  * Fork - LGPL
1774  * <script type="text/javascript">
1775  */
1776
1777 Roo.lib.Dom = {
1778     getViewWidth : function(full) {
1779         return full ? this.getDocumentWidth() : this.getViewportWidth();
1780     },
1781
1782     getViewHeight : function(full) {
1783         return full ? this.getDocumentHeight() : this.getViewportHeight();
1784     },
1785
1786     getDocumentHeight: function() {
1787         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1788         return Math.max(scrollHeight, this.getViewportHeight());
1789     },
1790
1791     getDocumentWidth: function() {
1792         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1793         return Math.max(scrollWidth, this.getViewportWidth());
1794     },
1795
1796     getViewportHeight: function() {
1797         var height = self.innerHeight;
1798         var mode = document.compatMode;
1799
1800         if ((mode || Roo.isIE) && !Roo.isOpera) {
1801             height = (mode == "CSS1Compat") ?
1802                      document.documentElement.clientHeight :
1803                      document.body.clientHeight;
1804         }
1805
1806         return height;
1807     },
1808
1809     getViewportWidth: function() {
1810         var width = self.innerWidth;
1811         var mode = document.compatMode;
1812
1813         if (mode || Roo.isIE) {
1814             width = (mode == "CSS1Compat") ?
1815                     document.documentElement.clientWidth :
1816                     document.body.clientWidth;
1817         }
1818         return width;
1819     },
1820
1821     isAncestor : function(p, c) {
1822         p = Roo.getDom(p);
1823         c = Roo.getDom(c);
1824         if (!p || !c) {
1825             return false;
1826         }
1827
1828         if (p.contains && !Roo.isSafari) {
1829             return p.contains(c);
1830         } else if (p.compareDocumentPosition) {
1831             return !!(p.compareDocumentPosition(c) & 16);
1832         } else {
1833             var parent = c.parentNode;
1834             while (parent) {
1835                 if (parent == p) {
1836                     return true;
1837                 }
1838                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1839                     return false;
1840                 }
1841                 parent = parent.parentNode;
1842             }
1843             return false;
1844         }
1845     },
1846
1847     getRegion : function(el) {
1848         return Roo.lib.Region.getRegion(el);
1849     },
1850
1851     getY : function(el) {
1852         return this.getXY(el)[1];
1853     },
1854
1855     getX : function(el) {
1856         return this.getXY(el)[0];
1857     },
1858
1859     getXY : function(el) {
1860         var p, pe, b, scroll, bd = document.body;
1861         el = Roo.getDom(el);
1862         var fly = Roo.lib.AnimBase.fly;
1863         if (el.getBoundingClientRect) {
1864             b = el.getBoundingClientRect();
1865             scroll = fly(document).getScroll();
1866             return [b.left + scroll.left, b.top + scroll.top];
1867         }
1868         var x = 0, y = 0;
1869
1870         p = el;
1871
1872         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1873
1874         while (p) {
1875
1876             x += p.offsetLeft;
1877             y += p.offsetTop;
1878
1879             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1880                 hasAbsolute = true;
1881             }
1882
1883             if (Roo.isGecko) {
1884                 pe = fly(p);
1885
1886                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1887                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1888
1889
1890                 x += bl;
1891                 y += bt;
1892
1893
1894                 if (p != el && pe.getStyle('overflow') != 'visible') {
1895                     x += bl;
1896                     y += bt;
1897                 }
1898             }
1899             p = p.offsetParent;
1900         }
1901
1902         if (Roo.isSafari && hasAbsolute) {
1903             x -= bd.offsetLeft;
1904             y -= bd.offsetTop;
1905         }
1906
1907         if (Roo.isGecko && !hasAbsolute) {
1908             var dbd = fly(bd);
1909             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1910             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1911         }
1912
1913         p = el.parentNode;
1914         while (p && p != bd) {
1915             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1916                 x -= p.scrollLeft;
1917                 y -= p.scrollTop;
1918             }
1919             p = p.parentNode;
1920         }
1921         return [x, y];
1922     },
1923  
1924   
1925
1926
1927     setXY : function(el, xy) {
1928         el = Roo.fly(el, '_setXY');
1929         el.position();
1930         var pts = el.translatePoints(xy);
1931         if (xy[0] !== false) {
1932             el.dom.style.left = pts.left + "px";
1933         }
1934         if (xy[1] !== false) {
1935             el.dom.style.top = pts.top + "px";
1936         }
1937     },
1938
1939     setX : function(el, x) {
1940         this.setXY(el, [x, false]);
1941     },
1942
1943     setY : function(el, y) {
1944         this.setXY(el, [false, y]);
1945     }
1946 };
1947 /*
1948  * Portions of this file are based on pieces of Yahoo User Interface Library
1949  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1950  * YUI licensed under the BSD License:
1951  * http://developer.yahoo.net/yui/license.txt
1952  * <script type="text/javascript">
1953  *
1954  */
1955
1956 Roo.lib.Event = function() {
1957     var loadComplete = false;
1958     var listeners = [];
1959     var unloadListeners = [];
1960     var retryCount = 0;
1961     var onAvailStack = [];
1962     var counter = 0;
1963     var lastError = null;
1964
1965     return {
1966         POLL_RETRYS: 200,
1967         POLL_INTERVAL: 20,
1968         EL: 0,
1969         TYPE: 1,
1970         FN: 2,
1971         WFN: 3,
1972         OBJ: 3,
1973         ADJ_SCOPE: 4,
1974         _interval: null,
1975
1976         startInterval: function() {
1977             if (!this._interval) {
1978                 var self = this;
1979                 var callback = function() {
1980                     self._tryPreloadAttach();
1981                 };
1982                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1983
1984             }
1985         },
1986
1987         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1988             onAvailStack.push({ id:         p_id,
1989                 fn:         p_fn,
1990                 obj:        p_obj,
1991                 override:   p_override,
1992                 checkReady: false    });
1993
1994             retryCount = this.POLL_RETRYS;
1995             this.startInterval();
1996         },
1997
1998
1999         addListener: function(el, eventName, fn) {
2000             el = Roo.getDom(el);
2001             if (!el || !fn) {
2002                 return false;
2003             }
2004
2005             if ("unload" == eventName) {
2006                 unloadListeners[unloadListeners.length] =
2007                 [el, eventName, fn];
2008                 return true;
2009             }
2010
2011             var wrappedFn = function(e) {
2012                 return fn(Roo.lib.Event.getEvent(e));
2013             };
2014
2015             var li = [el, eventName, fn, wrappedFn];
2016
2017             var index = listeners.length;
2018             listeners[index] = li;
2019
2020             this.doAdd(el, eventName, wrappedFn, false);
2021             return true;
2022
2023         },
2024
2025
2026         removeListener: function(el, eventName, fn) {
2027             var i, len;
2028
2029             el = Roo.getDom(el);
2030
2031             if(!fn) {
2032                 return this.purgeElement(el, false, eventName);
2033             }
2034
2035
2036             if ("unload" == eventName) {
2037
2038                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2039                     var li = unloadListeners[i];
2040                     if (li &&
2041                         li[0] == el &&
2042                         li[1] == eventName &&
2043                         li[2] == fn) {
2044                         unloadListeners.splice(i, 1);
2045                         return true;
2046                     }
2047                 }
2048
2049                 return false;
2050             }
2051
2052             var cacheItem = null;
2053
2054
2055             var index = arguments[3];
2056
2057             if ("undefined" == typeof index) {
2058                 index = this._getCacheIndex(el, eventName, fn);
2059             }
2060
2061             if (index >= 0) {
2062                 cacheItem = listeners[index];
2063             }
2064
2065             if (!el || !cacheItem) {
2066                 return false;
2067             }
2068
2069             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2070
2071             delete listeners[index][this.WFN];
2072             delete listeners[index][this.FN];
2073             listeners.splice(index, 1);
2074
2075             return true;
2076
2077         },
2078
2079
2080         getTarget: function(ev, resolveTextNode) {
2081             ev = ev.browserEvent || ev;
2082             var t = ev.target || ev.srcElement;
2083             return this.resolveTextNode(t);
2084         },
2085
2086
2087         resolveTextNode: function(node) {
2088             if (Roo.isSafari && node && 3 == node.nodeType) {
2089                 return node.parentNode;
2090             } else {
2091                 return node;
2092             }
2093         },
2094
2095
2096         getPageX: function(ev) {
2097             ev = ev.browserEvent || ev;
2098             var x = ev.pageX;
2099             if (!x && 0 !== x) {
2100                 x = ev.clientX || 0;
2101
2102                 if (Roo.isIE) {
2103                     x += this.getScroll()[1];
2104                 }
2105             }
2106
2107             return x;
2108         },
2109
2110
2111         getPageY: function(ev) {
2112             ev = ev.browserEvent || ev;
2113             var y = ev.pageY;
2114             if (!y && 0 !== y) {
2115                 y = ev.clientY || 0;
2116
2117                 if (Roo.isIE) {
2118                     y += this.getScroll()[0];
2119                 }
2120             }
2121
2122
2123             return y;
2124         },
2125
2126
2127         getXY: function(ev) {
2128             ev = ev.browserEvent || ev;
2129             return [this.getPageX(ev), this.getPageY(ev)];
2130         },
2131
2132
2133         getRelatedTarget: function(ev) {
2134             ev = ev.browserEvent || ev;
2135             var t = ev.relatedTarget;
2136             if (!t) {
2137                 if (ev.type == "mouseout") {
2138                     t = ev.toElement;
2139                 } else if (ev.type == "mouseover") {
2140                     t = ev.fromElement;
2141                 }
2142             }
2143
2144             return this.resolveTextNode(t);
2145         },
2146
2147
2148         getTime: function(ev) {
2149             ev = ev.browserEvent || ev;
2150             if (!ev.time) {
2151                 var t = new Date().getTime();
2152                 try {
2153                     ev.time = t;
2154                 } catch(ex) {
2155                     this.lastError = ex;
2156                     return t;
2157                 }
2158             }
2159
2160             return ev.time;
2161         },
2162
2163
2164         stopEvent: function(ev) {
2165             this.stopPropagation(ev);
2166             this.preventDefault(ev);
2167         },
2168
2169
2170         stopPropagation: function(ev) {
2171             ev = ev.browserEvent || ev;
2172             if (ev.stopPropagation) {
2173                 ev.stopPropagation();
2174             } else {
2175                 ev.cancelBubble = true;
2176             }
2177         },
2178
2179
2180         preventDefault: function(ev) {
2181             ev = ev.browserEvent || ev;
2182             if(ev.preventDefault) {
2183                 ev.preventDefault();
2184             } else {
2185                 ev.returnValue = false;
2186             }
2187         },
2188
2189
2190         getEvent: function(e) {
2191             var ev = e || window.event;
2192             if (!ev) {
2193                 var c = this.getEvent.caller;
2194                 while (c) {
2195                     ev = c.arguments[0];
2196                     if (ev && Event == ev.constructor) {
2197                         break;
2198                     }
2199                     c = c.caller;
2200                 }
2201             }
2202             return ev;
2203         },
2204
2205
2206         getCharCode: function(ev) {
2207             ev = ev.browserEvent || ev;
2208             return ev.charCode || ev.keyCode || 0;
2209         },
2210
2211
2212         _getCacheIndex: function(el, eventName, fn) {
2213             for (var i = 0,len = listeners.length; i < len; ++i) {
2214                 var li = listeners[i];
2215                 if (li &&
2216                     li[this.FN] == fn &&
2217                     li[this.EL] == el &&
2218                     li[this.TYPE] == eventName) {
2219                     return i;
2220                 }
2221             }
2222
2223             return -1;
2224         },
2225
2226
2227         elCache: {},
2228
2229
2230         getEl: function(id) {
2231             return document.getElementById(id);
2232         },
2233
2234
2235         clearCache: function() {
2236         },
2237
2238
2239         _load: function(e) {
2240             loadComplete = true;
2241             var EU = Roo.lib.Event;
2242
2243
2244             if (Roo.isIE) {
2245                 EU.doRemove(window, "load", EU._load);
2246             }
2247         },
2248
2249
2250         _tryPreloadAttach: function() {
2251
2252             if (this.locked) {
2253                 return false;
2254             }
2255
2256             this.locked = true;
2257
2258
2259             var tryAgain = !loadComplete;
2260             if (!tryAgain) {
2261                 tryAgain = (retryCount > 0);
2262             }
2263
2264
2265             var notAvail = [];
2266             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2267                 var item = onAvailStack[i];
2268                 if (item) {
2269                     var el = this.getEl(item.id);
2270
2271                     if (el) {
2272                         if (!item.checkReady ||
2273                             loadComplete ||
2274                             el.nextSibling ||
2275                             (document && document.body)) {
2276
2277                             var scope = el;
2278                             if (item.override) {
2279                                 if (item.override === true) {
2280                                     scope = item.obj;
2281                                 } else {
2282                                     scope = item.override;
2283                                 }
2284                             }
2285                             item.fn.call(scope, item.obj);
2286                             onAvailStack[i] = null;
2287                         }
2288                     } else {
2289                         notAvail.push(item);
2290                     }
2291                 }
2292             }
2293
2294             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2295
2296             if (tryAgain) {
2297
2298                 this.startInterval();
2299             } else {
2300                 clearInterval(this._interval);
2301                 this._interval = null;
2302             }
2303
2304             this.locked = false;
2305
2306             return true;
2307
2308         },
2309
2310
2311         purgeElement: function(el, recurse, eventName) {
2312             var elListeners = this.getListeners(el, eventName);
2313             if (elListeners) {
2314                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2315                     var l = elListeners[i];
2316                     this.removeListener(el, l.type, l.fn);
2317                 }
2318             }
2319
2320             if (recurse && el && el.childNodes) {
2321                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2322                     this.purgeElement(el.childNodes[i], recurse, eventName);
2323                 }
2324             }
2325         },
2326
2327
2328         getListeners: function(el, eventName) {
2329             var results = [], searchLists;
2330             if (!eventName) {
2331                 searchLists = [listeners, unloadListeners];
2332             } else if (eventName == "unload") {
2333                 searchLists = [unloadListeners];
2334             } else {
2335                 searchLists = [listeners];
2336             }
2337
2338             for (var j = 0; j < searchLists.length; ++j) {
2339                 var searchList = searchLists[j];
2340                 if (searchList && searchList.length > 0) {
2341                     for (var i = 0,len = searchList.length; i < len; ++i) {
2342                         var l = searchList[i];
2343                         if (l && l[this.EL] === el &&
2344                             (!eventName || eventName === l[this.TYPE])) {
2345                             results.push({
2346                                 type:   l[this.TYPE],
2347                                 fn:     l[this.FN],
2348                                 obj:    l[this.OBJ],
2349                                 adjust: l[this.ADJ_SCOPE],
2350                                 index:  i
2351                             });
2352                         }
2353                     }
2354                 }
2355             }
2356
2357             return (results.length) ? results : null;
2358         },
2359
2360
2361         _unload: function(e) {
2362
2363             var EU = Roo.lib.Event, i, j, l, len, index;
2364
2365             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2366                 l = unloadListeners[i];
2367                 if (l) {
2368                     var scope = window;
2369                     if (l[EU.ADJ_SCOPE]) {
2370                         if (l[EU.ADJ_SCOPE] === true) {
2371                             scope = l[EU.OBJ];
2372                         } else {
2373                             scope = l[EU.ADJ_SCOPE];
2374                         }
2375                     }
2376                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2377                     unloadListeners[i] = null;
2378                     l = null;
2379                     scope = null;
2380                 }
2381             }
2382
2383             unloadListeners = null;
2384
2385             if (listeners && listeners.length > 0) {
2386                 j = listeners.length;
2387                 while (j) {
2388                     index = j - 1;
2389                     l = listeners[index];
2390                     if (l) {
2391                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2392                                 l[EU.FN], index);
2393                     }
2394                     j = j - 1;
2395                 }
2396                 l = null;
2397
2398                 EU.clearCache();
2399             }
2400
2401             EU.doRemove(window, "unload", EU._unload);
2402
2403         },
2404
2405
2406         getScroll: function() {
2407             var dd = document.documentElement, db = document.body;
2408             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2409                 return [dd.scrollTop, dd.scrollLeft];
2410             } else if (db) {
2411                 return [db.scrollTop, db.scrollLeft];
2412             } else {
2413                 return [0, 0];
2414             }
2415         },
2416
2417
2418         doAdd: function () {
2419             if (window.addEventListener) {
2420                 return function(el, eventName, fn, capture) {
2421                     el.addEventListener(eventName, fn, (capture));
2422                 };
2423             } else if (window.attachEvent) {
2424                 return function(el, eventName, fn, capture) {
2425                     el.attachEvent("on" + eventName, fn);
2426                 };
2427             } else {
2428                 return function() {
2429                 };
2430             }
2431         }(),
2432
2433
2434         doRemove: function() {
2435             if (window.removeEventListener) {
2436                 return function (el, eventName, fn, capture) {
2437                     el.removeEventListener(eventName, fn, (capture));
2438                 };
2439             } else if (window.detachEvent) {
2440                 return function (el, eventName, fn) {
2441                     el.detachEvent("on" + eventName, fn);
2442                 };
2443             } else {
2444                 return function() {
2445                 };
2446             }
2447         }()
2448     };
2449     
2450 }();
2451 (function() {     
2452    
2453     var E = Roo.lib.Event;
2454     E.on = E.addListener;
2455     E.un = E.removeListener;
2456
2457     if (document && document.body) {
2458         E._load();
2459     } else {
2460         E.doAdd(window, "load", E._load);
2461     }
2462     E.doAdd(window, "unload", E._unload);
2463     E._tryPreloadAttach();
2464 })();
2465
2466 /*
2467  * Portions of this file are based on pieces of Yahoo User Interface Library
2468  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2469  * YUI licensed under the BSD License:
2470  * http://developer.yahoo.net/yui/license.txt
2471  * <script type="text/javascript">
2472  *
2473  */
2474
2475 (function() {
2476     /**
2477      * @class Roo.lib.Ajax
2478      *
2479      */
2480     Roo.lib.Ajax = {
2481         /**
2482          * @static 
2483          */
2484         request : function(method, uri, cb, data, options) {
2485             if(options){
2486                 var hs = options.headers;
2487                 if(hs){
2488                     for(var h in hs){
2489                         if(hs.hasOwnProperty(h)){
2490                             this.initHeader(h, hs[h], false);
2491                         }
2492                     }
2493                 }
2494                 if(options.xmlData){
2495                     this.initHeader('Content-Type', 'text/xml', false);
2496                     method = 'POST';
2497                     data = options.xmlData;
2498                 }
2499             }
2500
2501             return this.asyncRequest(method, uri, cb, data);
2502         },
2503
2504         serializeForm : function(form) {
2505             if(typeof form == 'string') {
2506                 form = (document.getElementById(form) || document.forms[form]);
2507             }
2508
2509             var el, name, val, disabled, data = '', hasSubmit = false;
2510             for (var i = 0; i < form.elements.length; i++) {
2511                 el = form.elements[i];
2512                 disabled = form.elements[i].disabled;
2513                 name = form.elements[i].name;
2514                 val = form.elements[i].value;
2515
2516                 if (!disabled && name){
2517                     switch (el.type)
2518                             {
2519                         case 'select-one':
2520                         case 'select-multiple':
2521                             for (var j = 0; j < el.options.length; j++) {
2522                                 if (el.options[j].selected) {
2523                                     if (Roo.isIE) {
2524                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2525                                     }
2526                                     else {
2527                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2528                                     }
2529                                 }
2530                             }
2531                             break;
2532                         case 'radio':
2533                         case 'checkbox':
2534                             if (el.checked) {
2535                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2536                             }
2537                             break;
2538                         case 'file':
2539
2540                         case undefined:
2541
2542                         case 'reset':
2543
2544                         case 'button':
2545
2546                             break;
2547                         case 'submit':
2548                             if(hasSubmit == false) {
2549                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2550                                 hasSubmit = true;
2551                             }
2552                             break;
2553                         default:
2554                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2555                             break;
2556                     }
2557                 }
2558             }
2559             data = data.substr(0, data.length - 1);
2560             return data;
2561         },
2562
2563         headers:{},
2564
2565         hasHeaders:false,
2566
2567         useDefaultHeader:true,
2568
2569         defaultPostHeader:'application/x-www-form-urlencoded',
2570
2571         useDefaultXhrHeader:true,
2572
2573         defaultXhrHeader:'XMLHttpRequest',
2574
2575         hasDefaultHeaders:true,
2576
2577         defaultHeaders:{},
2578
2579         poll:{},
2580
2581         timeout:{},
2582
2583         pollInterval:50,
2584
2585         transactionId:0,
2586
2587         setProgId:function(id)
2588         {
2589             this.activeX.unshift(id);
2590         },
2591
2592         setDefaultPostHeader:function(b)
2593         {
2594             this.useDefaultHeader = b;
2595         },
2596
2597         setDefaultXhrHeader:function(b)
2598         {
2599             this.useDefaultXhrHeader = b;
2600         },
2601
2602         setPollingInterval:function(i)
2603         {
2604             if (typeof i == 'number' && isFinite(i)) {
2605                 this.pollInterval = i;
2606             }
2607         },
2608
2609         createXhrObject:function(transactionId)
2610         {
2611             var obj,http;
2612             try
2613             {
2614
2615                 http = new XMLHttpRequest();
2616
2617                 obj = { conn:http, tId:transactionId };
2618             }
2619             catch(e)
2620             {
2621                 for (var i = 0; i < this.activeX.length; ++i) {
2622                     try
2623                     {
2624
2625                         http = new ActiveXObject(this.activeX[i]);
2626
2627                         obj = { conn:http, tId:transactionId };
2628                         break;
2629                     }
2630                     catch(e) {
2631                     }
2632                 }
2633             }
2634             finally
2635             {
2636                 return obj;
2637             }
2638         },
2639
2640         getConnectionObject:function()
2641         {
2642             var o;
2643             var tId = this.transactionId;
2644
2645             try
2646             {
2647                 o = this.createXhrObject(tId);
2648                 if (o) {
2649                     this.transactionId++;
2650                 }
2651             }
2652             catch(e) {
2653             }
2654             finally
2655             {
2656                 return o;
2657             }
2658         },
2659
2660         asyncRequest:function(method, uri, callback, postData)
2661         {
2662             var o = this.getConnectionObject();
2663
2664             if (!o) {
2665                 return null;
2666             }
2667             else {
2668                 o.conn.open(method, uri, true);
2669
2670                 if (this.useDefaultXhrHeader) {
2671                     if (!this.defaultHeaders['X-Requested-With']) {
2672                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2673                     }
2674                 }
2675
2676                 if(postData && this.useDefaultHeader){
2677                     this.initHeader('Content-Type', this.defaultPostHeader);
2678                 }
2679
2680                  if (this.hasDefaultHeaders || this.hasHeaders) {
2681                     this.setHeader(o);
2682                 }
2683
2684                 this.handleReadyState(o, callback);
2685                 o.conn.send(postData || null);
2686
2687                 return o;
2688             }
2689         },
2690
2691         handleReadyState:function(o, callback)
2692         {
2693             var oConn = this;
2694
2695             if (callback && callback.timeout) {
2696                 this.timeout[o.tId] = window.setTimeout(function() {
2697                     oConn.abort(o, callback, true);
2698                 }, callback.timeout);
2699             }
2700
2701             this.poll[o.tId] = window.setInterval(
2702                     function() {
2703                         if (o.conn && o.conn.readyState == 4) {
2704                             window.clearInterval(oConn.poll[o.tId]);
2705                             delete oConn.poll[o.tId];
2706
2707                             if(callback && callback.timeout) {
2708                                 window.clearTimeout(oConn.timeout[o.tId]);
2709                                 delete oConn.timeout[o.tId];
2710                             }
2711
2712                             oConn.handleTransactionResponse(o, callback);
2713                         }
2714                     }
2715                     , this.pollInterval);
2716         },
2717
2718         handleTransactionResponse:function(o, callback, isAbort)
2719         {
2720
2721             if (!callback) {
2722                 this.releaseObject(o);
2723                 return;
2724             }
2725
2726             var httpStatus, responseObject;
2727
2728             try
2729             {
2730                 if (o.conn.status !== undefined && o.conn.status != 0) {
2731                     httpStatus = o.conn.status;
2732                 }
2733                 else {
2734                     httpStatus = 13030;
2735                 }
2736             }
2737             catch(e) {
2738
2739
2740                 httpStatus = 13030;
2741             }
2742
2743             if (httpStatus >= 200 && httpStatus < 300) {
2744                 responseObject = this.createResponseObject(o, callback.argument);
2745                 if (callback.success) {
2746                     if (!callback.scope) {
2747                         callback.success(responseObject);
2748                     }
2749                     else {
2750
2751
2752                         callback.success.apply(callback.scope, [responseObject]);
2753                     }
2754                 }
2755             }
2756             else {
2757                 switch (httpStatus) {
2758
2759                     case 12002:
2760                     case 12029:
2761                     case 12030:
2762                     case 12031:
2763                     case 12152:
2764                     case 13030:
2765                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2766                         if (callback.failure) {
2767                             if (!callback.scope) {
2768                                 callback.failure(responseObject);
2769                             }
2770                             else {
2771                                 callback.failure.apply(callback.scope, [responseObject]);
2772                             }
2773                         }
2774                         break;
2775                     default:
2776                         responseObject = this.createResponseObject(o, callback.argument);
2777                         if (callback.failure) {
2778                             if (!callback.scope) {
2779                                 callback.failure(responseObject);
2780                             }
2781                             else {
2782                                 callback.failure.apply(callback.scope, [responseObject]);
2783                             }
2784                         }
2785                 }
2786             }
2787
2788             this.releaseObject(o);
2789             responseObject = null;
2790         },
2791
2792         createResponseObject:function(o, callbackArg)
2793         {
2794             var obj = {};
2795             var headerObj = {};
2796
2797             try
2798             {
2799                 var headerStr = o.conn.getAllResponseHeaders();
2800                 var header = headerStr.split('\n');
2801                 for (var i = 0; i < header.length; i++) {
2802                     var delimitPos = header[i].indexOf(':');
2803                     if (delimitPos != -1) {
2804                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2805                     }
2806                 }
2807             }
2808             catch(e) {
2809             }
2810
2811             obj.tId = o.tId;
2812             obj.status = o.conn.status;
2813             obj.statusText = o.conn.statusText;
2814             obj.getResponseHeader = headerObj;
2815             obj.getAllResponseHeaders = headerStr;
2816             obj.responseText = o.conn.responseText;
2817             obj.responseXML = o.conn.responseXML;
2818
2819             if (typeof callbackArg !== undefined) {
2820                 obj.argument = callbackArg;
2821             }
2822
2823             return obj;
2824         },
2825
2826         createExceptionObject:function(tId, callbackArg, isAbort)
2827         {
2828             var COMM_CODE = 0;
2829             var COMM_ERROR = 'communication failure';
2830             var ABORT_CODE = -1;
2831             var ABORT_ERROR = 'transaction aborted';
2832
2833             var obj = {};
2834
2835             obj.tId = tId;
2836             if (isAbort) {
2837                 obj.status = ABORT_CODE;
2838                 obj.statusText = ABORT_ERROR;
2839             }
2840             else {
2841                 obj.status = COMM_CODE;
2842                 obj.statusText = COMM_ERROR;
2843             }
2844
2845             if (callbackArg) {
2846                 obj.argument = callbackArg;
2847             }
2848
2849             return obj;
2850         },
2851
2852         initHeader:function(label, value, isDefault)
2853         {
2854             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2855
2856             if (headerObj[label] === undefined) {
2857                 headerObj[label] = value;
2858             }
2859             else {
2860
2861
2862                 headerObj[label] = value + "," + headerObj[label];
2863             }
2864
2865             if (isDefault) {
2866                 this.hasDefaultHeaders = true;
2867             }
2868             else {
2869                 this.hasHeaders = true;
2870             }
2871         },
2872
2873
2874         setHeader:function(o)
2875         {
2876             if (this.hasDefaultHeaders) {
2877                 for (var prop in this.defaultHeaders) {
2878                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2879                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2880                     }
2881                 }
2882             }
2883
2884             if (this.hasHeaders) {
2885                 for (var prop in this.headers) {
2886                     if (this.headers.hasOwnProperty(prop)) {
2887                         o.conn.setRequestHeader(prop, this.headers[prop]);
2888                     }
2889                 }
2890                 this.headers = {};
2891                 this.hasHeaders = false;
2892             }
2893         },
2894
2895         resetDefaultHeaders:function() {
2896             delete this.defaultHeaders;
2897             this.defaultHeaders = {};
2898             this.hasDefaultHeaders = false;
2899         },
2900
2901         abort:function(o, callback, isTimeout)
2902         {
2903             if(this.isCallInProgress(o)) {
2904                 o.conn.abort();
2905                 window.clearInterval(this.poll[o.tId]);
2906                 delete this.poll[o.tId];
2907                 if (isTimeout) {
2908                     delete this.timeout[o.tId];
2909                 }
2910
2911                 this.handleTransactionResponse(o, callback, true);
2912
2913                 return true;
2914             }
2915             else {
2916                 return false;
2917             }
2918         },
2919
2920
2921         isCallInProgress:function(o)
2922         {
2923             if (o && o.conn) {
2924                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2925             }
2926             else {
2927
2928                 return false;
2929             }
2930         },
2931
2932
2933         releaseObject:function(o)
2934         {
2935
2936             o.conn = null;
2937
2938             o = null;
2939         },
2940
2941         activeX:[
2942         'MSXML2.XMLHTTP.3.0',
2943         'MSXML2.XMLHTTP',
2944         'Microsoft.XMLHTTP'
2945         ]
2946
2947
2948     };
2949 })();/*
2950  * Portions of this file are based on pieces of Yahoo User Interface Library
2951  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2952  * YUI licensed under the BSD License:
2953  * http://developer.yahoo.net/yui/license.txt
2954  * <script type="text/javascript">
2955  *
2956  */
2957
2958 Roo.lib.Region = function(t, r, b, l) {
2959     this.top = t;
2960     this[1] = t;
2961     this.right = r;
2962     this.bottom = b;
2963     this.left = l;
2964     this[0] = l;
2965 };
2966
2967
2968 Roo.lib.Region.prototype = {
2969     contains : function(region) {
2970         return ( region.left >= this.left &&
2971                  region.right <= this.right &&
2972                  region.top >= this.top &&
2973                  region.bottom <= this.bottom    );
2974
2975     },
2976
2977     getArea : function() {
2978         return ( (this.bottom - this.top) * (this.right - this.left) );
2979     },
2980
2981     intersect : function(region) {
2982         var t = Math.max(this.top, region.top);
2983         var r = Math.min(this.right, region.right);
2984         var b = Math.min(this.bottom, region.bottom);
2985         var l = Math.max(this.left, region.left);
2986
2987         if (b >= t && r >= l) {
2988             return new Roo.lib.Region(t, r, b, l);
2989         } else {
2990             return null;
2991         }
2992     },
2993     union : function(region) {
2994         var t = Math.min(this.top, region.top);
2995         var r = Math.max(this.right, region.right);
2996         var b = Math.max(this.bottom, region.bottom);
2997         var l = Math.min(this.left, region.left);
2998
2999         return new Roo.lib.Region(t, r, b, l);
3000     },
3001
3002     adjust : function(t, l, b, r) {
3003         this.top += t;
3004         this.left += l;
3005         this.right += r;
3006         this.bottom += b;
3007         return this;
3008     }
3009 };
3010
3011 Roo.lib.Region.getRegion = function(el) {
3012     var p = Roo.lib.Dom.getXY(el);
3013
3014     var t = p[1];
3015     var r = p[0] + el.offsetWidth;
3016     var b = p[1] + el.offsetHeight;
3017     var l = p[0];
3018
3019     return new Roo.lib.Region(t, r, b, l);
3020 };
3021 /*
3022  * Portions of this file are based on pieces of Yahoo User Interface Library
3023  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3024  * YUI licensed under the BSD License:
3025  * http://developer.yahoo.net/yui/license.txt
3026  * <script type="text/javascript">
3027  *
3028  */
3029 //@@dep Roo.lib.Region
3030
3031
3032 Roo.lib.Point = function(x, y) {
3033     if (x instanceof Array) {
3034         y = x[1];
3035         x = x[0];
3036     }
3037     this.x = this.right = this.left = this[0] = x;
3038     this.y = this.top = this.bottom = this[1] = y;
3039 };
3040
3041 Roo.lib.Point.prototype = new Roo.lib.Region();
3042 /*
3043  * Portions of this file are based on pieces of Yahoo User Interface Library
3044  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3045  * YUI licensed under the BSD License:
3046  * http://developer.yahoo.net/yui/license.txt
3047  * <script type="text/javascript">
3048  *
3049  */
3050  
3051 (function() {   
3052
3053     Roo.lib.Anim = {
3054         scroll : function(el, args, duration, easing, cb, scope) {
3055             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3056         },
3057
3058         motion : function(el, args, duration, easing, cb, scope) {
3059             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3060         },
3061
3062         color : function(el, args, duration, easing, cb, scope) {
3063             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3064         },
3065
3066         run : function(el, args, duration, easing, cb, scope, type) {
3067             type = type || Roo.lib.AnimBase;
3068             if (typeof easing == "string") {
3069                 easing = Roo.lib.Easing[easing];
3070             }
3071             var anim = new type(el, args, duration, easing);
3072             anim.animateX(function() {
3073                 Roo.callback(cb, scope);
3074             });
3075             return anim;
3076         }
3077     };
3078 })();/*
3079  * Portions of this file are based on pieces of Yahoo User Interface Library
3080  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3081  * YUI licensed under the BSD License:
3082  * http://developer.yahoo.net/yui/license.txt
3083  * <script type="text/javascript">
3084  *
3085  */
3086
3087 (function() {    
3088     var libFlyweight;
3089     
3090     function fly(el) {
3091         if (!libFlyweight) {
3092             libFlyweight = new Roo.Element.Flyweight();
3093         }
3094         libFlyweight.dom = el;
3095         return libFlyweight;
3096     }
3097
3098     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3099     
3100    
3101     
3102     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3103         if (el) {
3104             this.init(el, attributes, duration, method);
3105         }
3106     };
3107
3108     Roo.lib.AnimBase.fly = fly;
3109     
3110     
3111     
3112     Roo.lib.AnimBase.prototype = {
3113
3114         toString: function() {
3115             var el = this.getEl();
3116             var id = el.id || el.tagName;
3117             return ("Anim " + id);
3118         },
3119
3120         patterns: {
3121             noNegatives:        /width|height|opacity|padding/i,
3122             offsetAttribute:  /^((width|height)|(top|left))$/,
3123             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3124             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3125         },
3126
3127
3128         doMethod: function(attr, start, end) {
3129             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3130         },
3131
3132
3133         setAttribute: function(attr, val, unit) {
3134             if (this.patterns.noNegatives.test(attr)) {
3135                 val = (val > 0) ? val : 0;
3136             }
3137
3138             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3139         },
3140
3141
3142         getAttribute: function(attr) {
3143             var el = this.getEl();
3144             var val = fly(el).getStyle(attr);
3145
3146             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3147                 return parseFloat(val);
3148             }
3149
3150             var a = this.patterns.offsetAttribute.exec(attr) || [];
3151             var pos = !!( a[3] );
3152             var box = !!( a[2] );
3153
3154
3155             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3156                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3157             } else {
3158                 val = 0;
3159             }
3160
3161             return val;
3162         },
3163
3164
3165         getDefaultUnit: function(attr) {
3166             if (this.patterns.defaultUnit.test(attr)) {
3167                 return 'px';
3168             }
3169
3170             return '';
3171         },
3172
3173         animateX : function(callback, scope) {
3174             var f = function() {
3175                 this.onComplete.removeListener(f);
3176                 if (typeof callback == "function") {
3177                     callback.call(scope || this, this);
3178                 }
3179             };
3180             this.onComplete.addListener(f, this);
3181             this.animate();
3182         },
3183
3184
3185         setRuntimeAttribute: function(attr) {
3186             var start;
3187             var end;
3188             var attributes = this.attributes;
3189
3190             this.runtimeAttributes[attr] = {};
3191
3192             var isset = function(prop) {
3193                 return (typeof prop !== 'undefined');
3194             };
3195
3196             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3197                 return false;
3198             }
3199
3200             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3201
3202
3203             if (isset(attributes[attr]['to'])) {
3204                 end = attributes[attr]['to'];
3205             } else if (isset(attributes[attr]['by'])) {
3206                 if (start.constructor == Array) {
3207                     end = [];
3208                     for (var i = 0, len = start.length; i < len; ++i) {
3209                         end[i] = start[i] + attributes[attr]['by'][i];
3210                     }
3211                 } else {
3212                     end = start + attributes[attr]['by'];
3213                 }
3214             }
3215
3216             this.runtimeAttributes[attr].start = start;
3217             this.runtimeAttributes[attr].end = end;
3218
3219
3220             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3221         },
3222
3223
3224         init: function(el, attributes, duration, method) {
3225
3226             var isAnimated = false;
3227
3228
3229             var startTime = null;
3230
3231
3232             var actualFrames = 0;
3233
3234
3235             el = Roo.getDom(el);
3236
3237
3238             this.attributes = attributes || {};
3239
3240
3241             this.duration = duration || 1;
3242
3243
3244             this.method = method || Roo.lib.Easing.easeNone;
3245
3246
3247             this.useSeconds = true;
3248
3249
3250             this.currentFrame = 0;
3251
3252
3253             this.totalFrames = Roo.lib.AnimMgr.fps;
3254
3255
3256             this.getEl = function() {
3257                 return el;
3258             };
3259
3260
3261             this.isAnimated = function() {
3262                 return isAnimated;
3263             };
3264
3265
3266             this.getStartTime = function() {
3267                 return startTime;
3268             };
3269
3270             this.runtimeAttributes = {};
3271
3272
3273             this.animate = function() {
3274                 if (this.isAnimated()) {
3275                     return false;
3276                 }
3277
3278                 this.currentFrame = 0;
3279
3280                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3281
3282                 Roo.lib.AnimMgr.registerElement(this);
3283             };
3284
3285
3286             this.stop = function(finish) {
3287                 if (finish) {
3288                     this.currentFrame = this.totalFrames;
3289                     this._onTween.fire();
3290                 }
3291                 Roo.lib.AnimMgr.stop(this);
3292             };
3293
3294             var onStart = function() {
3295                 this.onStart.fire();
3296
3297                 this.runtimeAttributes = {};
3298                 for (var attr in this.attributes) {
3299                     this.setRuntimeAttribute(attr);
3300                 }
3301
3302                 isAnimated = true;
3303                 actualFrames = 0;
3304                 startTime = new Date();
3305             };
3306
3307
3308             var onTween = function() {
3309                 var data = {
3310                     duration: new Date() - this.getStartTime(),
3311                     currentFrame: this.currentFrame
3312                 };
3313
3314                 data.toString = function() {
3315                     return (
3316                             'duration: ' + data.duration +
3317                             ', currentFrame: ' + data.currentFrame
3318                             );
3319                 };
3320
3321                 this.onTween.fire(data);
3322
3323                 var runtimeAttributes = this.runtimeAttributes;
3324
3325                 for (var attr in runtimeAttributes) {
3326                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3327                 }
3328
3329                 actualFrames += 1;
3330             };
3331
3332             var onComplete = function() {
3333                 var actual_duration = (new Date() - startTime) / 1000 ;
3334
3335                 var data = {
3336                     duration: actual_duration,
3337                     frames: actualFrames,
3338                     fps: actualFrames / actual_duration
3339                 };
3340
3341                 data.toString = function() {
3342                     return (
3343                             'duration: ' + data.duration +
3344                             ', frames: ' + data.frames +
3345                             ', fps: ' + data.fps
3346                             );
3347                 };
3348
3349                 isAnimated = false;
3350                 actualFrames = 0;
3351                 this.onComplete.fire(data);
3352             };
3353
3354
3355             this._onStart = new Roo.util.Event(this);
3356             this.onStart = new Roo.util.Event(this);
3357             this.onTween = new Roo.util.Event(this);
3358             this._onTween = new Roo.util.Event(this);
3359             this.onComplete = new Roo.util.Event(this);
3360             this._onComplete = new Roo.util.Event(this);
3361             this._onStart.addListener(onStart);
3362             this._onTween.addListener(onTween);
3363             this._onComplete.addListener(onComplete);
3364         }
3365     };
3366 })();
3367 /*
3368  * Portions of this file are based on pieces of Yahoo User Interface Library
3369  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3370  * YUI licensed under the BSD License:
3371  * http://developer.yahoo.net/yui/license.txt
3372  * <script type="text/javascript">
3373  *
3374  */
3375
3376 Roo.lib.AnimMgr = new function() {
3377
3378         var thread = null;
3379
3380
3381         var queue = [];
3382
3383
3384         var tweenCount = 0;
3385
3386
3387         this.fps = 1000;
3388
3389
3390         this.delay = 1;
3391
3392
3393         this.registerElement = function(tween) {
3394             queue[queue.length] = tween;
3395             tweenCount += 1;
3396             tween._onStart.fire();
3397             this.start();
3398         };
3399
3400
3401         this.unRegister = function(tween, index) {
3402             tween._onComplete.fire();
3403             index = index || getIndex(tween);
3404             if (index != -1) {
3405                 queue.splice(index, 1);
3406             }
3407
3408             tweenCount -= 1;
3409             if (tweenCount <= 0) {
3410                 this.stop();
3411             }
3412         };
3413
3414
3415         this.start = function() {
3416             if (thread === null) {
3417                 thread = setInterval(this.run, this.delay);
3418             }
3419         };
3420
3421
3422         this.stop = function(tween) {
3423             if (!tween) {
3424                 clearInterval(thread);
3425
3426                 for (var i = 0, len = queue.length; i < len; ++i) {
3427                     if (queue[0].isAnimated()) {
3428                         this.unRegister(queue[0], 0);
3429                     }
3430                 }
3431
3432                 queue = [];
3433                 thread = null;
3434                 tweenCount = 0;
3435             }
3436             else {
3437                 this.unRegister(tween);
3438             }
3439         };
3440
3441
3442         this.run = function() {
3443             for (var i = 0, len = queue.length; i < len; ++i) {
3444                 var tween = queue[i];
3445                 if (!tween || !tween.isAnimated()) {
3446                     continue;
3447                 }
3448
3449                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3450                 {
3451                     tween.currentFrame += 1;
3452
3453                     if (tween.useSeconds) {
3454                         correctFrame(tween);
3455                     }
3456                     tween._onTween.fire();
3457                 }
3458                 else {
3459                     Roo.lib.AnimMgr.stop(tween, i);
3460                 }
3461             }
3462         };
3463
3464         var getIndex = function(anim) {
3465             for (var i = 0, len = queue.length; i < len; ++i) {
3466                 if (queue[i] == anim) {
3467                     return i;
3468                 }
3469             }
3470             return -1;
3471         };
3472
3473
3474         var correctFrame = function(tween) {
3475             var frames = tween.totalFrames;
3476             var frame = tween.currentFrame;
3477             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3478             var elapsed = (new Date() - tween.getStartTime());
3479             var tweak = 0;
3480
3481             if (elapsed < tween.duration * 1000) {
3482                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3483             } else {
3484                 tweak = frames - (frame + 1);
3485             }
3486             if (tweak > 0 && isFinite(tweak)) {
3487                 if (tween.currentFrame + tweak >= frames) {
3488                     tweak = frames - (frame + 1);
3489                 }
3490
3491                 tween.currentFrame += tweak;
3492             }
3493         };
3494     };/*
3495  * Portions of this file are based on pieces of Yahoo User Interface Library
3496  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3497  * YUI licensed under the BSD License:
3498  * http://developer.yahoo.net/yui/license.txt
3499  * <script type="text/javascript">
3500  *
3501  */
3502 Roo.lib.Bezier = new function() {
3503
3504         this.getPosition = function(points, t) {
3505             var n = points.length;
3506             var tmp = [];
3507
3508             for (var i = 0; i < n; ++i) {
3509                 tmp[i] = [points[i][0], points[i][1]];
3510             }
3511
3512             for (var j = 1; j < n; ++j) {
3513                 for (i = 0; i < n - j; ++i) {
3514                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3515                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3516                 }
3517             }
3518
3519             return [ tmp[0][0], tmp[0][1] ];
3520
3521         };
3522     };/*
3523  * Portions of this file are based on pieces of Yahoo User Interface Library
3524  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525  * YUI licensed under the BSD License:
3526  * http://developer.yahoo.net/yui/license.txt
3527  * <script type="text/javascript">
3528  *
3529  */
3530 (function() {
3531
3532     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3533         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3534     };
3535
3536     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3537
3538     var fly = Roo.lib.AnimBase.fly;
3539     var Y = Roo.lib;
3540     var superclass = Y.ColorAnim.superclass;
3541     var proto = Y.ColorAnim.prototype;
3542
3543     proto.toString = function() {
3544         var el = this.getEl();
3545         var id = el.id || el.tagName;
3546         return ("ColorAnim " + id);
3547     };
3548
3549     proto.patterns.color = /color$/i;
3550     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3551     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3552     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3553     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3554
3555
3556     proto.parseColor = function(s) {
3557         if (s.length == 3) {
3558             return s;
3559         }
3560
3561         var c = this.patterns.hex.exec(s);
3562         if (c && c.length == 4) {
3563             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3564         }
3565
3566         c = this.patterns.rgb.exec(s);
3567         if (c && c.length == 4) {
3568             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3569         }
3570
3571         c = this.patterns.hex3.exec(s);
3572         if (c && c.length == 4) {
3573             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3574         }
3575
3576         return null;
3577     };
3578     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3579     proto.getAttribute = function(attr) {
3580         var el = this.getEl();
3581         if (this.patterns.color.test(attr)) {
3582             var val = fly(el).getStyle(attr);
3583
3584             if (this.patterns.transparent.test(val)) {
3585                 var parent = el.parentNode;
3586                 val = fly(parent).getStyle(attr);
3587
3588                 while (parent && this.patterns.transparent.test(val)) {
3589                     parent = parent.parentNode;
3590                     val = fly(parent).getStyle(attr);
3591                     if (parent.tagName.toUpperCase() == 'HTML') {
3592                         val = '#fff';
3593                     }
3594                 }
3595             }
3596         } else {
3597             val = superclass.getAttribute.call(this, attr);
3598         }
3599
3600         return val;
3601     };
3602     proto.getAttribute = function(attr) {
3603         var el = this.getEl();
3604         if (this.patterns.color.test(attr)) {
3605             var val = fly(el).getStyle(attr);
3606
3607             if (this.patterns.transparent.test(val)) {
3608                 var parent = el.parentNode;
3609                 val = fly(parent).getStyle(attr);
3610
3611                 while (parent && this.patterns.transparent.test(val)) {
3612                     parent = parent.parentNode;
3613                     val = fly(parent).getStyle(attr);
3614                     if (parent.tagName.toUpperCase() == 'HTML') {
3615                         val = '#fff';
3616                     }
3617                 }
3618             }
3619         } else {
3620             val = superclass.getAttribute.call(this, attr);
3621         }
3622
3623         return val;
3624     };
3625
3626     proto.doMethod = function(attr, start, end) {
3627         var val;
3628
3629         if (this.patterns.color.test(attr)) {
3630             val = [];
3631             for (var i = 0, len = start.length; i < len; ++i) {
3632                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3633             }
3634
3635             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3636         }
3637         else {
3638             val = superclass.doMethod.call(this, attr, start, end);
3639         }
3640
3641         return val;
3642     };
3643
3644     proto.setRuntimeAttribute = function(attr) {
3645         superclass.setRuntimeAttribute.call(this, attr);
3646
3647         if (this.patterns.color.test(attr)) {
3648             var attributes = this.attributes;
3649             var start = this.parseColor(this.runtimeAttributes[attr].start);
3650             var end = this.parseColor(this.runtimeAttributes[attr].end);
3651
3652             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3653                 end = this.parseColor(attributes[attr].by);
3654
3655                 for (var i = 0, len = start.length; i < len; ++i) {
3656                     end[i] = start[i] + end[i];
3657                 }
3658             }
3659
3660             this.runtimeAttributes[attr].start = start;
3661             this.runtimeAttributes[attr].end = end;
3662         }
3663     };
3664 })();
3665
3666 /*
3667  * Portions of this file are based on pieces of Yahoo User Interface Library
3668  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669  * YUI licensed under the BSD License:
3670  * http://developer.yahoo.net/yui/license.txt
3671  * <script type="text/javascript">
3672  *
3673  */
3674 Roo.lib.Easing = {
3675
3676
3677     easeNone: function (t, b, c, d) {
3678         return c * t / d + b;
3679     },
3680
3681
3682     easeIn: function (t, b, c, d) {
3683         return c * (t /= d) * t + b;
3684     },
3685
3686
3687     easeOut: function (t, b, c, d) {
3688         return -c * (t /= d) * (t - 2) + b;
3689     },
3690
3691
3692     easeBoth: function (t, b, c, d) {
3693         if ((t /= d / 2) < 1) {
3694             return c / 2 * t * t + b;
3695         }
3696
3697         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3698     },
3699
3700
3701     easeInStrong: function (t, b, c, d) {
3702         return c * (t /= d) * t * t * t + b;
3703     },
3704
3705
3706     easeOutStrong: function (t, b, c, d) {
3707         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3708     },
3709
3710
3711     easeBothStrong: function (t, b, c, d) {
3712         if ((t /= d / 2) < 1) {
3713             return c / 2 * t * t * t * t + b;
3714         }
3715
3716         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3717     },
3718
3719
3720
3721     elasticIn: function (t, b, c, d, a, p) {
3722         if (t == 0) {
3723             return b;
3724         }
3725         if ((t /= d) == 1) {
3726             return b + c;
3727         }
3728         if (!p) {
3729             p = d * .3;
3730         }
3731
3732         if (!a || a < Math.abs(c)) {
3733             a = c;
3734             var s = p / 4;
3735         }
3736         else {
3737             var s = p / (2 * Math.PI) * Math.asin(c / a);
3738         }
3739
3740         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3741     },
3742
3743
3744     elasticOut: function (t, b, c, d, a, p) {
3745         if (t == 0) {
3746             return b;
3747         }
3748         if ((t /= d) == 1) {
3749             return b + c;
3750         }
3751         if (!p) {
3752             p = d * .3;
3753         }
3754
3755         if (!a || a < Math.abs(c)) {
3756             a = c;
3757             var s = p / 4;
3758         }
3759         else {
3760             var s = p / (2 * Math.PI) * Math.asin(c / a);
3761         }
3762
3763         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3764     },
3765
3766
3767     elasticBoth: function (t, b, c, d, a, p) {
3768         if (t == 0) {
3769             return b;
3770         }
3771
3772         if ((t /= d / 2) == 2) {
3773             return b + c;
3774         }
3775
3776         if (!p) {
3777             p = d * (.3 * 1.5);
3778         }
3779
3780         if (!a || a < Math.abs(c)) {
3781             a = c;
3782             var s = p / 4;
3783         }
3784         else {
3785             var s = p / (2 * Math.PI) * Math.asin(c / a);
3786         }
3787
3788         if (t < 1) {
3789             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3790                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3791         }
3792         return a * Math.pow(2, -10 * (t -= 1)) *
3793                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3794     },
3795
3796
3797
3798     backIn: function (t, b, c, d, s) {
3799         if (typeof s == 'undefined') {
3800             s = 1.70158;
3801         }
3802         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3803     },
3804
3805
3806     backOut: function (t, b, c, d, s) {
3807         if (typeof s == 'undefined') {
3808             s = 1.70158;
3809         }
3810         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3811     },
3812
3813
3814     backBoth: function (t, b, c, d, s) {
3815         if (typeof s == 'undefined') {
3816             s = 1.70158;
3817         }
3818
3819         if ((t /= d / 2 ) < 1) {
3820             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3821         }
3822         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3823     },
3824
3825
3826     bounceIn: function (t, b, c, d) {
3827         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3828     },
3829
3830
3831     bounceOut: function (t, b, c, d) {
3832         if ((t /= d) < (1 / 2.75)) {
3833             return c * (7.5625 * t * t) + b;
3834         } else if (t < (2 / 2.75)) {
3835             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3836         } else if (t < (2.5 / 2.75)) {
3837             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3838         }
3839         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3840     },
3841
3842
3843     bounceBoth: function (t, b, c, d) {
3844         if (t < d / 2) {
3845             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3846         }
3847         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3848     }
3849 };/*
3850  * Portions of this file are based on pieces of Yahoo User Interface Library
3851  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3852  * YUI licensed under the BSD License:
3853  * http://developer.yahoo.net/yui/license.txt
3854  * <script type="text/javascript">
3855  *
3856  */
3857     (function() {
3858         Roo.lib.Motion = function(el, attributes, duration, method) {
3859             if (el) {
3860                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3861             }
3862         };
3863
3864         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3865
3866
3867         var Y = Roo.lib;
3868         var superclass = Y.Motion.superclass;
3869         var proto = Y.Motion.prototype;
3870
3871         proto.toString = function() {
3872             var el = this.getEl();
3873             var id = el.id || el.tagName;
3874             return ("Motion " + id);
3875         };
3876
3877         proto.patterns.points = /^points$/i;
3878
3879         proto.setAttribute = function(attr, val, unit) {
3880             if (this.patterns.points.test(attr)) {
3881                 unit = unit || 'px';
3882                 superclass.setAttribute.call(this, 'left', val[0], unit);
3883                 superclass.setAttribute.call(this, 'top', val[1], unit);
3884             } else {
3885                 superclass.setAttribute.call(this, attr, val, unit);
3886             }
3887         };
3888
3889         proto.getAttribute = function(attr) {
3890             if (this.patterns.points.test(attr)) {
3891                 var val = [
3892                         superclass.getAttribute.call(this, 'left'),
3893                         superclass.getAttribute.call(this, 'top')
3894                         ];
3895             } else {
3896                 val = superclass.getAttribute.call(this, attr);
3897             }
3898
3899             return val;
3900         };
3901
3902         proto.doMethod = function(attr, start, end) {
3903             var val = null;
3904
3905             if (this.patterns.points.test(attr)) {
3906                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3907                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3908             } else {
3909                 val = superclass.doMethod.call(this, attr, start, end);
3910             }
3911             return val;
3912         };
3913
3914         proto.setRuntimeAttribute = function(attr) {
3915             if (this.patterns.points.test(attr)) {
3916                 var el = this.getEl();
3917                 var attributes = this.attributes;
3918                 var start;
3919                 var control = attributes['points']['control'] || [];
3920                 var end;
3921                 var i, len;
3922
3923                 if (control.length > 0 && !(control[0] instanceof Array)) {
3924                     control = [control];
3925                 } else {
3926                     var tmp = [];
3927                     for (i = 0,len = control.length; i < len; ++i) {
3928                         tmp[i] = control[i];
3929                     }
3930                     control = tmp;
3931                 }
3932
3933                 Roo.fly(el).position();
3934
3935                 if (isset(attributes['points']['from'])) {
3936                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3937                 }
3938                 else {
3939                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3940                 }
3941
3942                 start = this.getAttribute('points');
3943
3944
3945                 if (isset(attributes['points']['to'])) {
3946                     end = translateValues.call(this, attributes['points']['to'], start);
3947
3948                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3949                     for (i = 0,len = control.length; i < len; ++i) {
3950                         control[i] = translateValues.call(this, control[i], start);
3951                     }
3952
3953
3954                 } else if (isset(attributes['points']['by'])) {
3955                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3956
3957                     for (i = 0,len = control.length; i < len; ++i) {
3958                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3959                     }
3960                 }
3961
3962                 this.runtimeAttributes[attr] = [start];
3963
3964                 if (control.length > 0) {
3965                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3966                 }
3967
3968                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3969             }
3970             else {
3971                 superclass.setRuntimeAttribute.call(this, attr);
3972             }
3973         };
3974
3975         var translateValues = function(val, start) {
3976             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3978
3979             return val;
3980         };
3981
3982         var isset = function(prop) {
3983             return (typeof prop !== 'undefined');
3984         };
3985     })();
3986 /*
3987  * Portions of this file are based on pieces of Yahoo User Interface Library
3988  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3989  * YUI licensed under the BSD License:
3990  * http://developer.yahoo.net/yui/license.txt
3991  * <script type="text/javascript">
3992  *
3993  */
3994     (function() {
3995         Roo.lib.Scroll = function(el, attributes, duration, method) {
3996             if (el) {
3997                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3998             }
3999         };
4000
4001         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4002
4003
4004         var Y = Roo.lib;
4005         var superclass = Y.Scroll.superclass;
4006         var proto = Y.Scroll.prototype;
4007
4008         proto.toString = function() {
4009             var el = this.getEl();
4010             var id = el.id || el.tagName;
4011             return ("Scroll " + id);
4012         };
4013
4014         proto.doMethod = function(attr, start, end) {
4015             var val = null;
4016
4017             if (attr == 'scroll') {
4018                 val = [
4019                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4020                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4021                         ];
4022
4023             } else {
4024                 val = superclass.doMethod.call(this, attr, start, end);
4025             }
4026             return val;
4027         };
4028
4029         proto.getAttribute = function(attr) {
4030             var val = null;
4031             var el = this.getEl();
4032
4033             if (attr == 'scroll') {
4034                 val = [ el.scrollLeft, el.scrollTop ];
4035             } else {
4036                 val = superclass.getAttribute.call(this, attr);
4037             }
4038
4039             return val;
4040         };
4041
4042         proto.setAttribute = function(attr, val, unit) {
4043             var el = this.getEl();
4044
4045             if (attr == 'scroll') {
4046                 el.scrollLeft = val[0];
4047                 el.scrollTop = val[1];
4048             } else {
4049                 superclass.setAttribute.call(this, attr, val, unit);
4050             }
4051         };
4052     })();
4053 /*
4054  * Based on:
4055  * Ext JS Library 1.1.1
4056  * Copyright(c) 2006-2007, Ext JS, LLC.
4057  *
4058  * Originally Released Under LGPL - original licence link has changed is not relivant.
4059  *
4060  * Fork - LGPL
4061  * <script type="text/javascript">
4062  */
4063
4064
4065 // nasty IE9 hack - what a pile of crap that is..
4066
4067  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4068     Range.prototype.createContextualFragment = function (html) {
4069         var doc = window.document;
4070         var container = doc.createElement("div");
4071         container.innerHTML = html;
4072         var frag = doc.createDocumentFragment(), n;
4073         while ((n = container.firstChild)) {
4074             frag.appendChild(n);
4075         }
4076         return frag;
4077     };
4078 }
4079
4080 /**
4081  * @class Roo.DomHelper
4082  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4083  * 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>.
4084  * @singleton
4085  */
4086 Roo.DomHelper = function(){
4087     var tempTableEl = null;
4088     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4089     var tableRe = /^table|tbody|tr|td$/i;
4090     var xmlns = {};
4091     // build as innerHTML where available
4092     /** @ignore */
4093     var createHtml = function(o){
4094         if(typeof o == 'string'){
4095             return o;
4096         }
4097         var b = "";
4098         if(!o.tag){
4099             o.tag = "div";
4100         }
4101         b += "<" + o.tag;
4102         for(var attr in o){
4103             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4104             if(attr == "style"){
4105                 var s = o["style"];
4106                 if(typeof s == "function"){
4107                     s = s.call();
4108                 }
4109                 if(typeof s == "string"){
4110                     b += ' style="' + s + '"';
4111                 }else if(typeof s == "object"){
4112                     b += ' style="';
4113                     for(var key in s){
4114                         if(typeof s[key] != "function"){
4115                             b += key + ":" + s[key] + ";";
4116                         }
4117                     }
4118                     b += '"';
4119                 }
4120             }else{
4121                 if(attr == "cls"){
4122                     b += ' class="' + o["cls"] + '"';
4123                 }else if(attr == "htmlFor"){
4124                     b += ' for="' + o["htmlFor"] + '"';
4125                 }else{
4126                     b += " " + attr + '="' + o[attr] + '"';
4127                 }
4128             }
4129         }
4130         if(emptyTags.test(o.tag)){
4131             b += "/>";
4132         }else{
4133             b += ">";
4134             var cn = o.children || o.cn;
4135             if(cn){
4136                 //http://bugs.kde.org/show_bug.cgi?id=71506
4137                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4138                     for(var i = 0, len = cn.length; i < len; i++) {
4139                         b += createHtml(cn[i], b);
4140                     }
4141                 }else{
4142                     b += createHtml(cn, b);
4143                 }
4144             }
4145             if(o.html){
4146                 b += o.html;
4147             }
4148             b += "</" + o.tag + ">";
4149         }
4150         return b;
4151     };
4152
4153     // build as dom
4154     /** @ignore */
4155     var createDom = function(o, parentNode){
4156          
4157         // defininition craeted..
4158         var ns = false;
4159         if (o.ns && o.ns != 'html') {
4160                
4161             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4162                 xmlns[o.ns] = o.xmlns;
4163                 ns = o.xmlns;
4164             }
4165             if (typeof(xmlns[o.ns]) == 'undefined') {
4166                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4167             }
4168             ns = xmlns[o.ns];
4169         }
4170         
4171         
4172         if (typeof(o) == 'string') {
4173             return parentNode.appendChild(document.createTextNode(o));
4174         }
4175         o.tag = o.tag || div;
4176         if (o.ns && Roo.isIE) {
4177             ns = false;
4178             o.tag = o.ns + ':' + o.tag;
4179             
4180         }
4181         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4182         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4183         for(var attr in o){
4184             
4185             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4186                     attr == "style" || typeof o[attr] == "function") continue;
4187                     
4188             if(attr=="cls" && Roo.isIE){
4189                 el.className = o["cls"];
4190             }else{
4191                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4192                 else el[attr] = o[attr];
4193             }
4194         }
4195         Roo.DomHelper.applyStyles(el, o.style);
4196         var cn = o.children || o.cn;
4197         if(cn){
4198             //http://bugs.kde.org/show_bug.cgi?id=71506
4199              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4200                 for(var i = 0, len = cn.length; i < len; i++) {
4201                     createDom(cn[i], el);
4202                 }
4203             }else{
4204                 createDom(cn, el);
4205             }
4206         }
4207         if(o.html){
4208             el.innerHTML = o.html;
4209         }
4210         if(parentNode){
4211            parentNode.appendChild(el);
4212         }
4213         return el;
4214     };
4215
4216     var ieTable = function(depth, s, h, e){
4217         tempTableEl.innerHTML = [s, h, e].join('');
4218         var i = -1, el = tempTableEl;
4219         while(++i < depth){
4220             el = el.firstChild;
4221         }
4222         return el;
4223     };
4224
4225     // kill repeat to save bytes
4226     var ts = '<table>',
4227         te = '</table>',
4228         tbs = ts+'<tbody>',
4229         tbe = '</tbody>'+te,
4230         trs = tbs + '<tr>',
4231         tre = '</tr>'+tbe;
4232
4233     /**
4234      * @ignore
4235      * Nasty code for IE's broken table implementation
4236      */
4237     var insertIntoTable = function(tag, where, el, html){
4238         if(!tempTableEl){
4239             tempTableEl = document.createElement('div');
4240         }
4241         var node;
4242         var before = null;
4243         if(tag == 'td'){
4244             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4245                 return;
4246             }
4247             if(where == 'beforebegin'){
4248                 before = el;
4249                 el = el.parentNode;
4250             } else{
4251                 before = el.nextSibling;
4252                 el = el.parentNode;
4253             }
4254             node = ieTable(4, trs, html, tre);
4255         }
4256         else if(tag == 'tr'){
4257             if(where == 'beforebegin'){
4258                 before = el;
4259                 el = el.parentNode;
4260                 node = ieTable(3, tbs, html, tbe);
4261             } else if(where == 'afterend'){
4262                 before = el.nextSibling;
4263                 el = el.parentNode;
4264                 node = ieTable(3, tbs, html, tbe);
4265             } else{ // INTO a TR
4266                 if(where == 'afterbegin'){
4267                     before = el.firstChild;
4268                 }
4269                 node = ieTable(4, trs, html, tre);
4270             }
4271         } else if(tag == 'tbody'){
4272             if(where == 'beforebegin'){
4273                 before = el;
4274                 el = el.parentNode;
4275                 node = ieTable(2, ts, html, te);
4276             } else if(where == 'afterend'){
4277                 before = el.nextSibling;
4278                 el = el.parentNode;
4279                 node = ieTable(2, ts, html, te);
4280             } else{
4281                 if(where == 'afterbegin'){
4282                     before = el.firstChild;
4283                 }
4284                 node = ieTable(3, tbs, html, tbe);
4285             }
4286         } else{ // TABLE
4287             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4288                 return;
4289             }
4290             if(where == 'afterbegin'){
4291                 before = el.firstChild;
4292             }
4293             node = ieTable(2, ts, html, te);
4294         }
4295         el.insertBefore(node, before);
4296         return node;
4297     };
4298
4299     return {
4300     /** True to force the use of DOM instead of html fragments @type Boolean */
4301     useDom : false,
4302
4303     /**
4304      * Returns the markup for the passed Element(s) config
4305      * @param {Object} o The Dom object spec (and children)
4306      * @return {String}
4307      */
4308     markup : function(o){
4309         return createHtml(o);
4310     },
4311
4312     /**
4313      * Applies a style specification to an element
4314      * @param {String/HTMLElement} el The element to apply styles to
4315      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4316      * a function which returns such a specification.
4317      */
4318     applyStyles : function(el, styles){
4319         if(styles){
4320            el = Roo.fly(el);
4321            if(typeof styles == "string"){
4322                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4323                var matches;
4324                while ((matches = re.exec(styles)) != null){
4325                    el.setStyle(matches[1], matches[2]);
4326                }
4327            }else if (typeof styles == "object"){
4328                for (var style in styles){
4329                   el.setStyle(style, styles[style]);
4330                }
4331            }else if (typeof styles == "function"){
4332                 Roo.DomHelper.applyStyles(el, styles.call());
4333            }
4334         }
4335     },
4336
4337     /**
4338      * Inserts an HTML fragment into the Dom
4339      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4340      * @param {HTMLElement} el The context element
4341      * @param {String} html The HTML fragmenet
4342      * @return {HTMLElement} The new node
4343      */
4344     insertHtml : function(where, el, html){
4345         where = where.toLowerCase();
4346         if(el.insertAdjacentHTML){
4347             if(tableRe.test(el.tagName)){
4348                 var rs;
4349                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4350                     return rs;
4351                 }
4352             }
4353             switch(where){
4354                 case "beforebegin":
4355                     el.insertAdjacentHTML('BeforeBegin', html);
4356                     return el.previousSibling;
4357                 case "afterbegin":
4358                     el.insertAdjacentHTML('AfterBegin', html);
4359                     return el.firstChild;
4360                 case "beforeend":
4361                     el.insertAdjacentHTML('BeforeEnd', html);
4362                     return el.lastChild;
4363                 case "afterend":
4364                     el.insertAdjacentHTML('AfterEnd', html);
4365                     return el.nextSibling;
4366             }
4367             throw 'Illegal insertion point -> "' + where + '"';
4368         }
4369         var range = el.ownerDocument.createRange();
4370         var frag;
4371         switch(where){
4372              case "beforebegin":
4373                 range.setStartBefore(el);
4374                 frag = range.createContextualFragment(html);
4375                 el.parentNode.insertBefore(frag, el);
4376                 return el.previousSibling;
4377              case "afterbegin":
4378                 if(el.firstChild){
4379                     range.setStartBefore(el.firstChild);
4380                     frag = range.createContextualFragment(html);
4381                     el.insertBefore(frag, el.firstChild);
4382                     return el.firstChild;
4383                 }else{
4384                     el.innerHTML = html;
4385                     return el.firstChild;
4386                 }
4387             case "beforeend":
4388                 if(el.lastChild){
4389                     range.setStartAfter(el.lastChild);
4390                     frag = range.createContextualFragment(html);
4391                     el.appendChild(frag);
4392                     return el.lastChild;
4393                 }else{
4394                     el.innerHTML = html;
4395                     return el.lastChild;
4396                 }
4397             case "afterend":
4398                 range.setStartAfter(el);
4399                 frag = range.createContextualFragment(html);
4400                 el.parentNode.insertBefore(frag, el.nextSibling);
4401                 return el.nextSibling;
4402             }
4403             throw 'Illegal insertion point -> "' + where + '"';
4404     },
4405
4406     /**
4407      * Creates new Dom element(s) and inserts them before el
4408      * @param {String/HTMLElement/Element} el The context element
4409      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4410      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4411      * @return {HTMLElement/Roo.Element} The new node
4412      */
4413     insertBefore : function(el, o, returnElement){
4414         return this.doInsert(el, o, returnElement, "beforeBegin");
4415     },
4416
4417     /**
4418      * Creates new Dom element(s) and inserts them after el
4419      * @param {String/HTMLElement/Element} el The context element
4420      * @param {Object} o The Dom object spec (and children)
4421      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4422      * @return {HTMLElement/Roo.Element} The new node
4423      */
4424     insertAfter : function(el, o, returnElement){
4425         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4426     },
4427
4428     /**
4429      * Creates new Dom element(s) and inserts them as the first child of el
4430      * @param {String/HTMLElement/Element} el The context element
4431      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4432      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4433      * @return {HTMLElement/Roo.Element} The new node
4434      */
4435     insertFirst : function(el, o, returnElement){
4436         return this.doInsert(el, o, returnElement, "afterBegin");
4437     },
4438
4439     // private
4440     doInsert : function(el, o, returnElement, pos, sibling){
4441         el = Roo.getDom(el);
4442         var newNode;
4443         if(this.useDom || o.ns){
4444             newNode = createDom(o, null);
4445             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4446         }else{
4447             var html = createHtml(o);
4448             newNode = this.insertHtml(pos, el, html);
4449         }
4450         return returnElement ? Roo.get(newNode, true) : newNode;
4451     },
4452
4453     /**
4454      * Creates new Dom element(s) and appends them to el
4455      * @param {String/HTMLElement/Element} el The context element
4456      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4457      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4458      * @return {HTMLElement/Roo.Element} The new node
4459      */
4460     append : function(el, o, returnElement){
4461         el = Roo.getDom(el);
4462         var newNode;
4463         if(this.useDom || o.ns){
4464             newNode = createDom(o, null);
4465             el.appendChild(newNode);
4466         }else{
4467             var html = createHtml(o);
4468             newNode = this.insertHtml("beforeEnd", el, html);
4469         }
4470         return returnElement ? Roo.get(newNode, true) : newNode;
4471     },
4472
4473     /**
4474      * Creates new Dom element(s) and overwrites the contents of el with them
4475      * @param {String/HTMLElement/Element} el The context element
4476      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4477      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4478      * @return {HTMLElement/Roo.Element} The new node
4479      */
4480     overwrite : function(el, o, returnElement){
4481         el = Roo.getDom(el);
4482         if (o.ns) {
4483           
4484             while (el.childNodes.length) {
4485                 el.removeChild(el.firstChild);
4486             }
4487             createDom(o, el);
4488         } else {
4489             el.innerHTML = createHtml(o);   
4490         }
4491         
4492         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4493     },
4494
4495     /**
4496      * Creates a new Roo.DomHelper.Template from the Dom object spec
4497      * @param {Object} o The Dom object spec (and children)
4498      * @return {Roo.DomHelper.Template} The new template
4499      */
4500     createTemplate : function(o){
4501         var html = createHtml(o);
4502         return new Roo.Template(html);
4503     }
4504     };
4505 }();
4506 /*
4507  * Based on:
4508  * Ext JS Library 1.1.1
4509  * Copyright(c) 2006-2007, Ext JS, LLC.
4510  *
4511  * Originally Released Under LGPL - original licence link has changed is not relivant.
4512  *
4513  * Fork - LGPL
4514  * <script type="text/javascript">
4515  */
4516  
4517 /**
4518 * @class Roo.Template
4519 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4520 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4521 * Usage:
4522 <pre><code>
4523 var t = new Roo.Template({
4524     html :  '&lt;div name="{id}"&gt;' + 
4525         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4526         '&lt;/div&gt;',
4527     myformat: function (value, allValues) {
4528         return 'XX' + value;
4529     }
4530 });
4531 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4532 </code></pre>
4533 * For more information see this blog post with examples:
4534 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4535      - Create Elements using DOM, HTML fragments and Templates</a>. 
4536 * @constructor
4537 * @param {Object} cfg - Configuration object.
4538 */
4539 Roo.Template = function(cfg){
4540     // BC!
4541     if(cfg instanceof Array){
4542         cfg = cfg.join("");
4543     }else if(arguments.length > 1){
4544         cfg = Array.prototype.join.call(arguments, "");
4545     }
4546     
4547     
4548     if (typeof(cfg) == 'object') {
4549         Roo.apply(this,cfg)
4550     } else {
4551         // bc
4552         this.html = cfg;
4553     }
4554     if (this.url) {
4555         this.load();
4556     }
4557     
4558 };
4559 Roo.Template.prototype = {
4560     
4561     /**
4562      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4563      *                    it should be fixed so that template is observable...
4564      */
4565     url : false,
4566     /**
4567      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4568      */
4569     html : '',
4570     /**
4571      * Returns an HTML fragment of this template with the specified values applied.
4572      * @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'})
4573      * @return {String} The HTML fragment
4574      */
4575     applyTemplate : function(values){
4576         try {
4577            
4578             if(this.compiled){
4579                 return this.compiled(values);
4580             }
4581             var useF = this.disableFormats !== true;
4582             var fm = Roo.util.Format, tpl = this;
4583             var fn = function(m, name, format, args){
4584                 if(format && useF){
4585                     if(format.substr(0, 5) == "this."){
4586                         return tpl.call(format.substr(5), values[name], values);
4587                     }else{
4588                         if(args){
4589                             // quoted values are required for strings in compiled templates, 
4590                             // but for non compiled we need to strip them
4591                             // quoted reversed for jsmin
4592                             var re = /^\s*['"](.*)["']\s*$/;
4593                             args = args.split(',');
4594                             for(var i = 0, len = args.length; i < len; i++){
4595                                 args[i] = args[i].replace(re, "$1");
4596                             }
4597                             args = [values[name]].concat(args);
4598                         }else{
4599                             args = [values[name]];
4600                         }
4601                         return fm[format].apply(fm, args);
4602                     }
4603                 }else{
4604                     return values[name] !== undefined ? values[name] : "";
4605                 }
4606             };
4607             return this.html.replace(this.re, fn);
4608         } catch (e) {
4609             Roo.log(e);
4610             throw e;
4611         }
4612          
4613     },
4614     
4615     loading : false,
4616       
4617     load : function ()
4618     {
4619          
4620         if (this.loading) {
4621             return;
4622         }
4623         var _t = this;
4624         
4625         this.loading = true;
4626         this.compiled = false;
4627         
4628         var cx = new Roo.data.Connection();
4629         cx.request({
4630             url : this.url,
4631             method : 'GET',
4632             success : function (response) {
4633                 _t.loading = false;
4634                 _t.html = response.responseText;
4635                 _t.url = false;
4636                 _this.compile();
4637              },
4638             failure : function(response) {
4639                 Roo.log("Template failed to load from " + url);
4640                 _t.loading = false;
4641             }
4642         });
4643     },
4644
4645     /**
4646      * Sets the HTML used as the template and optionally compiles it.
4647      * @param {String} html
4648      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4649      * @return {Roo.Template} this
4650      */
4651     set : function(html, compile){
4652         this.html = html;
4653         this.compiled = null;
4654         if(compile){
4655             this.compile();
4656         }
4657         return this;
4658     },
4659     
4660     /**
4661      * True to disable format functions (defaults to false)
4662      * @type Boolean
4663      */
4664     disableFormats : false,
4665     
4666     /**
4667     * The regular expression used to match template variables 
4668     * @type RegExp
4669     * @property 
4670     */
4671     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4672     
4673     /**
4674      * Compiles the template into an internal function, eliminating the RegEx overhead.
4675      * @return {Roo.Template} this
4676      */
4677     compile : function(){
4678         var fm = Roo.util.Format;
4679         var useF = this.disableFormats !== true;
4680         var sep = Roo.isGecko ? "+" : ",";
4681         var fn = function(m, name, format, args){
4682             if(format && useF){
4683                 args = args ? ',' + args : "";
4684                 if(format.substr(0, 5) != "this."){
4685                     format = "fm." + format + '(';
4686                 }else{
4687                     format = 'this.call("'+ format.substr(5) + '", ';
4688                     args = ", values";
4689                 }
4690             }else{
4691                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4692             }
4693             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4694         };
4695         var body;
4696         // branched to use + in gecko and [].join() in others
4697         if(Roo.isGecko){
4698             body = "this.compiled = function(values){ return '" +
4699                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4700                     "';};";
4701         }else{
4702             body = ["this.compiled = function(values){ return ['"];
4703             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4704             body.push("'].join('');};");
4705             body = body.join('');
4706         }
4707         /**
4708          * eval:var:values
4709          * eval:var:fm
4710          */
4711         eval(body);
4712         return this;
4713     },
4714     
4715     // private function used to call members
4716     call : function(fnName, value, allValues){
4717         return this[fnName](value, allValues);
4718     },
4719     
4720     /**
4721      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4722      * @param {String/HTMLElement/Roo.Element} el The context element
4723      * @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'})
4724      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4725      * @return {HTMLElement/Roo.Element} The new node or Element
4726      */
4727     insertFirst: function(el, values, returnElement){
4728         return this.doInsert('afterBegin', el, values, returnElement);
4729     },
4730
4731     /**
4732      * Applies the supplied values to the template and inserts the new node(s) before el.
4733      * @param {String/HTMLElement/Roo.Element} el The context element
4734      * @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'})
4735      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4736      * @return {HTMLElement/Roo.Element} The new node or Element
4737      */
4738     insertBefore: function(el, values, returnElement){
4739         return this.doInsert('beforeBegin', el, values, returnElement);
4740     },
4741
4742     /**
4743      * Applies the supplied values to the template and inserts the new node(s) after el.
4744      * @param {String/HTMLElement/Roo.Element} el The context element
4745      * @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'})
4746      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4747      * @return {HTMLElement/Roo.Element} The new node or Element
4748      */
4749     insertAfter : function(el, values, returnElement){
4750         return this.doInsert('afterEnd', el, values, returnElement);
4751     },
4752     
4753     /**
4754      * Applies the supplied values to the template and appends the new node(s) to el.
4755      * @param {String/HTMLElement/Roo.Element} el The context element
4756      * @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'})
4757      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4758      * @return {HTMLElement/Roo.Element} The new node or Element
4759      */
4760     append : function(el, values, returnElement){
4761         return this.doInsert('beforeEnd', el, values, returnElement);
4762     },
4763
4764     doInsert : function(where, el, values, returnEl){
4765         el = Roo.getDom(el);
4766         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4767         return returnEl ? Roo.get(newNode, true) : newNode;
4768     },
4769
4770     /**
4771      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4772      * @param {String/HTMLElement/Roo.Element} el The context element
4773      * @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'})
4774      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775      * @return {HTMLElement/Roo.Element} The new node or Element
4776      */
4777     overwrite : function(el, values, returnElement){
4778         el = Roo.getDom(el);
4779         el.innerHTML = this.applyTemplate(values);
4780         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4781     }
4782 };
4783 /**
4784  * Alias for {@link #applyTemplate}
4785  * @method
4786  */
4787 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4788
4789 // backwards compat
4790 Roo.DomHelper.Template = Roo.Template;
4791
4792 /**
4793  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4794  * @param {String/HTMLElement} el A DOM element or its id
4795  * @returns {Roo.Template} The created template
4796  * @static
4797  */
4798 Roo.Template.from = function(el){
4799     el = Roo.getDom(el);
4800     return new Roo.Template(el.value || el.innerHTML);
4801 };/*
4802  * Based on:
4803  * Ext JS Library 1.1.1
4804  * Copyright(c) 2006-2007, Ext JS, LLC.
4805  *
4806  * Originally Released Under LGPL - original licence link has changed is not relivant.
4807  *
4808  * Fork - LGPL
4809  * <script type="text/javascript">
4810  */
4811  
4812
4813 /*
4814  * This is code is also distributed under MIT license for use
4815  * with jQuery and prototype JavaScript libraries.
4816  */
4817 /**
4818  * @class Roo.DomQuery
4819 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).
4820 <p>
4821 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>
4822
4823 <p>
4824 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.
4825 </p>
4826 <h4>Element Selectors:</h4>
4827 <ul class="list">
4828     <li> <b>*</b> any element</li>
4829     <li> <b>E</b> an element with the tag E</li>
4830     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4831     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4832     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4833     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4834 </ul>
4835 <h4>Attribute Selectors:</h4>
4836 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4837 <ul class="list">
4838     <li> <b>E[foo]</b> has an attribute "foo"</li>
4839     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4840     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4841     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4842     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4843     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4844     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4845 </ul>
4846 <h4>Pseudo Classes:</h4>
4847 <ul class="list">
4848     <li> <b>E:first-child</b> E is the first child of its parent</li>
4849     <li> <b>E:last-child</b> E is the last child of its parent</li>
4850     <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>
4851     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4852     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4853     <li> <b>E:only-child</b> E is the only child of its parent</li>
4854     <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>
4855     <li> <b>E:first</b> the first E in the resultset</li>
4856     <li> <b>E:last</b> the last E in the resultset</li>
4857     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4858     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4859     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4860     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4861     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4862     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4863     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4864     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4865     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4866 </ul>
4867 <h4>CSS Value Selectors:</h4>
4868 <ul class="list">
4869     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4870     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4871     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4872     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4873     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4874     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4875 </ul>
4876  * @singleton
4877  */
4878 Roo.DomQuery = function(){
4879     var cache = {}, simpleCache = {}, valueCache = {};
4880     var nonSpace = /\S/;
4881     var trimRe = /^\s+|\s+$/g;
4882     var tplRe = /\{(\d+)\}/g;
4883     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4884     var tagTokenRe = /^(#)?([\w-\*]+)/;
4885     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4886
4887     function child(p, index){
4888         var i = 0;
4889         var n = p.firstChild;
4890         while(n){
4891             if(n.nodeType == 1){
4892                if(++i == index){
4893                    return n;
4894                }
4895             }
4896             n = n.nextSibling;
4897         }
4898         return null;
4899     };
4900
4901     function next(n){
4902         while((n = n.nextSibling) && n.nodeType != 1);
4903         return n;
4904     };
4905
4906     function prev(n){
4907         while((n = n.previousSibling) && n.nodeType != 1);
4908         return n;
4909     };
4910
4911     function children(d){
4912         var n = d.firstChild, ni = -1;
4913             while(n){
4914                 var nx = n.nextSibling;
4915                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4916                     d.removeChild(n);
4917                 }else{
4918                     n.nodeIndex = ++ni;
4919                 }
4920                 n = nx;
4921             }
4922             return this;
4923         };
4924
4925     function byClassName(c, a, v){
4926         if(!v){
4927             return c;
4928         }
4929         var r = [], ri = -1, cn;
4930         for(var i = 0, ci; ci = c[i]; i++){
4931             if((' '+ci.className+' ').indexOf(v) != -1){
4932                 r[++ri] = ci;
4933             }
4934         }
4935         return r;
4936     };
4937
4938     function attrValue(n, attr){
4939         if(!n.tagName && typeof n.length != "undefined"){
4940             n = n[0];
4941         }
4942         if(!n){
4943             return null;
4944         }
4945         if(attr == "for"){
4946             return n.htmlFor;
4947         }
4948         if(attr == "class" || attr == "className"){
4949             return n.className;
4950         }
4951         return n.getAttribute(attr) || n[attr];
4952
4953     };
4954
4955     function getNodes(ns, mode, tagName){
4956         var result = [], ri = -1, cs;
4957         if(!ns){
4958             return result;
4959         }
4960         tagName = tagName || "*";
4961         if(typeof ns.getElementsByTagName != "undefined"){
4962             ns = [ns];
4963         }
4964         if(!mode){
4965             for(var i = 0, ni; ni = ns[i]; i++){
4966                 cs = ni.getElementsByTagName(tagName);
4967                 for(var j = 0, ci; ci = cs[j]; j++){
4968                     result[++ri] = ci;
4969                 }
4970             }
4971         }else if(mode == "/" || mode == ">"){
4972             var utag = tagName.toUpperCase();
4973             for(var i = 0, ni, cn; ni = ns[i]; i++){
4974                 cn = ni.children || ni.childNodes;
4975                 for(var j = 0, cj; cj = cn[j]; j++){
4976                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4977                         result[++ri] = cj;
4978                     }
4979                 }
4980             }
4981         }else if(mode == "+"){
4982             var utag = tagName.toUpperCase();
4983             for(var i = 0, n; n = ns[i]; i++){
4984                 while((n = n.nextSibling) && n.nodeType != 1);
4985                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4986                     result[++ri] = n;
4987                 }
4988             }
4989         }else if(mode == "~"){
4990             for(var i = 0, n; n = ns[i]; i++){
4991                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4992                 if(n){
4993                     result[++ri] = n;
4994                 }
4995             }
4996         }
4997         return result;
4998     };
4999
5000     function concat(a, b){
5001         if(b.slice){
5002             return a.concat(b);
5003         }
5004         for(var i = 0, l = b.length; i < l; i++){
5005             a[a.length] = b[i];
5006         }
5007         return a;
5008     }
5009
5010     function byTag(cs, tagName){
5011         if(cs.tagName || cs == document){
5012             cs = [cs];
5013         }
5014         if(!tagName){
5015             return cs;
5016         }
5017         var r = [], ri = -1;
5018         tagName = tagName.toLowerCase();
5019         for(var i = 0, ci; ci = cs[i]; i++){
5020             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5021                 r[++ri] = ci;
5022             }
5023         }
5024         return r;
5025     };
5026
5027     function byId(cs, attr, id){
5028         if(cs.tagName || cs == document){
5029             cs = [cs];
5030         }
5031         if(!id){
5032             return cs;
5033         }
5034         var r = [], ri = -1;
5035         for(var i = 0,ci; ci = cs[i]; i++){
5036             if(ci && ci.id == id){
5037                 r[++ri] = ci;
5038                 return r;
5039             }
5040         }
5041         return r;
5042     };
5043
5044     function byAttribute(cs, attr, value, op, custom){
5045         var r = [], ri = -1, st = custom=="{";
5046         var f = Roo.DomQuery.operators[op];
5047         for(var i = 0, ci; ci = cs[i]; i++){
5048             var a;
5049             if(st){
5050                 a = Roo.DomQuery.getStyle(ci, attr);
5051             }
5052             else if(attr == "class" || attr == "className"){
5053                 a = ci.className;
5054             }else if(attr == "for"){
5055                 a = ci.htmlFor;
5056             }else if(attr == "href"){
5057                 a = ci.getAttribute("href", 2);
5058             }else{
5059                 a = ci.getAttribute(attr);
5060             }
5061             if((f && f(a, value)) || (!f && a)){
5062                 r[++ri] = ci;
5063             }
5064         }
5065         return r;
5066     };
5067
5068     function byPseudo(cs, name, value){
5069         return Roo.DomQuery.pseudos[name](cs, value);
5070     };
5071
5072     // This is for IE MSXML which does not support expandos.
5073     // IE runs the same speed using setAttribute, however FF slows way down
5074     // and Safari completely fails so they need to continue to use expandos.
5075     var isIE = window.ActiveXObject ? true : false;
5076
5077     // this eval is stop the compressor from
5078     // renaming the variable to something shorter
5079     
5080     /** eval:var:batch */
5081     var batch = 30803; 
5082
5083     var key = 30803;
5084
5085     function nodupIEXml(cs){
5086         var d = ++key;
5087         cs[0].setAttribute("_nodup", d);
5088         var r = [cs[0]];
5089         for(var i = 1, len = cs.length; i < len; i++){
5090             var c = cs[i];
5091             if(!c.getAttribute("_nodup") != d){
5092                 c.setAttribute("_nodup", d);
5093                 r[r.length] = c;
5094             }
5095         }
5096         for(var i = 0, len = cs.length; i < len; i++){
5097             cs[i].removeAttribute("_nodup");
5098         }
5099         return r;
5100     }
5101
5102     function nodup(cs){
5103         if(!cs){
5104             return [];
5105         }
5106         var len = cs.length, c, i, r = cs, cj, ri = -1;
5107         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5108             return cs;
5109         }
5110         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5111             return nodupIEXml(cs);
5112         }
5113         var d = ++key;
5114         cs[0]._nodup = d;
5115         for(i = 1; c = cs[i]; i++){
5116             if(c._nodup != d){
5117                 c._nodup = d;
5118             }else{
5119                 r = [];
5120                 for(var j = 0; j < i; j++){
5121                     r[++ri] = cs[j];
5122                 }
5123                 for(j = i+1; cj = cs[j]; j++){
5124                     if(cj._nodup != d){
5125                         cj._nodup = d;
5126                         r[++ri] = cj;
5127                     }
5128                 }
5129                 return r;
5130             }
5131         }
5132         return r;
5133     }
5134
5135     function quickDiffIEXml(c1, c2){
5136         var d = ++key;
5137         for(var i = 0, len = c1.length; i < len; i++){
5138             c1[i].setAttribute("_qdiff", d);
5139         }
5140         var r = [];
5141         for(var i = 0, len = c2.length; i < len; i++){
5142             if(c2[i].getAttribute("_qdiff") != d){
5143                 r[r.length] = c2[i];
5144             }
5145         }
5146         for(var i = 0, len = c1.length; i < len; i++){
5147            c1[i].removeAttribute("_qdiff");
5148         }
5149         return r;
5150     }
5151
5152     function quickDiff(c1, c2){
5153         var len1 = c1.length;
5154         if(!len1){
5155             return c2;
5156         }
5157         if(isIE && c1[0].selectSingleNode){
5158             return quickDiffIEXml(c1, c2);
5159         }
5160         var d = ++key;
5161         for(var i = 0; i < len1; i++){
5162             c1[i]._qdiff = d;
5163         }
5164         var r = [];
5165         for(var i = 0, len = c2.length; i < len; i++){
5166             if(c2[i]._qdiff != d){
5167                 r[r.length] = c2[i];
5168             }
5169         }
5170         return r;
5171     }
5172
5173     function quickId(ns, mode, root, id){
5174         if(ns == root){
5175            var d = root.ownerDocument || root;
5176            return d.getElementById(id);
5177         }
5178         ns = getNodes(ns, mode, "*");
5179         return byId(ns, null, id);
5180     }
5181
5182     return {
5183         getStyle : function(el, name){
5184             return Roo.fly(el).getStyle(name);
5185         },
5186         /**
5187          * Compiles a selector/xpath query into a reusable function. The returned function
5188          * takes one parameter "root" (optional), which is the context node from where the query should start.
5189          * @param {String} selector The selector/xpath query
5190          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5191          * @return {Function}
5192          */
5193         compile : function(path, type){
5194             type = type || "select";
5195             
5196             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5197             var q = path, mode, lq;
5198             var tk = Roo.DomQuery.matchers;
5199             var tklen = tk.length;
5200             var mm;
5201
5202             // accept leading mode switch
5203             var lmode = q.match(modeRe);
5204             if(lmode && lmode[1]){
5205                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5206                 q = q.replace(lmode[1], "");
5207             }
5208             // strip leading slashes
5209             while(path.substr(0, 1)=="/"){
5210                 path = path.substr(1);
5211             }
5212
5213             while(q && lq != q){
5214                 lq = q;
5215                 var tm = q.match(tagTokenRe);
5216                 if(type == "select"){
5217                     if(tm){
5218                         if(tm[1] == "#"){
5219                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5220                         }else{
5221                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5222                         }
5223                         q = q.replace(tm[0], "");
5224                     }else if(q.substr(0, 1) != '@'){
5225                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5226                     }
5227                 }else{
5228                     if(tm){
5229                         if(tm[1] == "#"){
5230                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5231                         }else{
5232                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5233                         }
5234                         q = q.replace(tm[0], "");
5235                     }
5236                 }
5237                 while(!(mm = q.match(modeRe))){
5238                     var matched = false;
5239                     for(var j = 0; j < tklen; j++){
5240                         var t = tk[j];
5241                         var m = q.match(t.re);
5242                         if(m){
5243                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5244                                                     return m[i];
5245                                                 });
5246                             q = q.replace(m[0], "");
5247                             matched = true;
5248                             break;
5249                         }
5250                     }
5251                     // prevent infinite loop on bad selector
5252                     if(!matched){
5253                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5254                     }
5255                 }
5256                 if(mm[1]){
5257                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5258                     q = q.replace(mm[1], "");
5259                 }
5260             }
5261             fn[fn.length] = "return nodup(n);\n}";
5262             
5263              /** 
5264               * list of variables that need from compression as they are used by eval.
5265              *  eval:var:batch 
5266              *  eval:var:nodup
5267              *  eval:var:byTag
5268              *  eval:var:ById
5269              *  eval:var:getNodes
5270              *  eval:var:quickId
5271              *  eval:var:mode
5272              *  eval:var:root
5273              *  eval:var:n
5274              *  eval:var:byClassName
5275              *  eval:var:byPseudo
5276              *  eval:var:byAttribute
5277              *  eval:var:attrValue
5278              * 
5279              **/ 
5280             eval(fn.join(""));
5281             return f;
5282         },
5283
5284         /**
5285          * Selects a group of elements.
5286          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5287          * @param {Node} root (optional) The start of the query (defaults to document).
5288          * @return {Array}
5289          */
5290         select : function(path, root, type){
5291             if(!root || root == document){
5292                 root = document;
5293             }
5294             if(typeof root == "string"){
5295                 root = document.getElementById(root);
5296             }
5297             var paths = path.split(",");
5298             var results = [];
5299             for(var i = 0, len = paths.length; i < len; i++){
5300                 var p = paths[i].replace(trimRe, "");
5301                 if(!cache[p]){
5302                     cache[p] = Roo.DomQuery.compile(p);
5303                     if(!cache[p]){
5304                         throw p + " is not a valid selector";
5305                     }
5306                 }
5307                 var result = cache[p](root);
5308                 if(result && result != document){
5309                     results = results.concat(result);
5310                 }
5311             }
5312             if(paths.length > 1){
5313                 return nodup(results);
5314             }
5315             return results;
5316         },
5317
5318         /**
5319          * Selects a single element.
5320          * @param {String} selector The selector/xpath query
5321          * @param {Node} root (optional) The start of the query (defaults to document).
5322          * @return {Element}
5323          */
5324         selectNode : function(path, root){
5325             return Roo.DomQuery.select(path, root)[0];
5326         },
5327
5328         /**
5329          * Selects the value of a node, optionally replacing null with the defaultValue.
5330          * @param {String} selector The selector/xpath query
5331          * @param {Node} root (optional) The start of the query (defaults to document).
5332          * @param {String} defaultValue
5333          */
5334         selectValue : function(path, root, defaultValue){
5335             path = path.replace(trimRe, "");
5336             if(!valueCache[path]){
5337                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5338             }
5339             var n = valueCache[path](root);
5340             n = n[0] ? n[0] : n;
5341             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5342             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5343         },
5344
5345         /**
5346          * Selects the value of a node, parsing integers and floats.
5347          * @param {String} selector The selector/xpath query
5348          * @param {Node} root (optional) The start of the query (defaults to document).
5349          * @param {Number} defaultValue
5350          * @return {Number}
5351          */
5352         selectNumber : function(path, root, defaultValue){
5353             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5354             return parseFloat(v);
5355         },
5356
5357         /**
5358          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5359          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5360          * @param {String} selector The simple selector to test
5361          * @return {Boolean}
5362          */
5363         is : function(el, ss){
5364             if(typeof el == "string"){
5365                 el = document.getElementById(el);
5366             }
5367             var isArray = (el instanceof Array);
5368             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5369             return isArray ? (result.length == el.length) : (result.length > 0);
5370         },
5371
5372         /**
5373          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5374          * @param {Array} el An array of elements to filter
5375          * @param {String} selector The simple selector to test
5376          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5377          * the selector instead of the ones that match
5378          * @return {Array}
5379          */
5380         filter : function(els, ss, nonMatches){
5381             ss = ss.replace(trimRe, "");
5382             if(!simpleCache[ss]){
5383                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5384             }
5385             var result = simpleCache[ss](els);
5386             return nonMatches ? quickDiff(result, els) : result;
5387         },
5388
5389         /**
5390          * Collection of matching regular expressions and code snippets.
5391          */
5392         matchers : [{
5393                 re: /^\.([\w-]+)/,
5394                 select: 'n = byClassName(n, null, " {1} ");'
5395             }, {
5396                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5397                 select: 'n = byPseudo(n, "{1}", "{2}");'
5398             },{
5399                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5400                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5401             }, {
5402                 re: /^#([\w-]+)/,
5403                 select: 'n = byId(n, null, "{1}");'
5404             },{
5405                 re: /^@([\w-]+)/,
5406                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5407             }
5408         ],
5409
5410         /**
5411          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5412          * 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;.
5413          */
5414         operators : {
5415             "=" : function(a, v){
5416                 return a == v;
5417             },
5418             "!=" : function(a, v){
5419                 return a != v;
5420             },
5421             "^=" : function(a, v){
5422                 return a && a.substr(0, v.length) == v;
5423             },
5424             "$=" : function(a, v){
5425                 return a && a.substr(a.length-v.length) == v;
5426             },
5427             "*=" : function(a, v){
5428                 return a && a.indexOf(v) !== -1;
5429             },
5430             "%=" : function(a, v){
5431                 return (a % v) == 0;
5432             },
5433             "|=" : function(a, v){
5434                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5435             },
5436             "~=" : function(a, v){
5437                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5438             }
5439         },
5440
5441         /**
5442          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5443          * and the argument (if any) supplied in the selector.
5444          */
5445         pseudos : {
5446             "first-child" : function(c){
5447                 var r = [], ri = -1, n;
5448                 for(var i = 0, ci; ci = n = c[i]; i++){
5449                     while((n = n.previousSibling) && n.nodeType != 1);
5450                     if(!n){
5451                         r[++ri] = ci;
5452                     }
5453                 }
5454                 return r;
5455             },
5456
5457             "last-child" : function(c){
5458                 var r = [], ri = -1, n;
5459                 for(var i = 0, ci; ci = n = c[i]; i++){
5460                     while((n = n.nextSibling) && n.nodeType != 1);
5461                     if(!n){
5462                         r[++ri] = ci;
5463                     }
5464                 }
5465                 return r;
5466             },
5467
5468             "nth-child" : function(c, a) {
5469                 var r = [], ri = -1;
5470                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5471                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5472                 for(var i = 0, n; n = c[i]; i++){
5473                     var pn = n.parentNode;
5474                     if (batch != pn._batch) {
5475                         var j = 0;
5476                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5477                             if(cn.nodeType == 1){
5478                                cn.nodeIndex = ++j;
5479                             }
5480                         }
5481                         pn._batch = batch;
5482                     }
5483                     if (f == 1) {
5484                         if (l == 0 || n.nodeIndex == l){
5485                             r[++ri] = n;
5486                         }
5487                     } else if ((n.nodeIndex + l) % f == 0){
5488                         r[++ri] = n;
5489                     }
5490                 }
5491
5492                 return r;
5493             },
5494
5495             "only-child" : function(c){
5496                 var r = [], ri = -1;;
5497                 for(var i = 0, ci; ci = c[i]; i++){
5498                     if(!prev(ci) && !next(ci)){
5499                         r[++ri] = ci;
5500                     }
5501                 }
5502                 return r;
5503             },
5504
5505             "empty" : function(c){
5506                 var r = [], ri = -1;
5507                 for(var i = 0, ci; ci = c[i]; i++){
5508                     var cns = ci.childNodes, j = 0, cn, empty = true;
5509                     while(cn = cns[j]){
5510                         ++j;
5511                         if(cn.nodeType == 1 || cn.nodeType == 3){
5512                             empty = false;
5513                             break;
5514                         }
5515                     }
5516                     if(empty){
5517                         r[++ri] = ci;
5518                     }
5519                 }
5520                 return r;
5521             },
5522
5523             "contains" : function(c, v){
5524                 var r = [], ri = -1;
5525                 for(var i = 0, ci; ci = c[i]; i++){
5526                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5527                         r[++ri] = ci;
5528                     }
5529                 }
5530                 return r;
5531             },
5532
5533             "nodeValue" : function(c, v){
5534                 var r = [], ri = -1;
5535                 for(var i = 0, ci; ci = c[i]; i++){
5536                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5537                         r[++ri] = ci;
5538                     }
5539                 }
5540                 return r;
5541             },
5542
5543             "checked" : function(c){
5544                 var r = [], ri = -1;
5545                 for(var i = 0, ci; ci = c[i]; i++){
5546                     if(ci.checked == true){
5547                         r[++ri] = ci;
5548                     }
5549                 }
5550                 return r;
5551             },
5552
5553             "not" : function(c, ss){
5554                 return Roo.DomQuery.filter(c, ss, true);
5555             },
5556
5557             "odd" : function(c){
5558                 return this["nth-child"](c, "odd");
5559             },
5560
5561             "even" : function(c){
5562                 return this["nth-child"](c, "even");
5563             },
5564
5565             "nth" : function(c, a){
5566                 return c[a-1] || [];
5567             },
5568
5569             "first" : function(c){
5570                 return c[0] || [];
5571             },
5572
5573             "last" : function(c){
5574                 return c[c.length-1] || [];
5575             },
5576
5577             "has" : function(c, ss){
5578                 var s = Roo.DomQuery.select;
5579                 var r = [], ri = -1;
5580                 for(var i = 0, ci; ci = c[i]; i++){
5581                     if(s(ss, ci).length > 0){
5582                         r[++ri] = ci;
5583                     }
5584                 }
5585                 return r;
5586             },
5587
5588             "next" : function(c, ss){
5589                 var is = Roo.DomQuery.is;
5590                 var r = [], ri = -1;
5591                 for(var i = 0, ci; ci = c[i]; i++){
5592                     var n = next(ci);
5593                     if(n && is(n, ss)){
5594                         r[++ri] = ci;
5595                     }
5596                 }
5597                 return r;
5598             },
5599
5600             "prev" : function(c, ss){
5601                 var is = Roo.DomQuery.is;
5602                 var r = [], ri = -1;
5603                 for(var i = 0, ci; ci = c[i]; i++){
5604                     var n = prev(ci);
5605                     if(n && is(n, ss)){
5606                         r[++ri] = ci;
5607                     }
5608                 }
5609                 return r;
5610             }
5611         }
5612     };
5613 }();
5614
5615 /**
5616  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5617  * @param {String} path The selector/xpath query
5618  * @param {Node} root (optional) The start of the query (defaults to document).
5619  * @return {Array}
5620  * @member Roo
5621  * @method query
5622  */
5623 Roo.query = Roo.DomQuery.select;
5624 /*
5625  * Based on:
5626  * Ext JS Library 1.1.1
5627  * Copyright(c) 2006-2007, Ext JS, LLC.
5628  *
5629  * Originally Released Under LGPL - original licence link has changed is not relivant.
5630  *
5631  * Fork - LGPL
5632  * <script type="text/javascript">
5633  */
5634
5635 /**
5636  * @class Roo.util.Observable
5637  * Base class that provides a common interface for publishing events. Subclasses are expected to
5638  * to have a property "events" with all the events defined.<br>
5639  * For example:
5640  * <pre><code>
5641  Employee = function(name){
5642     this.name = name;
5643     this.addEvents({
5644         "fired" : true,
5645         "quit" : true
5646     });
5647  }
5648  Roo.extend(Employee, Roo.util.Observable);
5649 </code></pre>
5650  * @param {Object} config properties to use (incuding events / listeners)
5651  */
5652
5653 Roo.util.Observable = function(cfg){
5654     
5655     cfg = cfg|| {};
5656     this.addEvents(cfg.events || {});
5657     if (cfg.events) {
5658         delete cfg.events; // make sure
5659     }
5660      
5661     Roo.apply(this, cfg);
5662     
5663     if(this.listeners){
5664         this.on(this.listeners);
5665         delete this.listeners;
5666     }
5667 };
5668 Roo.util.Observable.prototype = {
5669     /** 
5670  * @cfg {Object} listeners  list of events and functions to call for this object, 
5671  * For example :
5672  * <pre><code>
5673     listeners :  { 
5674        'click' : function(e) {
5675            ..... 
5676         } ,
5677         .... 
5678     } 
5679   </code></pre>
5680  */
5681     
5682     
5683     /**
5684      * Fires the specified event with the passed parameters (minus the event name).
5685      * @param {String} eventName
5686      * @param {Object...} args Variable number of parameters are passed to handlers
5687      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5688      */
5689     fireEvent : function(){
5690         var ce = this.events[arguments[0].toLowerCase()];
5691         if(typeof ce == "object"){
5692             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5693         }else{
5694             return true;
5695         }
5696     },
5697
5698     // private
5699     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5700
5701     /**
5702      * Appends an event handler to this component
5703      * @param {String}   eventName The type of event to listen for
5704      * @param {Function} handler The method the event invokes
5705      * @param {Object}   scope (optional) The scope in which to execute the handler
5706      * function. The handler function's "this" context.
5707      * @param {Object}   options (optional) An object containing handler configuration
5708      * properties. This may contain any of the following properties:<ul>
5709      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5710      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5711      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5712      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5713      * by the specified number of milliseconds. If the event fires again within that time, the original
5714      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5715      * </ul><br>
5716      * <p>
5717      * <b>Combining Options</b><br>
5718      * Using the options argument, it is possible to combine different types of listeners:<br>
5719      * <br>
5720      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5721                 <pre><code>
5722                 el.on('click', this.onClick, this, {
5723                         single: true,
5724                 delay: 100,
5725                 forumId: 4
5726                 });
5727                 </code></pre>
5728      * <p>
5729      * <b>Attaching multiple handlers in 1 call</b><br>
5730      * The method also allows for a single argument to be passed which is a config object containing properties
5731      * which specify multiple handlers.
5732      * <pre><code>
5733                 el.on({
5734                         'click': {
5735                         fn: this.onClick,
5736                         scope: this,
5737                         delay: 100
5738                 }, 
5739                 'mouseover': {
5740                         fn: this.onMouseOver,
5741                         scope: this
5742                 },
5743                 'mouseout': {
5744                         fn: this.onMouseOut,
5745                         scope: this
5746                 }
5747                 });
5748                 </code></pre>
5749      * <p>
5750      * Or a shorthand syntax which passes the same scope object to all handlers:
5751         <pre><code>
5752                 el.on({
5753                         'click': this.onClick,
5754                 'mouseover': this.onMouseOver,
5755                 'mouseout': this.onMouseOut,
5756                 scope: this
5757                 });
5758                 </code></pre>
5759      */
5760     addListener : function(eventName, fn, scope, o){
5761         if(typeof eventName == "object"){
5762             o = eventName;
5763             for(var e in o){
5764                 if(this.filterOptRe.test(e)){
5765                     continue;
5766                 }
5767                 if(typeof o[e] == "function"){
5768                     // shared options
5769                     this.addListener(e, o[e], o.scope,  o);
5770                 }else{
5771                     // individual options
5772                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5773                 }
5774             }
5775             return;
5776         }
5777         o = (!o || typeof o == "boolean") ? {} : o;
5778         eventName = eventName.toLowerCase();
5779         var ce = this.events[eventName] || true;
5780         if(typeof ce == "boolean"){
5781             ce = new Roo.util.Event(this, eventName);
5782             this.events[eventName] = ce;
5783         }
5784         ce.addListener(fn, scope, o);
5785     },
5786
5787     /**
5788      * Removes a listener
5789      * @param {String}   eventName     The type of event to listen for
5790      * @param {Function} handler        The handler to remove
5791      * @param {Object}   scope  (optional) The scope (this object) for the handler
5792      */
5793     removeListener : function(eventName, fn, scope){
5794         var ce = this.events[eventName.toLowerCase()];
5795         if(typeof ce == "object"){
5796             ce.removeListener(fn, scope);
5797         }
5798     },
5799
5800     /**
5801      * Removes all listeners for this object
5802      */
5803     purgeListeners : function(){
5804         for(var evt in this.events){
5805             if(typeof this.events[evt] == "object"){
5806                  this.events[evt].clearListeners();
5807             }
5808         }
5809     },
5810
5811     relayEvents : function(o, events){
5812         var createHandler = function(ename){
5813             return function(){
5814                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5815             };
5816         };
5817         for(var i = 0, len = events.length; i < len; i++){
5818             var ename = events[i];
5819             if(!this.events[ename]){ this.events[ename] = true; };
5820             o.on(ename, createHandler(ename), this);
5821         }
5822     },
5823
5824     /**
5825      * Used to define events on this Observable
5826      * @param {Object} object The object with the events defined
5827      */
5828     addEvents : function(o){
5829         if(!this.events){
5830             this.events = {};
5831         }
5832         Roo.applyIf(this.events, o);
5833     },
5834
5835     /**
5836      * Checks to see if this object has any listeners for a specified event
5837      * @param {String} eventName The name of the event to check for
5838      * @return {Boolean} True if the event is being listened for, else false
5839      */
5840     hasListener : function(eventName){
5841         var e = this.events[eventName];
5842         return typeof e == "object" && e.listeners.length > 0;
5843     }
5844 };
5845 /**
5846  * Appends an event handler to this element (shorthand for addListener)
5847  * @param {String}   eventName     The type of event to listen for
5848  * @param {Function} handler        The method the event invokes
5849  * @param {Object}   scope (optional) The scope in which to execute the handler
5850  * function. The handler function's "this" context.
5851  * @param {Object}   options  (optional)
5852  * @method
5853  */
5854 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5855 /**
5856  * Removes a listener (shorthand for removeListener)
5857  * @param {String}   eventName     The type of event to listen for
5858  * @param {Function} handler        The handler to remove
5859  * @param {Object}   scope  (optional) The scope (this object) for the handler
5860  * @method
5861  */
5862 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5863
5864 /**
5865  * Starts capture on the specified Observable. All events will be passed
5866  * to the supplied function with the event name + standard signature of the event
5867  * <b>before</b> the event is fired. If the supplied function returns false,
5868  * the event will not fire.
5869  * @param {Observable} o The Observable to capture
5870  * @param {Function} fn The function to call
5871  * @param {Object} scope (optional) The scope (this object) for the fn
5872  * @static
5873  */
5874 Roo.util.Observable.capture = function(o, fn, scope){
5875     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5876 };
5877
5878 /**
5879  * Removes <b>all</b> added captures from the Observable.
5880  * @param {Observable} o The Observable to release
5881  * @static
5882  */
5883 Roo.util.Observable.releaseCapture = function(o){
5884     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5885 };
5886
5887 (function(){
5888
5889     var createBuffered = function(h, o, scope){
5890         var task = new Roo.util.DelayedTask();
5891         return function(){
5892             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5893         };
5894     };
5895
5896     var createSingle = function(h, e, fn, scope){
5897         return function(){
5898             e.removeListener(fn, scope);
5899             return h.apply(scope, arguments);
5900         };
5901     };
5902
5903     var createDelayed = function(h, o, scope){
5904         return function(){
5905             var args = Array.prototype.slice.call(arguments, 0);
5906             setTimeout(function(){
5907                 h.apply(scope, args);
5908             }, o.delay || 10);
5909         };
5910     };
5911
5912     Roo.util.Event = function(obj, name){
5913         this.name = name;
5914         this.obj = obj;
5915         this.listeners = [];
5916     };
5917
5918     Roo.util.Event.prototype = {
5919         addListener : function(fn, scope, options){
5920             var o = options || {};
5921             scope = scope || this.obj;
5922             if(!this.isListening(fn, scope)){
5923                 var l = {fn: fn, scope: scope, options: o};
5924                 var h = fn;
5925                 if(o.delay){
5926                     h = createDelayed(h, o, scope);
5927                 }
5928                 if(o.single){
5929                     h = createSingle(h, this, fn, scope);
5930                 }
5931                 if(o.buffer){
5932                     h = createBuffered(h, o, scope);
5933                 }
5934                 l.fireFn = h;
5935                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5936                     this.listeners.push(l);
5937                 }else{
5938                     this.listeners = this.listeners.slice(0);
5939                     this.listeners.push(l);
5940                 }
5941             }
5942         },
5943
5944         findListener : function(fn, scope){
5945             scope = scope || this.obj;
5946             var ls = this.listeners;
5947             for(var i = 0, len = ls.length; i < len; i++){
5948                 var l = ls[i];
5949                 if(l.fn == fn && l.scope == scope){
5950                     return i;
5951                 }
5952             }
5953             return -1;
5954         },
5955
5956         isListening : function(fn, scope){
5957             return this.findListener(fn, scope) != -1;
5958         },
5959
5960         removeListener : function(fn, scope){
5961             var index;
5962             if((index = this.findListener(fn, scope)) != -1){
5963                 if(!this.firing){
5964                     this.listeners.splice(index, 1);
5965                 }else{
5966                     this.listeners = this.listeners.slice(0);
5967                     this.listeners.splice(index, 1);
5968                 }
5969                 return true;
5970             }
5971             return false;
5972         },
5973
5974         clearListeners : function(){
5975             this.listeners = [];
5976         },
5977
5978         fire : function(){
5979             var ls = this.listeners, scope, len = ls.length;
5980             if(len > 0){
5981                 this.firing = true;
5982                 var args = Array.prototype.slice.call(arguments, 0);
5983                 for(var i = 0; i < len; i++){
5984                     var l = ls[i];
5985                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5986                         this.firing = false;
5987                         return false;
5988                     }
5989                 }
5990                 this.firing = false;
5991             }
5992             return true;
5993         }
5994     };
5995 })();/*
5996  * Based on:
5997  * Ext JS Library 1.1.1
5998  * Copyright(c) 2006-2007, Ext JS, LLC.
5999  *
6000  * Originally Released Under LGPL - original licence link has changed is not relivant.
6001  *
6002  * Fork - LGPL
6003  * <script type="text/javascript">
6004  */
6005
6006 /**
6007  * @class Roo.EventManager
6008  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6009  * several useful events directly.
6010  * See {@link Roo.EventObject} for more details on normalized event objects.
6011  * @singleton
6012  */
6013 Roo.EventManager = function(){
6014     var docReadyEvent, docReadyProcId, docReadyState = false;
6015     var resizeEvent, resizeTask, textEvent, textSize;
6016     var E = Roo.lib.Event;
6017     var D = Roo.lib.Dom;
6018
6019
6020     var fireDocReady = function(){
6021         if(!docReadyState){
6022             docReadyState = true;
6023             Roo.isReady = true;
6024             if(docReadyProcId){
6025                 clearInterval(docReadyProcId);
6026             }
6027             if(Roo.isGecko || Roo.isOpera) {
6028                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6029             }
6030             if(Roo.isIE){
6031                 var defer = document.getElementById("ie-deferred-loader");
6032                 if(defer){
6033                     defer.onreadystatechange = null;
6034                     defer.parentNode.removeChild(defer);
6035                 }
6036             }
6037             if(docReadyEvent){
6038                 docReadyEvent.fire();
6039                 docReadyEvent.clearListeners();
6040             }
6041         }
6042     };
6043     
6044     var initDocReady = function(){
6045         docReadyEvent = new Roo.util.Event();
6046         if(Roo.isGecko || Roo.isOpera) {
6047             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6048         }else if(Roo.isIE){
6049             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6050             var defer = document.getElementById("ie-deferred-loader");
6051             defer.onreadystatechange = function(){
6052                 if(this.readyState == "complete"){
6053                     fireDocReady();
6054                 }
6055             };
6056         }else if(Roo.isSafari){ 
6057             docReadyProcId = setInterval(function(){
6058                 var rs = document.readyState;
6059                 if(rs == "complete") {
6060                     fireDocReady();     
6061                  }
6062             }, 10);
6063         }
6064         // no matter what, make sure it fires on load
6065         E.on(window, "load", fireDocReady);
6066     };
6067
6068     var createBuffered = function(h, o){
6069         var task = new Roo.util.DelayedTask(h);
6070         return function(e){
6071             // create new event object impl so new events don't wipe out properties
6072             e = new Roo.EventObjectImpl(e);
6073             task.delay(o.buffer, h, null, [e]);
6074         };
6075     };
6076
6077     var createSingle = function(h, el, ename, fn){
6078         return function(e){
6079             Roo.EventManager.removeListener(el, ename, fn);
6080             h(e);
6081         };
6082     };
6083
6084     var createDelayed = function(h, o){
6085         return function(e){
6086             // create new event object impl so new events don't wipe out properties
6087             e = new Roo.EventObjectImpl(e);
6088             setTimeout(function(){
6089                 h(e);
6090             }, o.delay || 10);
6091         };
6092     };
6093
6094     var listen = function(element, ename, opt, fn, scope){
6095         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6096         fn = fn || o.fn; scope = scope || o.scope;
6097         var el = Roo.getDom(element);
6098         if(!el){
6099             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6100         }
6101         var h = function(e){
6102             e = Roo.EventObject.setEvent(e);
6103             var t;
6104             if(o.delegate){
6105                 t = e.getTarget(o.delegate, el);
6106                 if(!t){
6107                     return;
6108                 }
6109             }else{
6110                 t = e.target;
6111             }
6112             if(o.stopEvent === true){
6113                 e.stopEvent();
6114             }
6115             if(o.preventDefault === true){
6116                e.preventDefault();
6117             }
6118             if(o.stopPropagation === true){
6119                 e.stopPropagation();
6120             }
6121
6122             if(o.normalized === false){
6123                 e = e.browserEvent;
6124             }
6125
6126             fn.call(scope || el, e, t, o);
6127         };
6128         if(o.delay){
6129             h = createDelayed(h, o);
6130         }
6131         if(o.single){
6132             h = createSingle(h, el, ename, fn);
6133         }
6134         if(o.buffer){
6135             h = createBuffered(h, o);
6136         }
6137         fn._handlers = fn._handlers || [];
6138         fn._handlers.push([Roo.id(el), ename, h]);
6139
6140         E.on(el, ename, h);
6141         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6142             el.addEventListener("DOMMouseScroll", h, false);
6143             E.on(window, 'unload', function(){
6144                 el.removeEventListener("DOMMouseScroll", h, false);
6145             });
6146         }
6147         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6148             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6149         }
6150         return h;
6151     };
6152
6153     var stopListening = function(el, ename, fn){
6154         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6155         if(hds){
6156             for(var i = 0, len = hds.length; i < len; i++){
6157                 var h = hds[i];
6158                 if(h[0] == id && h[1] == ename){
6159                     hd = h[2];
6160                     hds.splice(i, 1);
6161                     break;
6162                 }
6163             }
6164         }
6165         E.un(el, ename, hd);
6166         el = Roo.getDom(el);
6167         if(ename == "mousewheel" && el.addEventListener){
6168             el.removeEventListener("DOMMouseScroll", hd, false);
6169         }
6170         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6171             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6172         }
6173     };
6174
6175     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6176     
6177     var pub = {
6178         
6179         
6180         /** 
6181          * Fix for doc tools
6182          * @scope Roo.EventManager
6183          */
6184         
6185         
6186         /** 
6187          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6188          * object with a Roo.EventObject
6189          * @param {Function} fn        The method the event invokes
6190          * @param {Object}   scope    An object that becomes the scope of the handler
6191          * @param {boolean}  override If true, the obj passed in becomes
6192          *                             the execution scope of the listener
6193          * @return {Function} The wrapped function
6194          * @deprecated
6195          */
6196         wrap : function(fn, scope, override){
6197             return function(e){
6198                 Roo.EventObject.setEvent(e);
6199                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6200             };
6201         },
6202         
6203         /**
6204      * Appends an event handler to an element (shorthand for addListener)
6205      * @param {String/HTMLElement}   element        The html element or id to assign the
6206      * @param {String}   eventName The type of event to listen for
6207      * @param {Function} handler The method the event invokes
6208      * @param {Object}   scope (optional) The scope in which to execute the handler
6209      * function. The handler function's "this" context.
6210      * @param {Object}   options (optional) An object containing handler configuration
6211      * properties. This may contain any of the following properties:<ul>
6212      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6213      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6214      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6215      * <li>preventDefault {Boolean} True to prevent the default action</li>
6216      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6217      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6218      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6219      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6220      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6221      * by the specified number of milliseconds. If the event fires again within that time, the original
6222      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6223      * </ul><br>
6224      * <p>
6225      * <b>Combining Options</b><br>
6226      * Using the options argument, it is possible to combine different types of listeners:<br>
6227      * <br>
6228      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6229      * Code:<pre><code>
6230 el.on('click', this.onClick, this, {
6231     single: true,
6232     delay: 100,
6233     stopEvent : true,
6234     forumId: 4
6235 });</code></pre>
6236      * <p>
6237      * <b>Attaching multiple handlers in 1 call</b><br>
6238       * The method also allows for a single argument to be passed which is a config object containing properties
6239      * which specify multiple handlers.
6240      * <p>
6241      * Code:<pre><code>
6242 el.on({
6243     'click' : {
6244         fn: this.onClick
6245         scope: this,
6246         delay: 100
6247     },
6248     'mouseover' : {
6249         fn: this.onMouseOver
6250         scope: this
6251     },
6252     'mouseout' : {
6253         fn: this.onMouseOut
6254         scope: this
6255     }
6256 });</code></pre>
6257      * <p>
6258      * Or a shorthand syntax:<br>
6259      * Code:<pre><code>
6260 el.on({
6261     'click' : this.onClick,
6262     'mouseover' : this.onMouseOver,
6263     'mouseout' : this.onMouseOut
6264     scope: this
6265 });</code></pre>
6266      */
6267         addListener : function(element, eventName, fn, scope, options){
6268             if(typeof eventName == "object"){
6269                 var o = eventName;
6270                 for(var e in o){
6271                     if(propRe.test(e)){
6272                         continue;
6273                     }
6274                     if(typeof o[e] == "function"){
6275                         // shared options
6276                         listen(element, e, o, o[e], o.scope);
6277                     }else{
6278                         // individual options
6279                         listen(element, e, o[e]);
6280                     }
6281                 }
6282                 return;
6283             }
6284             return listen(element, eventName, options, fn, scope);
6285         },
6286         
6287         /**
6288          * Removes an event handler
6289          *
6290          * @param {String/HTMLElement}   element        The id or html element to remove the 
6291          *                             event from
6292          * @param {String}   eventName     The type of event
6293          * @param {Function} fn
6294          * @return {Boolean} True if a listener was actually removed
6295          */
6296         removeListener : function(element, eventName, fn){
6297             return stopListening(element, eventName, fn);
6298         },
6299         
6300         /**
6301          * Fires when the document is ready (before onload and before images are loaded). Can be 
6302          * accessed shorthanded Roo.onReady().
6303          * @param {Function} fn        The method the event invokes
6304          * @param {Object}   scope    An  object that becomes the scope of the handler
6305          * @param {boolean}  options
6306          */
6307         onDocumentReady : function(fn, scope, options){
6308             if(docReadyState){ // if it already fired
6309                 docReadyEvent.addListener(fn, scope, options);
6310                 docReadyEvent.fire();
6311                 docReadyEvent.clearListeners();
6312                 return;
6313             }
6314             if(!docReadyEvent){
6315                 initDocReady();
6316             }
6317             docReadyEvent.addListener(fn, scope, options);
6318         },
6319         
6320         /**
6321          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6322          * @param {Function} fn        The method the event invokes
6323          * @param {Object}   scope    An object that becomes the scope of the handler
6324          * @param {boolean}  options
6325          */
6326         onWindowResize : function(fn, scope, options){
6327             if(!resizeEvent){
6328                 resizeEvent = new Roo.util.Event();
6329                 resizeTask = new Roo.util.DelayedTask(function(){
6330                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6331                 });
6332                 E.on(window, "resize", function(){
6333                     if(Roo.isIE){
6334                         resizeTask.delay(50);
6335                     }else{
6336                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6337                     }
6338                 });
6339             }
6340             resizeEvent.addListener(fn, scope, options);
6341         },
6342
6343         /**
6344          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6345          * @param {Function} fn        The method the event invokes
6346          * @param {Object}   scope    An object that becomes the scope of the handler
6347          * @param {boolean}  options
6348          */
6349         onTextResize : function(fn, scope, options){
6350             if(!textEvent){
6351                 textEvent = new Roo.util.Event();
6352                 var textEl = new Roo.Element(document.createElement('div'));
6353                 textEl.dom.className = 'x-text-resize';
6354                 textEl.dom.innerHTML = 'X';
6355                 textEl.appendTo(document.body);
6356                 textSize = textEl.dom.offsetHeight;
6357                 setInterval(function(){
6358                     if(textEl.dom.offsetHeight != textSize){
6359                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6360                     }
6361                 }, this.textResizeInterval);
6362             }
6363             textEvent.addListener(fn, scope, options);
6364         },
6365
6366         /**
6367          * Removes the passed window resize listener.
6368          * @param {Function} fn        The method the event invokes
6369          * @param {Object}   scope    The scope of handler
6370          */
6371         removeResizeListener : function(fn, scope){
6372             if(resizeEvent){
6373                 resizeEvent.removeListener(fn, scope);
6374             }
6375         },
6376
6377         // private
6378         fireResize : function(){
6379             if(resizeEvent){
6380                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6381             }   
6382         },
6383         /**
6384          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6385          */
6386         ieDeferSrc : false,
6387         /**
6388          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6389          */
6390         textResizeInterval : 50
6391     };
6392     
6393     /**
6394      * Fix for doc tools
6395      * @scopeAlias pub=Roo.EventManager
6396      */
6397     
6398      /**
6399      * Appends an event handler to an element (shorthand for addListener)
6400      * @param {String/HTMLElement}   element        The html element or id to assign the
6401      * @param {String}   eventName The type of event to listen for
6402      * @param {Function} handler The method the event invokes
6403      * @param {Object}   scope (optional) The scope in which to execute the handler
6404      * function. The handler function's "this" context.
6405      * @param {Object}   options (optional) An object containing handler configuration
6406      * properties. This may contain any of the following properties:<ul>
6407      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6408      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6409      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6410      * <li>preventDefault {Boolean} True to prevent the default action</li>
6411      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6412      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6413      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6414      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6415      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6416      * by the specified number of milliseconds. If the event fires again within that time, the original
6417      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6418      * </ul><br>
6419      * <p>
6420      * <b>Combining Options</b><br>
6421      * Using the options argument, it is possible to combine different types of listeners:<br>
6422      * <br>
6423      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6424      * Code:<pre><code>
6425 el.on('click', this.onClick, this, {
6426     single: true,
6427     delay: 100,
6428     stopEvent : true,
6429     forumId: 4
6430 });</code></pre>
6431      * <p>
6432      * <b>Attaching multiple handlers in 1 call</b><br>
6433       * The method also allows for a single argument to be passed which is a config object containing properties
6434      * which specify multiple handlers.
6435      * <p>
6436      * Code:<pre><code>
6437 el.on({
6438     'click' : {
6439         fn: this.onClick
6440         scope: this,
6441         delay: 100
6442     },
6443     'mouseover' : {
6444         fn: this.onMouseOver
6445         scope: this
6446     },
6447     'mouseout' : {
6448         fn: this.onMouseOut
6449         scope: this
6450     }
6451 });</code></pre>
6452      * <p>
6453      * Or a shorthand syntax:<br>
6454      * Code:<pre><code>
6455 el.on({
6456     'click' : this.onClick,
6457     'mouseover' : this.onMouseOver,
6458     'mouseout' : this.onMouseOut
6459     scope: this
6460 });</code></pre>
6461      */
6462     pub.on = pub.addListener;
6463     pub.un = pub.removeListener;
6464
6465     pub.stoppedMouseDownEvent = new Roo.util.Event();
6466     return pub;
6467 }();
6468 /**
6469   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6470   * @param {Function} fn        The method the event invokes
6471   * @param {Object}   scope    An  object that becomes the scope of the handler
6472   * @param {boolean}  override If true, the obj passed in becomes
6473   *                             the execution scope of the listener
6474   * @member Roo
6475   * @method onReady
6476  */
6477 Roo.onReady = Roo.EventManager.onDocumentReady;
6478
6479 Roo.onReady(function(){
6480     var bd = Roo.get(document.body);
6481     if(!bd){ return; }
6482
6483     var cls = [
6484             Roo.isIE ? "roo-ie"
6485             : Roo.isGecko ? "roo-gecko"
6486             : Roo.isOpera ? "roo-opera"
6487             : Roo.isSafari ? "roo-safari" : ""];
6488
6489     if(Roo.isMac){
6490         cls.push("roo-mac");
6491     }
6492     if(Roo.isLinux){
6493         cls.push("roo-linux");
6494     }
6495     if(Roo.isBorderBox){
6496         cls.push('roo-border-box');
6497     }
6498     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6499         var p = bd.dom.parentNode;
6500         if(p){
6501             p.className += ' roo-strict';
6502         }
6503     }
6504     bd.addClass(cls.join(' '));
6505 });
6506
6507 /**
6508  * @class Roo.EventObject
6509  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6510  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6511  * Example:
6512  * <pre><code>
6513  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6514     e.preventDefault();
6515     var target = e.getTarget();
6516     ...
6517  }
6518  var myDiv = Roo.get("myDiv");
6519  myDiv.on("click", handleClick);
6520  //or
6521  Roo.EventManager.on("myDiv", 'click', handleClick);
6522  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6523  </code></pre>
6524  * @singleton
6525  */
6526 Roo.EventObject = function(){
6527     
6528     var E = Roo.lib.Event;
6529     
6530     // safari keypress events for special keys return bad keycodes
6531     var safariKeys = {
6532         63234 : 37, // left
6533         63235 : 39, // right
6534         63232 : 38, // up
6535         63233 : 40, // down
6536         63276 : 33, // page up
6537         63277 : 34, // page down
6538         63272 : 46, // delete
6539         63273 : 36, // home
6540         63275 : 35  // end
6541     };
6542
6543     // normalize button clicks
6544     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6545                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6546
6547     Roo.EventObjectImpl = function(e){
6548         if(e){
6549             this.setEvent(e.browserEvent || e);
6550         }
6551     };
6552     Roo.EventObjectImpl.prototype = {
6553         /**
6554          * Used to fix doc tools.
6555          * @scope Roo.EventObject.prototype
6556          */
6557             
6558
6559         
6560         
6561         /** The normal browser event */
6562         browserEvent : null,
6563         /** The button pressed in a mouse event */
6564         button : -1,
6565         /** True if the shift key was down during the event */
6566         shiftKey : false,
6567         /** True if the control key was down during the event */
6568         ctrlKey : false,
6569         /** True if the alt key was down during the event */
6570         altKey : false,
6571
6572         /** Key constant 
6573         * @type Number */
6574         BACKSPACE : 8,
6575         /** Key constant 
6576         * @type Number */
6577         TAB : 9,
6578         /** Key constant 
6579         * @type Number */
6580         RETURN : 13,
6581         /** Key constant 
6582         * @type Number */
6583         ENTER : 13,
6584         /** Key constant 
6585         * @type Number */
6586         SHIFT : 16,
6587         /** Key constant 
6588         * @type Number */
6589         CONTROL : 17,
6590         /** Key constant 
6591         * @type Number */
6592         ESC : 27,
6593         /** Key constant 
6594         * @type Number */
6595         SPACE : 32,
6596         /** Key constant 
6597         * @type Number */
6598         PAGEUP : 33,
6599         /** Key constant 
6600         * @type Number */
6601         PAGEDOWN : 34,
6602         /** Key constant 
6603         * @type Number */
6604         END : 35,
6605         /** Key constant 
6606         * @type Number */
6607         HOME : 36,
6608         /** Key constant 
6609         * @type Number */
6610         LEFT : 37,
6611         /** Key constant 
6612         * @type Number */
6613         UP : 38,
6614         /** Key constant 
6615         * @type Number */
6616         RIGHT : 39,
6617         /** Key constant 
6618         * @type Number */
6619         DOWN : 40,
6620         /** Key constant 
6621         * @type Number */
6622         DELETE : 46,
6623         /** Key constant 
6624         * @type Number */
6625         F5 : 116,
6626
6627            /** @private */
6628         setEvent : function(e){
6629             if(e == this || (e && e.browserEvent)){ // already wrapped
6630                 return e;
6631             }
6632             this.browserEvent = e;
6633             if(e){
6634                 // normalize buttons
6635                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6636                 if(e.type == 'click' && this.button == -1){
6637                     this.button = 0;
6638                 }
6639                 this.type = e.type;
6640                 this.shiftKey = e.shiftKey;
6641                 // mac metaKey behaves like ctrlKey
6642                 this.ctrlKey = e.ctrlKey || e.metaKey;
6643                 this.altKey = e.altKey;
6644                 // in getKey these will be normalized for the mac
6645                 this.keyCode = e.keyCode;
6646                 // keyup warnings on firefox.
6647                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6648                 // cache the target for the delayed and or buffered events
6649                 this.target = E.getTarget(e);
6650                 // same for XY
6651                 this.xy = E.getXY(e);
6652             }else{
6653                 this.button = -1;
6654                 this.shiftKey = false;
6655                 this.ctrlKey = false;
6656                 this.altKey = false;
6657                 this.keyCode = 0;
6658                 this.charCode =0;
6659                 this.target = null;
6660                 this.xy = [0, 0];
6661             }
6662             return this;
6663         },
6664
6665         /**
6666          * Stop the event (preventDefault and stopPropagation)
6667          */
6668         stopEvent : function(){
6669             if(this.browserEvent){
6670                 if(this.browserEvent.type == 'mousedown'){
6671                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6672                 }
6673                 E.stopEvent(this.browserEvent);
6674             }
6675         },
6676
6677         /**
6678          * Prevents the browsers default handling of the event.
6679          */
6680         preventDefault : function(){
6681             if(this.browserEvent){
6682                 E.preventDefault(this.browserEvent);
6683             }
6684         },
6685
6686         /** @private */
6687         isNavKeyPress : function(){
6688             var k = this.keyCode;
6689             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6690             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6691         },
6692
6693         isSpecialKey : function(){
6694             var k = this.keyCode;
6695             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6696             (k == 16) || (k == 17) ||
6697             (k >= 18 && k <= 20) ||
6698             (k >= 33 && k <= 35) ||
6699             (k >= 36 && k <= 39) ||
6700             (k >= 44 && k <= 45);
6701         },
6702         /**
6703          * Cancels bubbling of the event.
6704          */
6705         stopPropagation : function(){
6706             if(this.browserEvent){
6707                 if(this.type == 'mousedown'){
6708                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6709                 }
6710                 E.stopPropagation(this.browserEvent);
6711             }
6712         },
6713
6714         /**
6715          * Gets the key code for the event.
6716          * @return {Number}
6717          */
6718         getCharCode : function(){
6719             return this.charCode || this.keyCode;
6720         },
6721
6722         /**
6723          * Returns a normalized keyCode for the event.
6724          * @return {Number} The key code
6725          */
6726         getKey : function(){
6727             var k = this.keyCode || this.charCode;
6728             return Roo.isSafari ? (safariKeys[k] || k) : k;
6729         },
6730
6731         /**
6732          * Gets the x coordinate of the event.
6733          * @return {Number}
6734          */
6735         getPageX : function(){
6736             return this.xy[0];
6737         },
6738
6739         /**
6740          * Gets the y coordinate of the event.
6741          * @return {Number}
6742          */
6743         getPageY : function(){
6744             return this.xy[1];
6745         },
6746
6747         /**
6748          * Gets the time of the event.
6749          * @return {Number}
6750          */
6751         getTime : function(){
6752             if(this.browserEvent){
6753                 return E.getTime(this.browserEvent);
6754             }
6755             return null;
6756         },
6757
6758         /**
6759          * Gets the page coordinates of the event.
6760          * @return {Array} The xy values like [x, y]
6761          */
6762         getXY : function(){
6763             return this.xy;
6764         },
6765
6766         /**
6767          * Gets the target for the event.
6768          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6769          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6770                 search as a number or element (defaults to 10 || document.body)
6771          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6772          * @return {HTMLelement}
6773          */
6774         getTarget : function(selector, maxDepth, returnEl){
6775             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6776         },
6777         /**
6778          * Gets the related target.
6779          * @return {HTMLElement}
6780          */
6781         getRelatedTarget : function(){
6782             if(this.browserEvent){
6783                 return E.getRelatedTarget(this.browserEvent);
6784             }
6785             return null;
6786         },
6787
6788         /**
6789          * Normalizes mouse wheel delta across browsers
6790          * @return {Number} The delta
6791          */
6792         getWheelDelta : function(){
6793             var e = this.browserEvent;
6794             var delta = 0;
6795             if(e.wheelDelta){ /* IE/Opera. */
6796                 delta = e.wheelDelta/120;
6797             }else if(e.detail){ /* Mozilla case. */
6798                 delta = -e.detail/3;
6799             }
6800             return delta;
6801         },
6802
6803         /**
6804          * Returns true if the control, meta, shift or alt key was pressed during this event.
6805          * @return {Boolean}
6806          */
6807         hasModifier : function(){
6808             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6809         },
6810
6811         /**
6812          * Returns true if the target of this event equals el or is a child of el
6813          * @param {String/HTMLElement/Element} el
6814          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6815          * @return {Boolean}
6816          */
6817         within : function(el, related){
6818             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6819             return t && Roo.fly(el).contains(t);
6820         },
6821
6822         getPoint : function(){
6823             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6824         }
6825     };
6826
6827     return new Roo.EventObjectImpl();
6828 }();
6829             
6830     /*
6831  * Based on:
6832  * Ext JS Library 1.1.1
6833  * Copyright(c) 2006-2007, Ext JS, LLC.
6834  *
6835  * Originally Released Under LGPL - original licence link has changed is not relivant.
6836  *
6837  * Fork - LGPL
6838  * <script type="text/javascript">
6839  */
6840
6841  
6842 // was in Composite Element!??!?!
6843  
6844 (function(){
6845     var D = Roo.lib.Dom;
6846     var E = Roo.lib.Event;
6847     var A = Roo.lib.Anim;
6848
6849     // local style camelizing for speed
6850     var propCache = {};
6851     var camelRe = /(-[a-z])/gi;
6852     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6853     var view = document.defaultView;
6854
6855 /**
6856  * @class Roo.Element
6857  * Represents an Element in the DOM.<br><br>
6858  * Usage:<br>
6859 <pre><code>
6860 var el = Roo.get("my-div");
6861
6862 // or with getEl
6863 var el = getEl("my-div");
6864
6865 // or with a DOM element
6866 var el = Roo.get(myDivElement);
6867 </code></pre>
6868  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6869  * each call instead of constructing a new one.<br><br>
6870  * <b>Animations</b><br />
6871  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6872  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6873 <pre>
6874 Option    Default   Description
6875 --------- --------  ---------------------------------------------
6876 duration  .35       The duration of the animation in seconds
6877 easing    easeOut   The YUI easing method
6878 callback  none      A function to execute when the anim completes
6879 scope     this      The scope (this) of the callback function
6880 </pre>
6881 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6882 * manipulate the animation. Here's an example:
6883 <pre><code>
6884 var el = Roo.get("my-div");
6885
6886 // no animation
6887 el.setWidth(100);
6888
6889 // default animation
6890 el.setWidth(100, true);
6891
6892 // animation with some options set
6893 el.setWidth(100, {
6894     duration: 1,
6895     callback: this.foo,
6896     scope: this
6897 });
6898
6899 // using the "anim" property to get the Anim object
6900 var opt = {
6901     duration: 1,
6902     callback: this.foo,
6903     scope: this
6904 };
6905 el.setWidth(100, opt);
6906 ...
6907 if(opt.anim.isAnimated()){
6908     opt.anim.stop();
6909 }
6910 </code></pre>
6911 * <b> Composite (Collections of) Elements</b><br />
6912  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6913  * @constructor Create a new Element directly.
6914  * @param {String/HTMLElement} element
6915  * @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).
6916  */
6917     Roo.Element = function(element, forceNew){
6918         var dom = typeof element == "string" ?
6919                 document.getElementById(element) : element;
6920         if(!dom){ // invalid id/element
6921             return null;
6922         }
6923         var id = dom.id;
6924         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6925             return Roo.Element.cache[id];
6926         }
6927
6928         /**
6929          * The DOM element
6930          * @type HTMLElement
6931          */
6932         this.dom = dom;
6933
6934         /**
6935          * The DOM element ID
6936          * @type String
6937          */
6938         this.id = id || Roo.id(dom);
6939     };
6940
6941     var El = Roo.Element;
6942
6943     El.prototype = {
6944         /**
6945          * The element's default display mode  (defaults to "")
6946          * @type String
6947          */
6948         originalDisplay : "",
6949
6950         visibilityMode : 1,
6951         /**
6952          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6953          * @type String
6954          */
6955         defaultUnit : "px",
6956         /**
6957          * Sets the element's visibility mode. When setVisible() is called it
6958          * will use this to determine whether to set the visibility or the display property.
6959          * @param visMode Element.VISIBILITY or Element.DISPLAY
6960          * @return {Roo.Element} this
6961          */
6962         setVisibilityMode : function(visMode){
6963             this.visibilityMode = visMode;
6964             return this;
6965         },
6966         /**
6967          * Convenience method for setVisibilityMode(Element.DISPLAY)
6968          * @param {String} display (optional) What to set display to when visible
6969          * @return {Roo.Element} this
6970          */
6971         enableDisplayMode : function(display){
6972             this.setVisibilityMode(El.DISPLAY);
6973             if(typeof display != "undefined") this.originalDisplay = display;
6974             return this;
6975         },
6976
6977         /**
6978          * 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)
6979          * @param {String} selector The simple selector to test
6980          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6981                 search as a number or element (defaults to 10 || document.body)
6982          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6983          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6984          */
6985         findParent : function(simpleSelector, maxDepth, returnEl){
6986             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6987             maxDepth = maxDepth || 50;
6988             if(typeof maxDepth != "number"){
6989                 stopEl = Roo.getDom(maxDepth);
6990                 maxDepth = 10;
6991             }
6992             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6993                 if(dq.is(p, simpleSelector)){
6994                     return returnEl ? Roo.get(p) : p;
6995                 }
6996                 depth++;
6997                 p = p.parentNode;
6998             }
6999             return null;
7000         },
7001
7002
7003         /**
7004          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7005          * @param {String} selector The simple selector to test
7006          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7007                 search as a number or element (defaults to 10 || document.body)
7008          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7009          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7010          */
7011         findParentNode : function(simpleSelector, maxDepth, returnEl){
7012             var p = Roo.fly(this.dom.parentNode, '_internal');
7013             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7014         },
7015
7016         /**
7017          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7018          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7019          * @param {String} selector The simple selector to test
7020          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7021                 search as a number or element (defaults to 10 || document.body)
7022          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7023          */
7024         up : function(simpleSelector, maxDepth){
7025             return this.findParentNode(simpleSelector, maxDepth, true);
7026         },
7027
7028
7029
7030         /**
7031          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7032          * @param {String} selector The simple selector to test
7033          * @return {Boolean} True if this element matches the selector, else false
7034          */
7035         is : function(simpleSelector){
7036             return Roo.DomQuery.is(this.dom, simpleSelector);
7037         },
7038
7039         /**
7040          * Perform animation on this element.
7041          * @param {Object} args The YUI animation control args
7042          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7043          * @param {Function} onComplete (optional) Function to call when animation completes
7044          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7045          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7046          * @return {Roo.Element} this
7047          */
7048         animate : function(args, duration, onComplete, easing, animType){
7049             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7050             return this;
7051         },
7052
7053         /*
7054          * @private Internal animation call
7055          */
7056         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7057             animType = animType || 'run';
7058             opt = opt || {};
7059             var anim = Roo.lib.Anim[animType](
7060                 this.dom, args,
7061                 (opt.duration || defaultDur) || .35,
7062                 (opt.easing || defaultEase) || 'easeOut',
7063                 function(){
7064                     Roo.callback(cb, this);
7065                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7066                 },
7067                 this
7068             );
7069             opt.anim = anim;
7070             return anim;
7071         },
7072
7073         // private legacy anim prep
7074         preanim : function(a, i){
7075             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7076         },
7077
7078         /**
7079          * Removes worthless text nodes
7080          * @param {Boolean} forceReclean (optional) By default the element
7081          * keeps track if it has been cleaned already so
7082          * you can call this over and over. However, if you update the element and
7083          * need to force a reclean, you can pass true.
7084          */
7085         clean : function(forceReclean){
7086             if(this.isCleaned && forceReclean !== true){
7087                 return this;
7088             }
7089             var ns = /\S/;
7090             var d = this.dom, n = d.firstChild, ni = -1;
7091             while(n){
7092                 var nx = n.nextSibling;
7093                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7094                     d.removeChild(n);
7095                 }else{
7096                     n.nodeIndex = ++ni;
7097                 }
7098                 n = nx;
7099             }
7100             this.isCleaned = true;
7101             return this;
7102         },
7103
7104         // private
7105         calcOffsetsTo : function(el){
7106             el = Roo.get(el);
7107             var d = el.dom;
7108             var restorePos = false;
7109             if(el.getStyle('position') == 'static'){
7110                 el.position('relative');
7111                 restorePos = true;
7112             }
7113             var x = 0, y =0;
7114             var op = this.dom;
7115             while(op && op != d && op.tagName != 'HTML'){
7116                 x+= op.offsetLeft;
7117                 y+= op.offsetTop;
7118                 op = op.offsetParent;
7119             }
7120             if(restorePos){
7121                 el.position('static');
7122             }
7123             return [x, y];
7124         },
7125
7126         /**
7127          * Scrolls this element into view within the passed container.
7128          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7129          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7130          * @return {Roo.Element} this
7131          */
7132         scrollIntoView : function(container, hscroll){
7133             var c = Roo.getDom(container) || document.body;
7134             var el = this.dom;
7135
7136             var o = this.calcOffsetsTo(c),
7137                 l = o[0],
7138                 t = o[1],
7139                 b = t+el.offsetHeight,
7140                 r = l+el.offsetWidth;
7141
7142             var ch = c.clientHeight;
7143             var ct = parseInt(c.scrollTop, 10);
7144             var cl = parseInt(c.scrollLeft, 10);
7145             var cb = ct + ch;
7146             var cr = cl + c.clientWidth;
7147
7148             if(t < ct){
7149                 c.scrollTop = t;
7150             }else if(b > cb){
7151                 c.scrollTop = b-ch;
7152             }
7153
7154             if(hscroll !== false){
7155                 if(l < cl){
7156                     c.scrollLeft = l;
7157                 }else if(r > cr){
7158                     c.scrollLeft = r-c.clientWidth;
7159                 }
7160             }
7161             return this;
7162         },
7163
7164         // private
7165         scrollChildIntoView : function(child, hscroll){
7166             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7167         },
7168
7169         /**
7170          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7171          * the new height may not be available immediately.
7172          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7173          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7174          * @param {Function} onComplete (optional) Function to call when animation completes
7175          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7176          * @return {Roo.Element} this
7177          */
7178         autoHeight : function(animate, duration, onComplete, easing){
7179             var oldHeight = this.getHeight();
7180             this.clip();
7181             this.setHeight(1); // force clipping
7182             setTimeout(function(){
7183                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7184                 if(!animate){
7185                     this.setHeight(height);
7186                     this.unclip();
7187                     if(typeof onComplete == "function"){
7188                         onComplete();
7189                     }
7190                 }else{
7191                     this.setHeight(oldHeight); // restore original height
7192                     this.setHeight(height, animate, duration, function(){
7193                         this.unclip();
7194                         if(typeof onComplete == "function") onComplete();
7195                     }.createDelegate(this), easing);
7196                 }
7197             }.createDelegate(this), 0);
7198             return this;
7199         },
7200
7201         /**
7202          * Returns true if this element is an ancestor of the passed element
7203          * @param {HTMLElement/String} el The element to check
7204          * @return {Boolean} True if this element is an ancestor of el, else false
7205          */
7206         contains : function(el){
7207             if(!el){return false;}
7208             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7209         },
7210
7211         /**
7212          * Checks whether the element is currently visible using both visibility and display properties.
7213          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7214          * @return {Boolean} True if the element is currently visible, else false
7215          */
7216         isVisible : function(deep) {
7217             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7218             if(deep !== true || !vis){
7219                 return vis;
7220             }
7221             var p = this.dom.parentNode;
7222             while(p && p.tagName.toLowerCase() != "body"){
7223                 if(!Roo.fly(p, '_isVisible').isVisible()){
7224                     return false;
7225                 }
7226                 p = p.parentNode;
7227             }
7228             return true;
7229         },
7230
7231         /**
7232          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7233          * @param {String} selector The CSS selector
7234          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7235          * @return {CompositeElement/CompositeElementLite} The composite element
7236          */
7237         select : function(selector, unique){
7238             return El.select(selector, unique, this.dom);
7239         },
7240
7241         /**
7242          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7243          * @param {String} selector The CSS selector
7244          * @return {Array} An array of the matched nodes
7245          */
7246         query : function(selector, unique){
7247             return Roo.DomQuery.select(selector, this.dom);
7248         },
7249
7250         /**
7251          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7252          * @param {String} selector The CSS selector
7253          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7254          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7255          */
7256         child : function(selector, returnDom){
7257             var n = Roo.DomQuery.selectNode(selector, this.dom);
7258             return returnDom ? n : Roo.get(n);
7259         },
7260
7261         /**
7262          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7263          * @param {String} selector The CSS selector
7264          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7265          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7266          */
7267         down : function(selector, returnDom){
7268             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7269             return returnDom ? n : Roo.get(n);
7270         },
7271
7272         /**
7273          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7274          * @param {String} group The group the DD object is member of
7275          * @param {Object} config The DD config object
7276          * @param {Object} overrides An object containing methods to override/implement on the DD object
7277          * @return {Roo.dd.DD} The DD object
7278          */
7279         initDD : function(group, config, overrides){
7280             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7281             return Roo.apply(dd, overrides);
7282         },
7283
7284         /**
7285          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7286          * @param {String} group The group the DDProxy object is member of
7287          * @param {Object} config The DDProxy config object
7288          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7289          * @return {Roo.dd.DDProxy} The DDProxy object
7290          */
7291         initDDProxy : function(group, config, overrides){
7292             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7293             return Roo.apply(dd, overrides);
7294         },
7295
7296         /**
7297          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7298          * @param {String} group The group the DDTarget object is member of
7299          * @param {Object} config The DDTarget config object
7300          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7301          * @return {Roo.dd.DDTarget} The DDTarget object
7302          */
7303         initDDTarget : function(group, config, overrides){
7304             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7305             return Roo.apply(dd, overrides);
7306         },
7307
7308         /**
7309          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7310          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7311          * @param {Boolean} visible Whether the element is visible
7312          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7313          * @return {Roo.Element} this
7314          */
7315          setVisible : function(visible, animate){
7316             if(!animate || !A){
7317                 if(this.visibilityMode == El.DISPLAY){
7318                     this.setDisplayed(visible);
7319                 }else{
7320                     this.fixDisplay();
7321                     this.dom.style.visibility = visible ? "visible" : "hidden";
7322                 }
7323             }else{
7324                 // closure for composites
7325                 var dom = this.dom;
7326                 var visMode = this.visibilityMode;
7327                 if(visible){
7328                     this.setOpacity(.01);
7329                     this.setVisible(true);
7330                 }
7331                 this.anim({opacity: { to: (visible?1:0) }},
7332                       this.preanim(arguments, 1),
7333                       null, .35, 'easeIn', function(){
7334                          if(!visible){
7335                              if(visMode == El.DISPLAY){
7336                                  dom.style.display = "none";
7337                              }else{
7338                                  dom.style.visibility = "hidden";
7339                              }
7340                              Roo.get(dom).setOpacity(1);
7341                          }
7342                      });
7343             }
7344             return this;
7345         },
7346
7347         /**
7348          * Returns true if display is not "none"
7349          * @return {Boolean}
7350          */
7351         isDisplayed : function() {
7352             return this.getStyle("display") != "none";
7353         },
7354
7355         /**
7356          * Toggles the element's visibility or display, depending on visibility mode.
7357          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7358          * @return {Roo.Element} this
7359          */
7360         toggle : function(animate){
7361             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7362             return this;
7363         },
7364
7365         /**
7366          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7367          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7368          * @return {Roo.Element} this
7369          */
7370         setDisplayed : function(value) {
7371             if(typeof value == "boolean"){
7372                value = value ? this.originalDisplay : "none";
7373             }
7374             this.setStyle("display", value);
7375             return this;
7376         },
7377
7378         /**
7379          * Tries to focus the element. Any exceptions are caught and ignored.
7380          * @return {Roo.Element} this
7381          */
7382         focus : function() {
7383             try{
7384                 this.dom.focus();
7385             }catch(e){}
7386             return this;
7387         },
7388
7389         /**
7390          * Tries to blur the element. Any exceptions are caught and ignored.
7391          * @return {Roo.Element} this
7392          */
7393         blur : function() {
7394             try{
7395                 this.dom.blur();
7396             }catch(e){}
7397             return this;
7398         },
7399
7400         /**
7401          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7402          * @param {String/Array} className The CSS class to add, or an array of classes
7403          * @return {Roo.Element} this
7404          */
7405         addClass : function(className){
7406             if(className instanceof Array){
7407                 for(var i = 0, len = className.length; i < len; i++) {
7408                     this.addClass(className[i]);
7409                 }
7410             }else{
7411                 if(className && !this.hasClass(className)){
7412                     this.dom.className = this.dom.className + " " + className;
7413                 }
7414             }
7415             return this;
7416         },
7417
7418         /**
7419          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7420          * @param {String/Array} className The CSS class to add, or an array of classes
7421          * @return {Roo.Element} this
7422          */
7423         radioClass : function(className){
7424             var siblings = this.dom.parentNode.childNodes;
7425             for(var i = 0; i < siblings.length; i++) {
7426                 var s = siblings[i];
7427                 if(s.nodeType == 1){
7428                     Roo.get(s).removeClass(className);
7429                 }
7430             }
7431             this.addClass(className);
7432             return this;
7433         },
7434
7435         /**
7436          * Removes one or more CSS classes from the element.
7437          * @param {String/Array} className The CSS class to remove, or an array of classes
7438          * @return {Roo.Element} this
7439          */
7440         removeClass : function(className){
7441             if(!className || !this.dom.className){
7442                 return this;
7443             }
7444             if(className instanceof Array){
7445                 for(var i = 0, len = className.length; i < len; i++) {
7446                     this.removeClass(className[i]);
7447                 }
7448             }else{
7449                 if(this.hasClass(className)){
7450                     var re = this.classReCache[className];
7451                     if (!re) {
7452                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7453                        this.classReCache[className] = re;
7454                     }
7455                     this.dom.className =
7456                         this.dom.className.replace(re, " ");
7457                 }
7458             }
7459             return this;
7460         },
7461
7462         // private
7463         classReCache: {},
7464
7465         /**
7466          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7467          * @param {String} className The CSS class to toggle
7468          * @return {Roo.Element} this
7469          */
7470         toggleClass : function(className){
7471             if(this.hasClass(className)){
7472                 this.removeClass(className);
7473             }else{
7474                 this.addClass(className);
7475             }
7476             return this;
7477         },
7478
7479         /**
7480          * Checks if the specified CSS class exists on this element's DOM node.
7481          * @param {String} className The CSS class to check for
7482          * @return {Boolean} True if the class exists, else false
7483          */
7484         hasClass : function(className){
7485             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7486         },
7487
7488         /**
7489          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7490          * @param {String} oldClassName The CSS class to replace
7491          * @param {String} newClassName The replacement CSS class
7492          * @return {Roo.Element} this
7493          */
7494         replaceClass : function(oldClassName, newClassName){
7495             this.removeClass(oldClassName);
7496             this.addClass(newClassName);
7497             return this;
7498         },
7499
7500         /**
7501          * Returns an object with properties matching the styles requested.
7502          * For example, el.getStyles('color', 'font-size', 'width') might return
7503          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7504          * @param {String} style1 A style name
7505          * @param {String} style2 A style name
7506          * @param {String} etc.
7507          * @return {Object} The style object
7508          */
7509         getStyles : function(){
7510             var a = arguments, len = a.length, r = {};
7511             for(var i = 0; i < len; i++){
7512                 r[a[i]] = this.getStyle(a[i]);
7513             }
7514             return r;
7515         },
7516
7517         /**
7518          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7519          * @param {String} property The style property whose value is returned.
7520          * @return {String} The current value of the style property for this element.
7521          */
7522         getStyle : function(){
7523             return view && view.getComputedStyle ?
7524                 function(prop){
7525                     var el = this.dom, v, cs, camel;
7526                     if(prop == 'float'){
7527                         prop = "cssFloat";
7528                     }
7529                     if(el.style && (v = el.style[prop])){
7530                         return v;
7531                     }
7532                     if(cs = view.getComputedStyle(el, "")){
7533                         if(!(camel = propCache[prop])){
7534                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7535                         }
7536                         return cs[camel];
7537                     }
7538                     return null;
7539                 } :
7540                 function(prop){
7541                     var el = this.dom, v, cs, camel;
7542                     if(prop == 'opacity'){
7543                         if(typeof el.style.filter == 'string'){
7544                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7545                             if(m){
7546                                 var fv = parseFloat(m[1]);
7547                                 if(!isNaN(fv)){
7548                                     return fv ? fv / 100 : 0;
7549                                 }
7550                             }
7551                         }
7552                         return 1;
7553                     }else if(prop == 'float'){
7554                         prop = "styleFloat";
7555                     }
7556                     if(!(camel = propCache[prop])){
7557                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7558                     }
7559                     if(v = el.style[camel]){
7560                         return v;
7561                     }
7562                     if(cs = el.currentStyle){
7563                         return cs[camel];
7564                     }
7565                     return null;
7566                 };
7567         }(),
7568
7569         /**
7570          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7571          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7572          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7573          * @return {Roo.Element} this
7574          */
7575         setStyle : function(prop, value){
7576             if(typeof prop == "string"){
7577                 
7578                 if (prop == 'float') {
7579                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7580                     return this;
7581                 }
7582                 
7583                 var camel;
7584                 if(!(camel = propCache[prop])){
7585                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7586                 }
7587                 
7588                 if(camel == 'opacity') {
7589                     this.setOpacity(value);
7590                 }else{
7591                     this.dom.style[camel] = value;
7592                 }
7593             }else{
7594                 for(var style in prop){
7595                     if(typeof prop[style] != "function"){
7596                        this.setStyle(style, prop[style]);
7597                     }
7598                 }
7599             }
7600             return this;
7601         },
7602
7603         /**
7604          * More flexible version of {@link #setStyle} for setting style properties.
7605          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7606          * a function which returns such a specification.
7607          * @return {Roo.Element} this
7608          */
7609         applyStyles : function(style){
7610             Roo.DomHelper.applyStyles(this.dom, style);
7611             return this;
7612         },
7613
7614         /**
7615           * 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).
7616           * @return {Number} The X position of the element
7617           */
7618         getX : function(){
7619             return D.getX(this.dom);
7620         },
7621
7622         /**
7623           * 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).
7624           * @return {Number} The Y position of the element
7625           */
7626         getY : function(){
7627             return D.getY(this.dom);
7628         },
7629
7630         /**
7631           * 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).
7632           * @return {Array} The XY position of the element
7633           */
7634         getXY : function(){
7635             return D.getXY(this.dom);
7636         },
7637
7638         /**
7639          * 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).
7640          * @param {Number} The X position of the element
7641          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7642          * @return {Roo.Element} this
7643          */
7644         setX : function(x, animate){
7645             if(!animate || !A){
7646                 D.setX(this.dom, x);
7647             }else{
7648                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7649             }
7650             return this;
7651         },
7652
7653         /**
7654          * 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).
7655          * @param {Number} The Y position of the element
7656          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7657          * @return {Roo.Element} this
7658          */
7659         setY : function(y, animate){
7660             if(!animate || !A){
7661                 D.setY(this.dom, y);
7662             }else{
7663                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7664             }
7665             return this;
7666         },
7667
7668         /**
7669          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7670          * @param {String} left The left CSS property value
7671          * @return {Roo.Element} this
7672          */
7673         setLeft : function(left){
7674             this.setStyle("left", this.addUnits(left));
7675             return this;
7676         },
7677
7678         /**
7679          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7680          * @param {String} top The top CSS property value
7681          * @return {Roo.Element} this
7682          */
7683         setTop : function(top){
7684             this.setStyle("top", this.addUnits(top));
7685             return this;
7686         },
7687
7688         /**
7689          * Sets the element's CSS right style.
7690          * @param {String} right The right CSS property value
7691          * @return {Roo.Element} this
7692          */
7693         setRight : function(right){
7694             this.setStyle("right", this.addUnits(right));
7695             return this;
7696         },
7697
7698         /**
7699          * Sets the element's CSS bottom style.
7700          * @param {String} bottom The bottom CSS property value
7701          * @return {Roo.Element} this
7702          */
7703         setBottom : function(bottom){
7704             this.setStyle("bottom", this.addUnits(bottom));
7705             return this;
7706         },
7707
7708         /**
7709          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7710          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7711          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7712          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7713          * @return {Roo.Element} this
7714          */
7715         setXY : function(pos, animate){
7716             if(!animate || !A){
7717                 D.setXY(this.dom, pos);
7718             }else{
7719                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7720             }
7721             return this;
7722         },
7723
7724         /**
7725          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7726          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7727          * @param {Number} x X value for new position (coordinates are page-based)
7728          * @param {Number} y Y value for new position (coordinates are page-based)
7729          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7730          * @return {Roo.Element} this
7731          */
7732         setLocation : function(x, y, animate){
7733             this.setXY([x, y], this.preanim(arguments, 2));
7734             return this;
7735         },
7736
7737         /**
7738          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7739          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7740          * @param {Number} x X value for new position (coordinates are page-based)
7741          * @param {Number} y Y value for new position (coordinates are page-based)
7742          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7743          * @return {Roo.Element} this
7744          */
7745         moveTo : function(x, y, animate){
7746             this.setXY([x, y], this.preanim(arguments, 2));
7747             return this;
7748         },
7749
7750         /**
7751          * Returns the region of the given element.
7752          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7753          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7754          */
7755         getRegion : function(){
7756             return D.getRegion(this.dom);
7757         },
7758
7759         /**
7760          * Returns the offset height of the element
7761          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7762          * @return {Number} The element's height
7763          */
7764         getHeight : function(contentHeight){
7765             var h = this.dom.offsetHeight || 0;
7766             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7767         },
7768
7769         /**
7770          * Returns the offset width of the element
7771          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7772          * @return {Number} The element's width
7773          */
7774         getWidth : function(contentWidth){
7775             var w = this.dom.offsetWidth || 0;
7776             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7777         },
7778
7779         /**
7780          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7781          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7782          * if a height has not been set using CSS.
7783          * @return {Number}
7784          */
7785         getComputedHeight : function(){
7786             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7787             if(!h){
7788                 h = parseInt(this.getStyle('height'), 10) || 0;
7789                 if(!this.isBorderBox()){
7790                     h += this.getFrameWidth('tb');
7791                 }
7792             }
7793             return h;
7794         },
7795
7796         /**
7797          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7798          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7799          * if a width has not been set using CSS.
7800          * @return {Number}
7801          */
7802         getComputedWidth : function(){
7803             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7804             if(!w){
7805                 w = parseInt(this.getStyle('width'), 10) || 0;
7806                 if(!this.isBorderBox()){
7807                     w += this.getFrameWidth('lr');
7808                 }
7809             }
7810             return w;
7811         },
7812
7813         /**
7814          * Returns the size of the element.
7815          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7816          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7817          */
7818         getSize : function(contentSize){
7819             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7820         },
7821
7822         /**
7823          * Returns the width and height of the viewport.
7824          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7825          */
7826         getViewSize : function(){
7827             var d = this.dom, doc = document, aw = 0, ah = 0;
7828             if(d == doc || d == doc.body){
7829                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7830             }else{
7831                 return {
7832                     width : d.clientWidth,
7833                     height: d.clientHeight
7834                 };
7835             }
7836         },
7837
7838         /**
7839          * Returns the value of the "value" attribute
7840          * @param {Boolean} asNumber true to parse the value as a number
7841          * @return {String/Number}
7842          */
7843         getValue : function(asNumber){
7844             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7845         },
7846
7847         // private
7848         adjustWidth : function(width){
7849             if(typeof width == "number"){
7850                 if(this.autoBoxAdjust && !this.isBorderBox()){
7851                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7852                 }
7853                 if(width < 0){
7854                     width = 0;
7855                 }
7856             }
7857             return width;
7858         },
7859
7860         // private
7861         adjustHeight : function(height){
7862             if(typeof height == "number"){
7863                if(this.autoBoxAdjust && !this.isBorderBox()){
7864                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7865                }
7866                if(height < 0){
7867                    height = 0;
7868                }
7869             }
7870             return height;
7871         },
7872
7873         /**
7874          * Set the width of the element
7875          * @param {Number} width The new width
7876          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7877          * @return {Roo.Element} this
7878          */
7879         setWidth : function(width, animate){
7880             width = this.adjustWidth(width);
7881             if(!animate || !A){
7882                 this.dom.style.width = this.addUnits(width);
7883             }else{
7884                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7885             }
7886             return this;
7887         },
7888
7889         /**
7890          * Set the height of the element
7891          * @param {Number} height The new height
7892          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7893          * @return {Roo.Element} this
7894          */
7895          setHeight : function(height, animate){
7896             height = this.adjustHeight(height);
7897             if(!animate || !A){
7898                 this.dom.style.height = this.addUnits(height);
7899             }else{
7900                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7901             }
7902             return this;
7903         },
7904
7905         /**
7906          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7907          * @param {Number} width The new width
7908          * @param {Number} height The new height
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          setSize : function(width, height, animate){
7913             if(typeof width == "object"){ // in case of object from getSize()
7914                 height = width.height; width = width.width;
7915             }
7916             width = this.adjustWidth(width); height = this.adjustHeight(height);
7917             if(!animate || !A){
7918                 this.dom.style.width = this.addUnits(width);
7919                 this.dom.style.height = this.addUnits(height);
7920             }else{
7921                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7922             }
7923             return this;
7924         },
7925
7926         /**
7927          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7928          * @param {Number} x X value for new position (coordinates are page-based)
7929          * @param {Number} y Y value for new position (coordinates are page-based)
7930          * @param {Number} width The new width
7931          * @param {Number} height The new height
7932          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7933          * @return {Roo.Element} this
7934          */
7935         setBounds : function(x, y, width, height, animate){
7936             if(!animate || !A){
7937                 this.setSize(width, height);
7938                 this.setLocation(x, y);
7939             }else{
7940                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7941                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7942                               this.preanim(arguments, 4), 'motion');
7943             }
7944             return this;
7945         },
7946
7947         /**
7948          * 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.
7949          * @param {Roo.lib.Region} region The region to fill
7950          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7951          * @return {Roo.Element} this
7952          */
7953         setRegion : function(region, animate){
7954             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7955             return this;
7956         },
7957
7958         /**
7959          * Appends an event handler
7960          *
7961          * @param {String}   eventName     The type of event to append
7962          * @param {Function} fn        The method the event invokes
7963          * @param {Object} scope       (optional) The scope (this object) of the fn
7964          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7965          */
7966         addListener : function(eventName, fn, scope, options){
7967             if (this.dom) {
7968                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7969             }
7970         },
7971
7972         /**
7973          * Removes an event handler from this element
7974          * @param {String} eventName the type of event to remove
7975          * @param {Function} fn the method the event invokes
7976          * @return {Roo.Element} this
7977          */
7978         removeListener : function(eventName, fn){
7979             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7980             return this;
7981         },
7982
7983         /**
7984          * Removes all previous added listeners from this element
7985          * @return {Roo.Element} this
7986          */
7987         removeAllListeners : function(){
7988             E.purgeElement(this.dom);
7989             return this;
7990         },
7991
7992         relayEvent : function(eventName, observable){
7993             this.on(eventName, function(e){
7994                 observable.fireEvent(eventName, e);
7995             });
7996         },
7997
7998         /**
7999          * Set the opacity of the element
8000          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8001          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8002          * @return {Roo.Element} this
8003          */
8004          setOpacity : function(opacity, animate){
8005             if(!animate || !A){
8006                 var s = this.dom.style;
8007                 if(Roo.isIE){
8008                     s.zoom = 1;
8009                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8010                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8011                 }else{
8012                     s.opacity = opacity;
8013                 }
8014             }else{
8015                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8016             }
8017             return this;
8018         },
8019
8020         /**
8021          * Gets the left X coordinate
8022          * @param {Boolean} local True to get the local css position instead of page coordinate
8023          * @return {Number}
8024          */
8025         getLeft : function(local){
8026             if(!local){
8027                 return this.getX();
8028             }else{
8029                 return parseInt(this.getStyle("left"), 10) || 0;
8030             }
8031         },
8032
8033         /**
8034          * Gets the right X coordinate of the element (element X position + element width)
8035          * @param {Boolean} local True to get the local css position instead of page coordinate
8036          * @return {Number}
8037          */
8038         getRight : function(local){
8039             if(!local){
8040                 return this.getX() + this.getWidth();
8041             }else{
8042                 return (this.getLeft(true) + this.getWidth()) || 0;
8043             }
8044         },
8045
8046         /**
8047          * Gets the top Y coordinate
8048          * @param {Boolean} local True to get the local css position instead of page coordinate
8049          * @return {Number}
8050          */
8051         getTop : function(local) {
8052             if(!local){
8053                 return this.getY();
8054             }else{
8055                 return parseInt(this.getStyle("top"), 10) || 0;
8056             }
8057         },
8058
8059         /**
8060          * Gets the bottom Y coordinate of the element (element Y position + element height)
8061          * @param {Boolean} local True to get the local css position instead of page coordinate
8062          * @return {Number}
8063          */
8064         getBottom : function(local){
8065             if(!local){
8066                 return this.getY() + this.getHeight();
8067             }else{
8068                 return (this.getTop(true) + this.getHeight()) || 0;
8069             }
8070         },
8071
8072         /**
8073         * Initializes positioning on this element. If a desired position is not passed, it will make the
8074         * the element positioned relative IF it is not already positioned.
8075         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8076         * @param {Number} zIndex (optional) The zIndex to apply
8077         * @param {Number} x (optional) Set the page X position
8078         * @param {Number} y (optional) Set the page Y position
8079         */
8080         position : function(pos, zIndex, x, y){
8081             if(!pos){
8082                if(this.getStyle('position') == 'static'){
8083                    this.setStyle('position', 'relative');
8084                }
8085             }else{
8086                 this.setStyle("position", pos);
8087             }
8088             if(zIndex){
8089                 this.setStyle("z-index", zIndex);
8090             }
8091             if(x !== undefined && y !== undefined){
8092                 this.setXY([x, y]);
8093             }else if(x !== undefined){
8094                 this.setX(x);
8095             }else if(y !== undefined){
8096                 this.setY(y);
8097             }
8098         },
8099
8100         /**
8101         * Clear positioning back to the default when the document was loaded
8102         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8103         * @return {Roo.Element} this
8104          */
8105         clearPositioning : function(value){
8106             value = value ||'';
8107             this.setStyle({
8108                 "left": value,
8109                 "right": value,
8110                 "top": value,
8111                 "bottom": value,
8112                 "z-index": "",
8113                 "position" : "static"
8114             });
8115             return this;
8116         },
8117
8118         /**
8119         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8120         * snapshot before performing an update and then restoring the element.
8121         * @return {Object}
8122         */
8123         getPositioning : function(){
8124             var l = this.getStyle("left");
8125             var t = this.getStyle("top");
8126             return {
8127                 "position" : this.getStyle("position"),
8128                 "left" : l,
8129                 "right" : l ? "" : this.getStyle("right"),
8130                 "top" : t,
8131                 "bottom" : t ? "" : this.getStyle("bottom"),
8132                 "z-index" : this.getStyle("z-index")
8133             };
8134         },
8135
8136         /**
8137          * Gets the width of the border(s) for the specified side(s)
8138          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8139          * passing lr would get the border (l)eft width + the border (r)ight width.
8140          * @return {Number} The width of the sides passed added together
8141          */
8142         getBorderWidth : function(side){
8143             return this.addStyles(side, El.borders);
8144         },
8145
8146         /**
8147          * Gets the width of the padding(s) for the specified side(s)
8148          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8149          * passing lr would get the padding (l)eft + the padding (r)ight.
8150          * @return {Number} The padding of the sides passed added together
8151          */
8152         getPadding : function(side){
8153             return this.addStyles(side, El.paddings);
8154         },
8155
8156         /**
8157         * Set positioning with an object returned by getPositioning().
8158         * @param {Object} posCfg
8159         * @return {Roo.Element} this
8160          */
8161         setPositioning : function(pc){
8162             this.applyStyles(pc);
8163             if(pc.right == "auto"){
8164                 this.dom.style.right = "";
8165             }
8166             if(pc.bottom == "auto"){
8167                 this.dom.style.bottom = "";
8168             }
8169             return this;
8170         },
8171
8172         // private
8173         fixDisplay : function(){
8174             if(this.getStyle("display") == "none"){
8175                 this.setStyle("visibility", "hidden");
8176                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8177                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8178                     this.setStyle("display", "block");
8179                 }
8180             }
8181         },
8182
8183         /**
8184          * Quick set left and top adding default units
8185          * @param {String} left The left CSS property value
8186          * @param {String} top The top CSS property value
8187          * @return {Roo.Element} this
8188          */
8189          setLeftTop : function(left, top){
8190             this.dom.style.left = this.addUnits(left);
8191             this.dom.style.top = this.addUnits(top);
8192             return this;
8193         },
8194
8195         /**
8196          * Move this element relative to its current position.
8197          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8198          * @param {Number} distance How far to move the element in pixels
8199          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8200          * @return {Roo.Element} this
8201          */
8202          move : function(direction, distance, animate){
8203             var xy = this.getXY();
8204             direction = direction.toLowerCase();
8205             switch(direction){
8206                 case "l":
8207                 case "left":
8208                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8209                     break;
8210                case "r":
8211                case "right":
8212                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8213                     break;
8214                case "t":
8215                case "top":
8216                case "up":
8217                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8218                     break;
8219                case "b":
8220                case "bottom":
8221                case "down":
8222                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8223                     break;
8224             }
8225             return this;
8226         },
8227
8228         /**
8229          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8230          * @return {Roo.Element} this
8231          */
8232         clip : function(){
8233             if(!this.isClipped){
8234                this.isClipped = true;
8235                this.originalClip = {
8236                    "o": this.getStyle("overflow"),
8237                    "x": this.getStyle("overflow-x"),
8238                    "y": this.getStyle("overflow-y")
8239                };
8240                this.setStyle("overflow", "hidden");
8241                this.setStyle("overflow-x", "hidden");
8242                this.setStyle("overflow-y", "hidden");
8243             }
8244             return this;
8245         },
8246
8247         /**
8248          *  Return clipping (overflow) to original clipping before clip() was called
8249          * @return {Roo.Element} this
8250          */
8251         unclip : function(){
8252             if(this.isClipped){
8253                 this.isClipped = false;
8254                 var o = this.originalClip;
8255                 if(o.o){this.setStyle("overflow", o.o);}
8256                 if(o.x){this.setStyle("overflow-x", o.x);}
8257                 if(o.y){this.setStyle("overflow-y", o.y);}
8258             }
8259             return this;
8260         },
8261
8262
8263         /**
8264          * Gets the x,y coordinates specified by the anchor position on the element.
8265          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8266          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8267          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8268          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8269          * @return {Array} [x, y] An array containing the element's x and y coordinates
8270          */
8271         getAnchorXY : function(anchor, local, s){
8272             //Passing a different size is useful for pre-calculating anchors,
8273             //especially for anchored animations that change the el size.
8274
8275             var w, h, vp = false;
8276             if(!s){
8277                 var d = this.dom;
8278                 if(d == document.body || d == document){
8279                     vp = true;
8280                     w = D.getViewWidth(); h = D.getViewHeight();
8281                 }else{
8282                     w = this.getWidth(); h = this.getHeight();
8283                 }
8284             }else{
8285                 w = s.width;  h = s.height;
8286             }
8287             var x = 0, y = 0, r = Math.round;
8288             switch((anchor || "tl").toLowerCase()){
8289                 case "c":
8290                     x = r(w*.5);
8291                     y = r(h*.5);
8292                 break;
8293                 case "t":
8294                     x = r(w*.5);
8295                     y = 0;
8296                 break;
8297                 case "l":
8298                     x = 0;
8299                     y = r(h*.5);
8300                 break;
8301                 case "r":
8302                     x = w;
8303                     y = r(h*.5);
8304                 break;
8305                 case "b":
8306                     x = r(w*.5);
8307                     y = h;
8308                 break;
8309                 case "tl":
8310                     x = 0;
8311                     y = 0;
8312                 break;
8313                 case "bl":
8314                     x = 0;
8315                     y = h;
8316                 break;
8317                 case "br":
8318                     x = w;
8319                     y = h;
8320                 break;
8321                 case "tr":
8322                     x = w;
8323                     y = 0;
8324                 break;
8325             }
8326             if(local === true){
8327                 return [x, y];
8328             }
8329             if(vp){
8330                 var sc = this.getScroll();
8331                 return [x + sc.left, y + sc.top];
8332             }
8333             //Add the element's offset xy
8334             var o = this.getXY();
8335             return [x+o[0], y+o[1]];
8336         },
8337
8338         /**
8339          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8340          * supported position values.
8341          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8342          * @param {String} position The position to align to.
8343          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8344          * @return {Array} [x, y]
8345          */
8346         getAlignToXY : function(el, p, o){
8347             el = Roo.get(el);
8348             var d = this.dom;
8349             if(!el.dom){
8350                 throw "Element.alignTo with an element that doesn't exist";
8351             }
8352             var c = false; //constrain to viewport
8353             var p1 = "", p2 = "";
8354             o = o || [0,0];
8355
8356             if(!p){
8357                 p = "tl-bl";
8358             }else if(p == "?"){
8359                 p = "tl-bl?";
8360             }else if(p.indexOf("-") == -1){
8361                 p = "tl-" + p;
8362             }
8363             p = p.toLowerCase();
8364             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8365             if(!m){
8366                throw "Element.alignTo with an invalid alignment " + p;
8367             }
8368             p1 = m[1]; p2 = m[2]; c = !!m[3];
8369
8370             //Subtract the aligned el's internal xy from the target's offset xy
8371             //plus custom offset to get the aligned el's new offset xy
8372             var a1 = this.getAnchorXY(p1, true);
8373             var a2 = el.getAnchorXY(p2, false);
8374             var x = a2[0] - a1[0] + o[0];
8375             var y = a2[1] - a1[1] + o[1];
8376             if(c){
8377                 //constrain the aligned el to viewport if necessary
8378                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8379                 // 5px of margin for ie
8380                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8381
8382                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8383                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8384                 //otherwise swap the aligned el to the opposite border of the target.
8385                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8386                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8387                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8388                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8389
8390                var doc = document;
8391                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8392                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8393
8394                if((x+w) > dw + scrollX){
8395                     x = swapX ? r.left-w : dw+scrollX-w;
8396                 }
8397                if(x < scrollX){
8398                    x = swapX ? r.right : scrollX;
8399                }
8400                if((y+h) > dh + scrollY){
8401                     y = swapY ? r.top-h : dh+scrollY-h;
8402                 }
8403                if (y < scrollY){
8404                    y = swapY ? r.bottom : scrollY;
8405                }
8406             }
8407             return [x,y];
8408         },
8409
8410         // private
8411         getConstrainToXY : function(){
8412             var os = {top:0, left:0, bottom:0, right: 0};
8413
8414             return function(el, local, offsets, proposedXY){
8415                 el = Roo.get(el);
8416                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8417
8418                 var vw, vh, vx = 0, vy = 0;
8419                 if(el.dom == document.body || el.dom == document){
8420                     vw = Roo.lib.Dom.getViewWidth();
8421                     vh = Roo.lib.Dom.getViewHeight();
8422                 }else{
8423                     vw = el.dom.clientWidth;
8424                     vh = el.dom.clientHeight;
8425                     if(!local){
8426                         var vxy = el.getXY();
8427                         vx = vxy[0];
8428                         vy = vxy[1];
8429                     }
8430                 }
8431
8432                 var s = el.getScroll();
8433
8434                 vx += offsets.left + s.left;
8435                 vy += offsets.top + s.top;
8436
8437                 vw -= offsets.right;
8438                 vh -= offsets.bottom;
8439
8440                 var vr = vx+vw;
8441                 var vb = vy+vh;
8442
8443                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8444                 var x = xy[0], y = xy[1];
8445                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8446
8447                 // only move it if it needs it
8448                 var moved = false;
8449
8450                 // first validate right/bottom
8451                 if((x + w) > vr){
8452                     x = vr - w;
8453                     moved = true;
8454                 }
8455                 if((y + h) > vb){
8456                     y = vb - h;
8457                     moved = true;
8458                 }
8459                 // then make sure top/left isn't negative
8460                 if(x < vx){
8461                     x = vx;
8462                     moved = true;
8463                 }
8464                 if(y < vy){
8465                     y = vy;
8466                     moved = true;
8467                 }
8468                 return moved ? [x, y] : false;
8469             };
8470         }(),
8471
8472         // private
8473         adjustForConstraints : function(xy, parent, offsets){
8474             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8475         },
8476
8477         /**
8478          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8479          * document it aligns it to the viewport.
8480          * The position parameter is optional, and can be specified in any one of the following formats:
8481          * <ul>
8482          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8483          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8484          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8485          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8486          *   <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
8487          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8488          * </ul>
8489          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8490          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8491          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8492          * that specified in order to enforce the viewport constraints.
8493          * Following are all of the supported anchor positions:
8494     <pre>
8495     Value  Description
8496     -----  -----------------------------
8497     tl     The top left corner (default)
8498     t      The center of the top edge
8499     tr     The top right corner
8500     l      The center of the left edge
8501     c      In the center of the element
8502     r      The center of the right edge
8503     bl     The bottom left corner
8504     b      The center of the bottom edge
8505     br     The bottom right corner
8506     </pre>
8507     Example Usage:
8508     <pre><code>
8509     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8510     el.alignTo("other-el");
8511
8512     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8513     el.alignTo("other-el", "tr?");
8514
8515     // align the bottom right corner of el with the center left edge of other-el
8516     el.alignTo("other-el", "br-l?");
8517
8518     // align the center of el with the bottom left corner of other-el and
8519     // adjust the x position by -6 pixels (and the y position by 0)
8520     el.alignTo("other-el", "c-bl", [-6, 0]);
8521     </code></pre>
8522          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8523          * @param {String} position The position to align to.
8524          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8525          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8526          * @return {Roo.Element} this
8527          */
8528         alignTo : function(element, position, offsets, animate){
8529             var xy = this.getAlignToXY(element, position, offsets);
8530             this.setXY(xy, this.preanim(arguments, 3));
8531             return this;
8532         },
8533
8534         /**
8535          * Anchors an element to another element and realigns it when the window is resized.
8536          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8537          * @param {String} position The position to align to.
8538          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8539          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8540          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8541          * is a number, it is used as the buffer delay (defaults to 50ms).
8542          * @param {Function} callback The function to call after the animation finishes
8543          * @return {Roo.Element} this
8544          */
8545         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8546             var action = function(){
8547                 this.alignTo(el, alignment, offsets, animate);
8548                 Roo.callback(callback, this);
8549             };
8550             Roo.EventManager.onWindowResize(action, this);
8551             var tm = typeof monitorScroll;
8552             if(tm != 'undefined'){
8553                 Roo.EventManager.on(window, 'scroll', action, this,
8554                     {buffer: tm == 'number' ? monitorScroll : 50});
8555             }
8556             action.call(this); // align immediately
8557             return this;
8558         },
8559         /**
8560          * Clears any opacity settings from this element. Required in some cases for IE.
8561          * @return {Roo.Element} this
8562          */
8563         clearOpacity : function(){
8564             if (window.ActiveXObject) {
8565                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8566                     this.dom.style.filter = "";
8567                 }
8568             } else {
8569                 this.dom.style.opacity = "";
8570                 this.dom.style["-moz-opacity"] = "";
8571                 this.dom.style["-khtml-opacity"] = "";
8572             }
8573             return this;
8574         },
8575
8576         /**
8577          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8578          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8579          * @return {Roo.Element} this
8580          */
8581         hide : function(animate){
8582             this.setVisible(false, this.preanim(arguments, 0));
8583             return this;
8584         },
8585
8586         /**
8587         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8588         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8589          * @return {Roo.Element} this
8590          */
8591         show : function(animate){
8592             this.setVisible(true, this.preanim(arguments, 0));
8593             return this;
8594         },
8595
8596         /**
8597          * @private Test if size has a unit, otherwise appends the default
8598          */
8599         addUnits : function(size){
8600             return Roo.Element.addUnits(size, this.defaultUnit);
8601         },
8602
8603         /**
8604          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8605          * @return {Roo.Element} this
8606          */
8607         beginMeasure : function(){
8608             var el = this.dom;
8609             if(el.offsetWidth || el.offsetHeight){
8610                 return this; // offsets work already
8611             }
8612             var changed = [];
8613             var p = this.dom, b = document.body; // start with this element
8614             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8615                 var pe = Roo.get(p);
8616                 if(pe.getStyle('display') == 'none'){
8617                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8618                     p.style.visibility = "hidden";
8619                     p.style.display = "block";
8620                 }
8621                 p = p.parentNode;
8622             }
8623             this._measureChanged = changed;
8624             return this;
8625
8626         },
8627
8628         /**
8629          * Restores displays to before beginMeasure was called
8630          * @return {Roo.Element} this
8631          */
8632         endMeasure : function(){
8633             var changed = this._measureChanged;
8634             if(changed){
8635                 for(var i = 0, len = changed.length; i < len; i++) {
8636                     var r = changed[i];
8637                     r.el.style.visibility = r.visibility;
8638                     r.el.style.display = "none";
8639                 }
8640                 this._measureChanged = null;
8641             }
8642             return this;
8643         },
8644
8645         /**
8646         * Update the innerHTML of this element, optionally searching for and processing scripts
8647         * @param {String} html The new HTML
8648         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8649         * @param {Function} callback For async script loading you can be noticed when the update completes
8650         * @return {Roo.Element} this
8651          */
8652         update : function(html, loadScripts, callback){
8653             if(typeof html == "undefined"){
8654                 html = "";
8655             }
8656             if(loadScripts !== true){
8657                 this.dom.innerHTML = html;
8658                 if(typeof callback == "function"){
8659                     callback();
8660                 }
8661                 return this;
8662             }
8663             var id = Roo.id();
8664             var dom = this.dom;
8665
8666             html += '<span id="' + id + '"></span>';
8667
8668             E.onAvailable(id, function(){
8669                 var hd = document.getElementsByTagName("head")[0];
8670                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8671                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8672                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8673
8674                 var match;
8675                 while(match = re.exec(html)){
8676                     var attrs = match[1];
8677                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8678                     if(srcMatch && srcMatch[2]){
8679                        var s = document.createElement("script");
8680                        s.src = srcMatch[2];
8681                        var typeMatch = attrs.match(typeRe);
8682                        if(typeMatch && typeMatch[2]){
8683                            s.type = typeMatch[2];
8684                        }
8685                        hd.appendChild(s);
8686                     }else if(match[2] && match[2].length > 0){
8687                         if(window.execScript) {
8688                            window.execScript(match[2]);
8689                         } else {
8690                             /**
8691                              * eval:var:id
8692                              * eval:var:dom
8693                              * eval:var:html
8694                              * 
8695                              */
8696                            window.eval(match[2]);
8697                         }
8698                     }
8699                 }
8700                 var el = document.getElementById(id);
8701                 if(el){el.parentNode.removeChild(el);}
8702                 if(typeof callback == "function"){
8703                     callback();
8704                 }
8705             });
8706             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8707             return this;
8708         },
8709
8710         /**
8711          * Direct access to the UpdateManager update() method (takes the same parameters).
8712          * @param {String/Function} url The url for this request or a function to call to get the url
8713          * @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}
8714          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8715          * @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.
8716          * @return {Roo.Element} this
8717          */
8718         load : function(){
8719             var um = this.getUpdateManager();
8720             um.update.apply(um, arguments);
8721             return this;
8722         },
8723
8724         /**
8725         * Gets this element's UpdateManager
8726         * @return {Roo.UpdateManager} The UpdateManager
8727         */
8728         getUpdateManager : function(){
8729             if(!this.updateManager){
8730                 this.updateManager = new Roo.UpdateManager(this);
8731             }
8732             return this.updateManager;
8733         },
8734
8735         /**
8736          * Disables text selection for this element (normalized across browsers)
8737          * @return {Roo.Element} this
8738          */
8739         unselectable : function(){
8740             this.dom.unselectable = "on";
8741             this.swallowEvent("selectstart", true);
8742             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8743             this.addClass("x-unselectable");
8744             return this;
8745         },
8746
8747         /**
8748         * Calculates the x, y to center this element on the screen
8749         * @return {Array} The x, y values [x, y]
8750         */
8751         getCenterXY : function(){
8752             return this.getAlignToXY(document, 'c-c');
8753         },
8754
8755         /**
8756         * Centers the Element in either the viewport, or another Element.
8757         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8758         */
8759         center : function(centerIn){
8760             this.alignTo(centerIn || document, 'c-c');
8761             return this;
8762         },
8763
8764         /**
8765          * Tests various css rules/browsers to determine if this element uses a border box
8766          * @return {Boolean}
8767          */
8768         isBorderBox : function(){
8769             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8770         },
8771
8772         /**
8773          * Return a box {x, y, width, height} that can be used to set another elements
8774          * size/location to match this element.
8775          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8776          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8777          * @return {Object} box An object in the format {x, y, width, height}
8778          */
8779         getBox : function(contentBox, local){
8780             var xy;
8781             if(!local){
8782                 xy = this.getXY();
8783             }else{
8784                 var left = parseInt(this.getStyle("left"), 10) || 0;
8785                 var top = parseInt(this.getStyle("top"), 10) || 0;
8786                 xy = [left, top];
8787             }
8788             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8789             if(!contentBox){
8790                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8791             }else{
8792                 var l = this.getBorderWidth("l")+this.getPadding("l");
8793                 var r = this.getBorderWidth("r")+this.getPadding("r");
8794                 var t = this.getBorderWidth("t")+this.getPadding("t");
8795                 var b = this.getBorderWidth("b")+this.getPadding("b");
8796                 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)};
8797             }
8798             bx.right = bx.x + bx.width;
8799             bx.bottom = bx.y + bx.height;
8800             return bx;
8801         },
8802
8803         /**
8804          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8805          for more information about the sides.
8806          * @param {String} sides
8807          * @return {Number}
8808          */
8809         getFrameWidth : function(sides, onlyContentBox){
8810             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8811         },
8812
8813         /**
8814          * 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.
8815          * @param {Object} box The box to fill {x, y, width, height}
8816          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8817          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8818          * @return {Roo.Element} this
8819          */
8820         setBox : function(box, adjust, animate){
8821             var w = box.width, h = box.height;
8822             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8823                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8824                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8825             }
8826             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8827             return this;
8828         },
8829
8830         /**
8831          * Forces the browser to repaint this element
8832          * @return {Roo.Element} this
8833          */
8834          repaint : function(){
8835             var dom = this.dom;
8836             this.addClass("x-repaint");
8837             setTimeout(function(){
8838                 Roo.get(dom).removeClass("x-repaint");
8839             }, 1);
8840             return this;
8841         },
8842
8843         /**
8844          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8845          * then it returns the calculated width of the sides (see getPadding)
8846          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8847          * @return {Object/Number}
8848          */
8849         getMargins : function(side){
8850             if(!side){
8851                 return {
8852                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8853                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8854                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8855                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8856                 };
8857             }else{
8858                 return this.addStyles(side, El.margins);
8859              }
8860         },
8861
8862         // private
8863         addStyles : function(sides, styles){
8864             var val = 0, v, w;
8865             for(var i = 0, len = sides.length; i < len; i++){
8866                 v = this.getStyle(styles[sides.charAt(i)]);
8867                 if(v){
8868                      w = parseInt(v, 10);
8869                      if(w){ val += w; }
8870                 }
8871             }
8872             return val;
8873         },
8874
8875         /**
8876          * Creates a proxy element of this element
8877          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8878          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8879          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8880          * @return {Roo.Element} The new proxy element
8881          */
8882         createProxy : function(config, renderTo, matchBox){
8883             if(renderTo){
8884                 renderTo = Roo.getDom(renderTo);
8885             }else{
8886                 renderTo = document.body;
8887             }
8888             config = typeof config == "object" ?
8889                 config : {tag : "div", cls: config};
8890             var proxy = Roo.DomHelper.append(renderTo, config, true);
8891             if(matchBox){
8892                proxy.setBox(this.getBox());
8893             }
8894             return proxy;
8895         },
8896
8897         /**
8898          * Puts a mask over this element to disable user interaction. Requires core.css.
8899          * This method can only be applied to elements which accept child nodes.
8900          * @param {String} msg (optional) A message to display in the mask
8901          * @param {String} msgCls (optional) A css class to apply to the msg element
8902          * @return {Element} The mask  element
8903          */
8904         mask : function(msg, msgCls)
8905         {
8906             if(this.getStyle("position") == "static"){
8907                 this.setStyle("position", "relative");
8908             }
8909             if(!this._mask){
8910                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8911             }
8912             this.addClass("x-masked");
8913             this._mask.setDisplayed(true);
8914             
8915             // we wander
8916             var z = 0;
8917             var dom = this.dom
8918             while (dom && dom.style) {
8919                 if (!isNaN(parseInt(dom.style.zIndex))) {
8920                     z = Math.max(z, parseInt(dom.style.zIndex));
8921                 }
8922                 dom = dom.parentNode;
8923             }
8924             // if we are masking the body - then it hides everything..
8925             if (this.dom == document.body) {
8926                 z = 1000000;
8927                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8928                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8929             }
8930            
8931             if(typeof msg == 'string'){
8932                 if(!this._maskMsg){
8933                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8934                 }
8935                 var mm = this._maskMsg;
8936                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8937                 mm.dom.firstChild.innerHTML = msg;
8938                 mm.setDisplayed(true);
8939                 mm.center(this);
8940                 mm.setStyle('z-index', z + 102);
8941             }
8942             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8943                 this._mask.setHeight(this.getHeight());
8944             }
8945             this._mask.setStyle('z-index', z + 100);
8946             
8947             return this._mask;
8948         },
8949
8950         /**
8951          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8952          * it is cached for reuse.
8953          */
8954         unmask : function(removeEl){
8955             if(this._mask){
8956                 if(removeEl === true){
8957                     this._mask.remove();
8958                     delete this._mask;
8959                     if(this._maskMsg){
8960                         this._maskMsg.remove();
8961                         delete this._maskMsg;
8962                     }
8963                 }else{
8964                     this._mask.setDisplayed(false);
8965                     if(this._maskMsg){
8966                         this._maskMsg.setDisplayed(false);
8967                     }
8968                 }
8969             }
8970             this.removeClass("x-masked");
8971         },
8972
8973         /**
8974          * Returns true if this element is masked
8975          * @return {Boolean}
8976          */
8977         isMasked : function(){
8978             return this._mask && this._mask.isVisible();
8979         },
8980
8981         /**
8982          * Creates an iframe shim for this element to keep selects and other windowed objects from
8983          * showing through.
8984          * @return {Roo.Element} The new shim element
8985          */
8986         createShim : function(){
8987             var el = document.createElement('iframe');
8988             el.frameBorder = 'no';
8989             el.className = 'roo-shim';
8990             if(Roo.isIE && Roo.isSecure){
8991                 el.src = Roo.SSL_SECURE_URL;
8992             }
8993             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8994             shim.autoBoxAdjust = false;
8995             return shim;
8996         },
8997
8998         /**
8999          * Removes this element from the DOM and deletes it from the cache
9000          */
9001         remove : function(){
9002             if(this.dom.parentNode){
9003                 this.dom.parentNode.removeChild(this.dom);
9004             }
9005             delete El.cache[this.dom.id];
9006         },
9007
9008         /**
9009          * Sets up event handlers to add and remove a css class when the mouse is over this element
9010          * @param {String} className
9011          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9012          * mouseout events for children elements
9013          * @return {Roo.Element} this
9014          */
9015         addClassOnOver : function(className, preventFlicker){
9016             this.on("mouseover", function(){
9017                 Roo.fly(this, '_internal').addClass(className);
9018             }, this.dom);
9019             var removeFn = function(e){
9020                 if(preventFlicker !== true || !e.within(this, true)){
9021                     Roo.fly(this, '_internal').removeClass(className);
9022                 }
9023             };
9024             this.on("mouseout", removeFn, this.dom);
9025             return this;
9026         },
9027
9028         /**
9029          * Sets up event handlers to add and remove a css class when this element has the focus
9030          * @param {String} className
9031          * @return {Roo.Element} this
9032          */
9033         addClassOnFocus : function(className){
9034             this.on("focus", function(){
9035                 Roo.fly(this, '_internal').addClass(className);
9036             }, this.dom);
9037             this.on("blur", function(){
9038                 Roo.fly(this, '_internal').removeClass(className);
9039             }, this.dom);
9040             return this;
9041         },
9042         /**
9043          * 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)
9044          * @param {String} className
9045          * @return {Roo.Element} this
9046          */
9047         addClassOnClick : function(className){
9048             var dom = this.dom;
9049             this.on("mousedown", function(){
9050                 Roo.fly(dom, '_internal').addClass(className);
9051                 var d = Roo.get(document);
9052                 var fn = function(){
9053                     Roo.fly(dom, '_internal').removeClass(className);
9054                     d.removeListener("mouseup", fn);
9055                 };
9056                 d.on("mouseup", fn);
9057             });
9058             return this;
9059         },
9060
9061         /**
9062          * Stops the specified event from bubbling and optionally prevents the default action
9063          * @param {String} eventName
9064          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9065          * @return {Roo.Element} this
9066          */
9067         swallowEvent : function(eventName, preventDefault){
9068             var fn = function(e){
9069                 e.stopPropagation();
9070                 if(preventDefault){
9071                     e.preventDefault();
9072                 }
9073             };
9074             if(eventName instanceof Array){
9075                 for(var i = 0, len = eventName.length; i < len; i++){
9076                      this.on(eventName[i], fn);
9077                 }
9078                 return this;
9079             }
9080             this.on(eventName, fn);
9081             return this;
9082         },
9083
9084         /**
9085          * @private
9086          */
9087       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9088
9089         /**
9090          * Sizes this element to its parent element's dimensions performing
9091          * neccessary box adjustments.
9092          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9093          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9094          * @return {Roo.Element} this
9095          */
9096         fitToParent : function(monitorResize, targetParent) {
9097           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9098           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9099           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9100             return;
9101           }
9102           var p = Roo.get(targetParent || this.dom.parentNode);
9103           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9104           if (monitorResize === true) {
9105             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9106             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9107           }
9108           return this;
9109         },
9110
9111         /**
9112          * Gets the next sibling, skipping text nodes
9113          * @return {HTMLElement} The next sibling or null
9114          */
9115         getNextSibling : function(){
9116             var n = this.dom.nextSibling;
9117             while(n && n.nodeType != 1){
9118                 n = n.nextSibling;
9119             }
9120             return n;
9121         },
9122
9123         /**
9124          * Gets the previous sibling, skipping text nodes
9125          * @return {HTMLElement} The previous sibling or null
9126          */
9127         getPrevSibling : function(){
9128             var n = this.dom.previousSibling;
9129             while(n && n.nodeType != 1){
9130                 n = n.previousSibling;
9131             }
9132             return n;
9133         },
9134
9135
9136         /**
9137          * Appends the passed element(s) to this element
9138          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9139          * @return {Roo.Element} this
9140          */
9141         appendChild: function(el){
9142             el = Roo.get(el);
9143             el.appendTo(this);
9144             return this;
9145         },
9146
9147         /**
9148          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9149          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9150          * automatically generated with the specified attributes.
9151          * @param {HTMLElement} insertBefore (optional) a child element of this element
9152          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9153          * @return {Roo.Element} The new child element
9154          */
9155         createChild: function(config, insertBefore, returnDom){
9156             config = config || {tag:'div'};
9157             if(insertBefore){
9158                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9159             }
9160             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9161         },
9162
9163         /**
9164          * Appends this element to the passed element
9165          * @param {String/HTMLElement/Element} el The new parent element
9166          * @return {Roo.Element} this
9167          */
9168         appendTo: function(el){
9169             el = Roo.getDom(el);
9170             el.appendChild(this.dom);
9171             return this;
9172         },
9173
9174         /**
9175          * Inserts this element before the passed element in the DOM
9176          * @param {String/HTMLElement/Element} el The element to insert before
9177          * @return {Roo.Element} this
9178          */
9179         insertBefore: function(el){
9180             el = Roo.getDom(el);
9181             el.parentNode.insertBefore(this.dom, el);
9182             return this;
9183         },
9184
9185         /**
9186          * Inserts this element after the passed element in the DOM
9187          * @param {String/HTMLElement/Element} el The element to insert after
9188          * @return {Roo.Element} this
9189          */
9190         insertAfter: function(el){
9191             el = Roo.getDom(el);
9192             el.parentNode.insertBefore(this.dom, el.nextSibling);
9193             return this;
9194         },
9195
9196         /**
9197          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9198          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9199          * @return {Roo.Element} The new child
9200          */
9201         insertFirst: function(el, returnDom){
9202             el = el || {};
9203             if(typeof el == 'object' && !el.nodeType){ // dh config
9204                 return this.createChild(el, this.dom.firstChild, returnDom);
9205             }else{
9206                 el = Roo.getDom(el);
9207                 this.dom.insertBefore(el, this.dom.firstChild);
9208                 return !returnDom ? Roo.get(el) : el;
9209             }
9210         },
9211
9212         /**
9213          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9214          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9215          * @param {String} where (optional) 'before' or 'after' defaults to before
9216          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9217          * @return {Roo.Element} the inserted Element
9218          */
9219         insertSibling: function(el, where, returnDom){
9220             where = where ? where.toLowerCase() : 'before';
9221             el = el || {};
9222             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9223
9224             if(typeof el == 'object' && !el.nodeType){ // dh config
9225                 if(where == 'after' && !this.dom.nextSibling){
9226                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9227                 }else{
9228                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9229                 }
9230
9231             }else{
9232                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9233                             where == 'before' ? this.dom : this.dom.nextSibling);
9234                 if(!returnDom){
9235                     rt = Roo.get(rt);
9236                 }
9237             }
9238             return rt;
9239         },
9240
9241         /**
9242          * Creates and wraps this element with another element
9243          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9244          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245          * @return {HTMLElement/Element} The newly created wrapper element
9246          */
9247         wrap: function(config, returnDom){
9248             if(!config){
9249                 config = {tag: "div"};
9250             }
9251             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9252             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9253             return newEl;
9254         },
9255
9256         /**
9257          * Replaces the passed element with this element
9258          * @param {String/HTMLElement/Element} el The element to replace
9259          * @return {Roo.Element} this
9260          */
9261         replace: function(el){
9262             el = Roo.get(el);
9263             this.insertBefore(el);
9264             el.remove();
9265             return this;
9266         },
9267
9268         /**
9269          * Inserts an html fragment into this element
9270          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9271          * @param {String} html The HTML fragment
9272          * @param {Boolean} returnEl True to return an Roo.Element
9273          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9274          */
9275         insertHtml : function(where, html, returnEl){
9276             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9277             return returnEl ? Roo.get(el) : el;
9278         },
9279
9280         /**
9281          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9282          * @param {Object} o The object with the attributes
9283          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9284          * @return {Roo.Element} this
9285          */
9286         set : function(o, useSet){
9287             var el = this.dom;
9288             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9289             for(var attr in o){
9290                 if(attr == "style" || typeof o[attr] == "function") continue;
9291                 if(attr=="cls"){
9292                     el.className = o["cls"];
9293                 }else{
9294                     if(useSet) el.setAttribute(attr, o[attr]);
9295                     else el[attr] = o[attr];
9296                 }
9297             }
9298             if(o.style){
9299                 Roo.DomHelper.applyStyles(el, o.style);
9300             }
9301             return this;
9302         },
9303
9304         /**
9305          * Convenience method for constructing a KeyMap
9306          * @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:
9307          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9308          * @param {Function} fn The function to call
9309          * @param {Object} scope (optional) The scope of the function
9310          * @return {Roo.KeyMap} The KeyMap created
9311          */
9312         addKeyListener : function(key, fn, scope){
9313             var config;
9314             if(typeof key != "object" || key instanceof Array){
9315                 config = {
9316                     key: key,
9317                     fn: fn,
9318                     scope: scope
9319                 };
9320             }else{
9321                 config = {
9322                     key : key.key,
9323                     shift : key.shift,
9324                     ctrl : key.ctrl,
9325                     alt : key.alt,
9326                     fn: fn,
9327                     scope: scope
9328                 };
9329             }
9330             return new Roo.KeyMap(this, config);
9331         },
9332
9333         /**
9334          * Creates a KeyMap for this element
9335          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9336          * @return {Roo.KeyMap} The KeyMap created
9337          */
9338         addKeyMap : function(config){
9339             return new Roo.KeyMap(this, config);
9340         },
9341
9342         /**
9343          * Returns true if this element is scrollable.
9344          * @return {Boolean}
9345          */
9346          isScrollable : function(){
9347             var dom = this.dom;
9348             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9349         },
9350
9351         /**
9352          * 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().
9353          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9354          * @param {Number} value The new scroll value
9355          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9356          * @return {Element} this
9357          */
9358
9359         scrollTo : function(side, value, animate){
9360             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9361             if(!animate || !A){
9362                 this.dom[prop] = value;
9363             }else{
9364                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9365                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9366             }
9367             return this;
9368         },
9369
9370         /**
9371          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9372          * within this element's scrollable range.
9373          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9374          * @param {Number} distance How far to scroll the element in pixels
9375          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9376          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9377          * was scrolled as far as it could go.
9378          */
9379          scroll : function(direction, distance, animate){
9380              if(!this.isScrollable()){
9381                  return;
9382              }
9383              var el = this.dom;
9384              var l = el.scrollLeft, t = el.scrollTop;
9385              var w = el.scrollWidth, h = el.scrollHeight;
9386              var cw = el.clientWidth, ch = el.clientHeight;
9387              direction = direction.toLowerCase();
9388              var scrolled = false;
9389              var a = this.preanim(arguments, 2);
9390              switch(direction){
9391                  case "l":
9392                  case "left":
9393                      if(w - l > cw){
9394                          var v = Math.min(l + distance, w-cw);
9395                          this.scrollTo("left", v, a);
9396                          scrolled = true;
9397                      }
9398                      break;
9399                 case "r":
9400                 case "right":
9401                      if(l > 0){
9402                          var v = Math.max(l - distance, 0);
9403                          this.scrollTo("left", v, a);
9404                          scrolled = true;
9405                      }
9406                      break;
9407                 case "t":
9408                 case "top":
9409                 case "up":
9410                      if(t > 0){
9411                          var v = Math.max(t - distance, 0);
9412                          this.scrollTo("top", v, a);
9413                          scrolled = true;
9414                      }
9415                      break;
9416                 case "b":
9417                 case "bottom":
9418                 case "down":
9419                      if(h - t > ch){
9420                          var v = Math.min(t + distance, h-ch);
9421                          this.scrollTo("top", v, a);
9422                          scrolled = true;
9423                      }
9424                      break;
9425              }
9426              return scrolled;
9427         },
9428
9429         /**
9430          * Translates the passed page coordinates into left/top css values for this element
9431          * @param {Number/Array} x The page x or an array containing [x, y]
9432          * @param {Number} y The page y
9433          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9434          */
9435         translatePoints : function(x, y){
9436             if(typeof x == 'object' || x instanceof Array){
9437                 y = x[1]; x = x[0];
9438             }
9439             var p = this.getStyle('position');
9440             var o = this.getXY();
9441
9442             var l = parseInt(this.getStyle('left'), 10);
9443             var t = parseInt(this.getStyle('top'), 10);
9444
9445             if(isNaN(l)){
9446                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9447             }
9448             if(isNaN(t)){
9449                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9450             }
9451
9452             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9453         },
9454
9455         /**
9456          * Returns the current scroll position of the element.
9457          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9458          */
9459         getScroll : function(){
9460             var d = this.dom, doc = document;
9461             if(d == doc || d == doc.body){
9462                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9463                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9464                 return {left: l, top: t};
9465             }else{
9466                 return {left: d.scrollLeft, top: d.scrollTop};
9467             }
9468         },
9469
9470         /**
9471          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9472          * are convert to standard 6 digit hex color.
9473          * @param {String} attr The css attribute
9474          * @param {String} defaultValue The default value to use when a valid color isn't found
9475          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9476          * YUI color anims.
9477          */
9478         getColor : function(attr, defaultValue, prefix){
9479             var v = this.getStyle(attr);
9480             if(!v || v == "transparent" || v == "inherit") {
9481                 return defaultValue;
9482             }
9483             var color = typeof prefix == "undefined" ? "#" : prefix;
9484             if(v.substr(0, 4) == "rgb("){
9485                 var rvs = v.slice(4, v.length -1).split(",");
9486                 for(var i = 0; i < 3; i++){
9487                     var h = parseInt(rvs[i]).toString(16);
9488                     if(h < 16){
9489                         h = "0" + h;
9490                     }
9491                     color += h;
9492                 }
9493             } else {
9494                 if(v.substr(0, 1) == "#"){
9495                     if(v.length == 4) {
9496                         for(var i = 1; i < 4; i++){
9497                             var c = v.charAt(i);
9498                             color +=  c + c;
9499                         }
9500                     }else if(v.length == 7){
9501                         color += v.substr(1);
9502                     }
9503                 }
9504             }
9505             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9506         },
9507
9508         /**
9509          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9510          * gradient background, rounded corners and a 4-way shadow.
9511          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9512          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9513          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9514          * @return {Roo.Element} this
9515          */
9516         boxWrap : function(cls){
9517             cls = cls || 'x-box';
9518             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9519             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9520             return el;
9521         },
9522
9523         /**
9524          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9525          * @param {String} namespace The namespace in which to look for the attribute
9526          * @param {String} name The attribute name
9527          * @return {String} The attribute value
9528          */
9529         getAttributeNS : Roo.isIE ? function(ns, name){
9530             var d = this.dom;
9531             var type = typeof d[ns+":"+name];
9532             if(type != 'undefined' && type != 'unknown'){
9533                 return d[ns+":"+name];
9534             }
9535             return d[name];
9536         } : function(ns, name){
9537             var d = this.dom;
9538             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9539         }
9540     };
9541
9542     var ep = El.prototype;
9543
9544     /**
9545      * Appends an event handler (Shorthand for addListener)
9546      * @param {String}   eventName     The type of event to append
9547      * @param {Function} fn        The method the event invokes
9548      * @param {Object} scope       (optional) The scope (this object) of the fn
9549      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9550      * @method
9551      */
9552     ep.on = ep.addListener;
9553         // backwards compat
9554     ep.mon = ep.addListener;
9555
9556     /**
9557      * Removes an event handler from this element (shorthand for removeListener)
9558      * @param {String} eventName the type of event to remove
9559      * @param {Function} fn the method the event invokes
9560      * @return {Roo.Element} this
9561      * @method
9562      */
9563     ep.un = ep.removeListener;
9564
9565     /**
9566      * true to automatically adjust width and height settings for box-model issues (default to true)
9567      */
9568     ep.autoBoxAdjust = true;
9569
9570     // private
9571     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9572
9573     // private
9574     El.addUnits = function(v, defaultUnit){
9575         if(v === "" || v == "auto"){
9576             return v;
9577         }
9578         if(v === undefined){
9579             return '';
9580         }
9581         if(typeof v == "number" || !El.unitPattern.test(v)){
9582             return v + (defaultUnit || 'px');
9583         }
9584         return v;
9585     };
9586
9587     // special markup used throughout Roo when box wrapping elements
9588     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>';
9589     /**
9590      * Visibility mode constant - Use visibility to hide element
9591      * @static
9592      * @type Number
9593      */
9594     El.VISIBILITY = 1;
9595     /**
9596      * Visibility mode constant - Use display to hide element
9597      * @static
9598      * @type Number
9599      */
9600     El.DISPLAY = 2;
9601
9602     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9603     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9604     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9605
9606
9607
9608     /**
9609      * @private
9610      */
9611     El.cache = {};
9612
9613     var docEl;
9614
9615     /**
9616      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9617      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9618      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9619      * @return {Element} The Element object
9620      * @static
9621      */
9622     El.get = function(el){
9623         var ex, elm, id;
9624         if(!el){ return null; }
9625         if(typeof el == "string"){ // element id
9626             if(!(elm = document.getElementById(el))){
9627                 return null;
9628             }
9629             if(ex = El.cache[el]){
9630                 ex.dom = elm;
9631             }else{
9632                 ex = El.cache[el] = new El(elm);
9633             }
9634             return ex;
9635         }else if(el.tagName){ // dom element
9636             if(!(id = el.id)){
9637                 id = Roo.id(el);
9638             }
9639             if(ex = El.cache[id]){
9640                 ex.dom = el;
9641             }else{
9642                 ex = El.cache[id] = new El(el);
9643             }
9644             return ex;
9645         }else if(el instanceof El){
9646             if(el != docEl){
9647                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9648                                                               // catch case where it hasn't been appended
9649                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9650             }
9651             return el;
9652         }else if(el.isComposite){
9653             return el;
9654         }else if(el instanceof Array){
9655             return El.select(el);
9656         }else if(el == document){
9657             // create a bogus element object representing the document object
9658             if(!docEl){
9659                 var f = function(){};
9660                 f.prototype = El.prototype;
9661                 docEl = new f();
9662                 docEl.dom = document;
9663             }
9664             return docEl;
9665         }
9666         return null;
9667     };
9668
9669     // private
9670     El.uncache = function(el){
9671         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9672             if(a[i]){
9673                 delete El.cache[a[i].id || a[i]];
9674             }
9675         }
9676     };
9677
9678     // private
9679     // Garbage collection - uncache elements/purge listeners on orphaned elements
9680     // so we don't hold a reference and cause the browser to retain them
9681     El.garbageCollect = function(){
9682         if(!Roo.enableGarbageCollector){
9683             clearInterval(El.collectorThread);
9684             return;
9685         }
9686         for(var eid in El.cache){
9687             var el = El.cache[eid], d = el.dom;
9688             // -------------------------------------------------------
9689             // Determining what is garbage:
9690             // -------------------------------------------------------
9691             // !d
9692             // dom node is null, definitely garbage
9693             // -------------------------------------------------------
9694             // !d.parentNode
9695             // no parentNode == direct orphan, definitely garbage
9696             // -------------------------------------------------------
9697             // !d.offsetParent && !document.getElementById(eid)
9698             // display none elements have no offsetParent so we will
9699             // also try to look it up by it's id. However, check
9700             // offsetParent first so we don't do unneeded lookups.
9701             // This enables collection of elements that are not orphans
9702             // directly, but somewhere up the line they have an orphan
9703             // parent.
9704             // -------------------------------------------------------
9705             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9706                 delete El.cache[eid];
9707                 if(d && Roo.enableListenerCollection){
9708                     E.purgeElement(d);
9709                 }
9710             }
9711         }
9712     }
9713     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9714
9715
9716     // dom is optional
9717     El.Flyweight = function(dom){
9718         this.dom = dom;
9719     };
9720     El.Flyweight.prototype = El.prototype;
9721
9722     El._flyweights = {};
9723     /**
9724      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9725      * the dom node can be overwritten by other code.
9726      * @param {String/HTMLElement} el The dom node or id
9727      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9728      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9729      * @static
9730      * @return {Element} The shared Element object
9731      */
9732     El.fly = function(el, named){
9733         named = named || '_global';
9734         el = Roo.getDom(el);
9735         if(!el){
9736             return null;
9737         }
9738         if(!El._flyweights[named]){
9739             El._flyweights[named] = new El.Flyweight();
9740         }
9741         El._flyweights[named].dom = el;
9742         return El._flyweights[named];
9743     };
9744
9745     /**
9746      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9747      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9748      * Shorthand of {@link Roo.Element#get}
9749      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9750      * @return {Element} The Element object
9751      * @member Roo
9752      * @method get
9753      */
9754     Roo.get = El.get;
9755     /**
9756      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9757      * the dom node can be overwritten by other code.
9758      * Shorthand of {@link Roo.Element#fly}
9759      * @param {String/HTMLElement} el The dom node or id
9760      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9761      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9762      * @static
9763      * @return {Element} The shared Element object
9764      * @member Roo
9765      * @method fly
9766      */
9767     Roo.fly = El.fly;
9768
9769     // speedy lookup for elements never to box adjust
9770     var noBoxAdjust = Roo.isStrict ? {
9771         select:1
9772     } : {
9773         input:1, select:1, textarea:1
9774     };
9775     if(Roo.isIE || Roo.isGecko){
9776         noBoxAdjust['button'] = 1;
9777     }
9778
9779
9780     Roo.EventManager.on(window, 'unload', function(){
9781         delete El.cache;
9782         delete El._flyweights;
9783     });
9784 })();
9785
9786
9787
9788
9789 if(Roo.DomQuery){
9790     Roo.Element.selectorFunction = Roo.DomQuery.select;
9791 }
9792
9793 Roo.Element.select = function(selector, unique, root){
9794     var els;
9795     if(typeof selector == "string"){
9796         els = Roo.Element.selectorFunction(selector, root);
9797     }else if(selector.length !== undefined){
9798         els = selector;
9799     }else{
9800         throw "Invalid selector";
9801     }
9802     if(unique === true){
9803         return new Roo.CompositeElement(els);
9804     }else{
9805         return new Roo.CompositeElementLite(els);
9806     }
9807 };
9808 /**
9809  * Selects elements based on the passed CSS selector to enable working on them as 1.
9810  * @param {String/Array} selector The CSS selector or an array of elements
9811  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9812  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9813  * @return {CompositeElementLite/CompositeElement}
9814  * @member Roo
9815  * @method select
9816  */
9817 Roo.select = Roo.Element.select;
9818
9819
9820
9821
9822
9823
9824
9825
9826
9827
9828
9829
9830
9831
9832 /*
9833  * Based on:
9834  * Ext JS Library 1.1.1
9835  * Copyright(c) 2006-2007, Ext JS, LLC.
9836  *
9837  * Originally Released Under LGPL - original licence link has changed is not relivant.
9838  *
9839  * Fork - LGPL
9840  * <script type="text/javascript">
9841  */
9842
9843
9844
9845 //Notifies Element that fx methods are available
9846 Roo.enableFx = true;
9847
9848 /**
9849  * @class Roo.Fx
9850  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9851  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9852  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9853  * Element effects to work.</p><br/>
9854  *
9855  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9856  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9857  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9858  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9859  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9860  * expected results and should be done with care.</p><br/>
9861  *
9862  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9863  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9864 <pre>
9865 Value  Description
9866 -----  -----------------------------
9867 tl     The top left corner
9868 t      The center of the top edge
9869 tr     The top right corner
9870 l      The center of the left edge
9871 r      The center of the right edge
9872 bl     The bottom left corner
9873 b      The center of the bottom edge
9874 br     The bottom right corner
9875 </pre>
9876  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9877  * below are common options that can be passed to any Fx method.</b>
9878  * @cfg {Function} callback A function called when the effect is finished
9879  * @cfg {Object} scope The scope of the effect function
9880  * @cfg {String} easing A valid Easing value for the effect
9881  * @cfg {String} afterCls A css class to apply after the effect
9882  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9883  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9884  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9885  * effects that end with the element being visually hidden, ignored otherwise)
9886  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9887  * a function which returns such a specification that will be applied to the Element after the effect finishes
9888  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9889  * @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
9890  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9891  */
9892 Roo.Fx = {
9893         /**
9894          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9895          * origin for the slide effect.  This function automatically handles wrapping the element with
9896          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9897          * Usage:
9898          *<pre><code>
9899 // default: slide the element in from the top
9900 el.slideIn();
9901
9902 // custom: slide the element in from the right with a 2-second duration
9903 el.slideIn('r', { duration: 2 });
9904
9905 // common config options shown with default values
9906 el.slideIn('t', {
9907     easing: 'easeOut',
9908     duration: .5
9909 });
9910 </code></pre>
9911          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9912          * @param {Object} options (optional) Object literal with any of the Fx config options
9913          * @return {Roo.Element} The Element
9914          */
9915     slideIn : function(anchor, o){
9916         var el = this.getFxEl();
9917         o = o || {};
9918
9919         el.queueFx(o, function(){
9920
9921             anchor = anchor || "t";
9922
9923             // fix display to visibility
9924             this.fixDisplay();
9925
9926             // restore values after effect
9927             var r = this.getFxRestore();
9928             var b = this.getBox();
9929             // fixed size for slide
9930             this.setSize(b);
9931
9932             // wrap if needed
9933             var wrap = this.fxWrap(r.pos, o, "hidden");
9934
9935             var st = this.dom.style;
9936             st.visibility = "visible";
9937             st.position = "absolute";
9938
9939             // clear out temp styles after slide and unwrap
9940             var after = function(){
9941                 el.fxUnwrap(wrap, r.pos, o);
9942                 st.width = r.width;
9943                 st.height = r.height;
9944                 el.afterFx(o);
9945             };
9946             // time to calc the positions
9947             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9948
9949             switch(anchor.toLowerCase()){
9950                 case "t":
9951                     wrap.setSize(b.width, 0);
9952                     st.left = st.bottom = "0";
9953                     a = {height: bh};
9954                 break;
9955                 case "l":
9956                     wrap.setSize(0, b.height);
9957                     st.right = st.top = "0";
9958                     a = {width: bw};
9959                 break;
9960                 case "r":
9961                     wrap.setSize(0, b.height);
9962                     wrap.setX(b.right);
9963                     st.left = st.top = "0";
9964                     a = {width: bw, points: pt};
9965                 break;
9966                 case "b":
9967                     wrap.setSize(b.width, 0);
9968                     wrap.setY(b.bottom);
9969                     st.left = st.top = "0";
9970                     a = {height: bh, points: pt};
9971                 break;
9972                 case "tl":
9973                     wrap.setSize(0, 0);
9974                     st.right = st.bottom = "0";
9975                     a = {width: bw, height: bh};
9976                 break;
9977                 case "bl":
9978                     wrap.setSize(0, 0);
9979                     wrap.setY(b.y+b.height);
9980                     st.right = st.top = "0";
9981                     a = {width: bw, height: bh, points: pt};
9982                 break;
9983                 case "br":
9984                     wrap.setSize(0, 0);
9985                     wrap.setXY([b.right, b.bottom]);
9986                     st.left = st.top = "0";
9987                     a = {width: bw, height: bh, points: pt};
9988                 break;
9989                 case "tr":
9990                     wrap.setSize(0, 0);
9991                     wrap.setX(b.x+b.width);
9992                     st.left = st.bottom = "0";
9993                     a = {width: bw, height: bh, points: pt};
9994                 break;
9995             }
9996             this.dom.style.visibility = "visible";
9997             wrap.show();
9998
9999             arguments.callee.anim = wrap.fxanim(a,
10000                 o,
10001                 'motion',
10002                 .5,
10003                 'easeOut', after);
10004         });
10005         return this;
10006     },
10007     
10008         /**
10009          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10010          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10011          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10012          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10013          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10014          * Usage:
10015          *<pre><code>
10016 // default: slide the element out to the top
10017 el.slideOut();
10018
10019 // custom: slide the element out to the right with a 2-second duration
10020 el.slideOut('r', { duration: 2 });
10021
10022 // common config options shown with default values
10023 el.slideOut('t', {
10024     easing: 'easeOut',
10025     duration: .5,
10026     remove: false,
10027     useDisplay: false
10028 });
10029 </code></pre>
10030          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10031          * @param {Object} options (optional) Object literal with any of the Fx config options
10032          * @return {Roo.Element} The Element
10033          */
10034     slideOut : function(anchor, o){
10035         var el = this.getFxEl();
10036         o = o || {};
10037
10038         el.queueFx(o, function(){
10039
10040             anchor = anchor || "t";
10041
10042             // restore values after effect
10043             var r = this.getFxRestore();
10044             
10045             var b = this.getBox();
10046             // fixed size for slide
10047             this.setSize(b);
10048
10049             // wrap if needed
10050             var wrap = this.fxWrap(r.pos, o, "visible");
10051
10052             var st = this.dom.style;
10053             st.visibility = "visible";
10054             st.position = "absolute";
10055
10056             wrap.setSize(b);
10057
10058             var after = function(){
10059                 if(o.useDisplay){
10060                     el.setDisplayed(false);
10061                 }else{
10062                     el.hide();
10063                 }
10064
10065                 el.fxUnwrap(wrap, r.pos, o);
10066
10067                 st.width = r.width;
10068                 st.height = r.height;
10069
10070                 el.afterFx(o);
10071             };
10072
10073             var a, zero = {to: 0};
10074             switch(anchor.toLowerCase()){
10075                 case "t":
10076                     st.left = st.bottom = "0";
10077                     a = {height: zero};
10078                 break;
10079                 case "l":
10080                     st.right = st.top = "0";
10081                     a = {width: zero};
10082                 break;
10083                 case "r":
10084                     st.left = st.top = "0";
10085                     a = {width: zero, points: {to:[b.right, b.y]}};
10086                 break;
10087                 case "b":
10088                     st.left = st.top = "0";
10089                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10090                 break;
10091                 case "tl":
10092                     st.right = st.bottom = "0";
10093                     a = {width: zero, height: zero};
10094                 break;
10095                 case "bl":
10096                     st.right = st.top = "0";
10097                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10098                 break;
10099                 case "br":
10100                     st.left = st.top = "0";
10101                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10102                 break;
10103                 case "tr":
10104                     st.left = st.bottom = "0";
10105                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10106                 break;
10107             }
10108
10109             arguments.callee.anim = wrap.fxanim(a,
10110                 o,
10111                 'motion',
10112                 .5,
10113                 "easeOut", after);
10114         });
10115         return this;
10116     },
10117
10118         /**
10119          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10120          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10121          * The element must be removed from the DOM using the 'remove' config option if desired.
10122          * Usage:
10123          *<pre><code>
10124 // default
10125 el.puff();
10126
10127 // common config options shown with default values
10128 el.puff({
10129     easing: 'easeOut',
10130     duration: .5,
10131     remove: false,
10132     useDisplay: false
10133 });
10134 </code></pre>
10135          * @param {Object} options (optional) Object literal with any of the Fx config options
10136          * @return {Roo.Element} The Element
10137          */
10138     puff : function(o){
10139         var el = this.getFxEl();
10140         o = o || {};
10141
10142         el.queueFx(o, function(){
10143             this.clearOpacity();
10144             this.show();
10145
10146             // restore values after effect
10147             var r = this.getFxRestore();
10148             var st = this.dom.style;
10149
10150             var after = function(){
10151                 if(o.useDisplay){
10152                     el.setDisplayed(false);
10153                 }else{
10154                     el.hide();
10155                 }
10156
10157                 el.clearOpacity();
10158
10159                 el.setPositioning(r.pos);
10160                 st.width = r.width;
10161                 st.height = r.height;
10162                 st.fontSize = '';
10163                 el.afterFx(o);
10164             };
10165
10166             var width = this.getWidth();
10167             var height = this.getHeight();
10168
10169             arguments.callee.anim = this.fxanim({
10170                     width : {to: this.adjustWidth(width * 2)},
10171                     height : {to: this.adjustHeight(height * 2)},
10172                     points : {by: [-(width * .5), -(height * .5)]},
10173                     opacity : {to: 0},
10174                     fontSize: {to:200, unit: "%"}
10175                 },
10176                 o,
10177                 'motion',
10178                 .5,
10179                 "easeOut", after);
10180         });
10181         return this;
10182     },
10183
10184         /**
10185          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10186          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10187          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10188          * Usage:
10189          *<pre><code>
10190 // default
10191 el.switchOff();
10192
10193 // all config options shown with default values
10194 el.switchOff({
10195     easing: 'easeIn',
10196     duration: .3,
10197     remove: false,
10198     useDisplay: false
10199 });
10200 </code></pre>
10201          * @param {Object} options (optional) Object literal with any of the Fx config options
10202          * @return {Roo.Element} The Element
10203          */
10204     switchOff : function(o){
10205         var el = this.getFxEl();
10206         o = o || {};
10207
10208         el.queueFx(o, function(){
10209             this.clearOpacity();
10210             this.clip();
10211
10212             // restore values after effect
10213             var r = this.getFxRestore();
10214             var st = this.dom.style;
10215
10216             var after = function(){
10217                 if(o.useDisplay){
10218                     el.setDisplayed(false);
10219                 }else{
10220                     el.hide();
10221                 }
10222
10223                 el.clearOpacity();
10224                 el.setPositioning(r.pos);
10225                 st.width = r.width;
10226                 st.height = r.height;
10227
10228                 el.afterFx(o);
10229             };
10230
10231             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10232                 this.clearOpacity();
10233                 (function(){
10234                     this.fxanim({
10235                         height:{to:1},
10236                         points:{by:[0, this.getHeight() * .5]}
10237                     }, o, 'motion', 0.3, 'easeIn', after);
10238                 }).defer(100, this);
10239             });
10240         });
10241         return this;
10242     },
10243
10244     /**
10245      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10246      * changed using the "attr" config option) and then fading back to the original color. If no original
10247      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10248      * Usage:
10249 <pre><code>
10250 // default: highlight background to yellow
10251 el.highlight();
10252
10253 // custom: highlight foreground text to blue for 2 seconds
10254 el.highlight("0000ff", { attr: 'color', duration: 2 });
10255
10256 // common config options shown with default values
10257 el.highlight("ffff9c", {
10258     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10259     endColor: (current color) or "ffffff",
10260     easing: 'easeIn',
10261     duration: 1
10262 });
10263 </code></pre>
10264      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10265      * @param {Object} options (optional) Object literal with any of the Fx config options
10266      * @return {Roo.Element} The Element
10267      */ 
10268     highlight : function(color, o){
10269         var el = this.getFxEl();
10270         o = o || {};
10271
10272         el.queueFx(o, function(){
10273             color = color || "ffff9c";
10274             attr = o.attr || "backgroundColor";
10275
10276             this.clearOpacity();
10277             this.show();
10278
10279             var origColor = this.getColor(attr);
10280             var restoreColor = this.dom.style[attr];
10281             endColor = (o.endColor || origColor) || "ffffff";
10282
10283             var after = function(){
10284                 el.dom.style[attr] = restoreColor;
10285                 el.afterFx(o);
10286             };
10287
10288             var a = {};
10289             a[attr] = {from: color, to: endColor};
10290             arguments.callee.anim = this.fxanim(a,
10291                 o,
10292                 'color',
10293                 1,
10294                 'easeIn', after);
10295         });
10296         return this;
10297     },
10298
10299    /**
10300     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10301     * Usage:
10302 <pre><code>
10303 // default: a single light blue ripple
10304 el.frame();
10305
10306 // custom: 3 red ripples lasting 3 seconds total
10307 el.frame("ff0000", 3, { duration: 3 });
10308
10309 // common config options shown with default values
10310 el.frame("C3DAF9", 1, {
10311     duration: 1 //duration of entire animation (not each individual ripple)
10312     // Note: Easing is not configurable and will be ignored if included
10313 });
10314 </code></pre>
10315     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10316     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10317     * @param {Object} options (optional) Object literal with any of the Fx config options
10318     * @return {Roo.Element} The Element
10319     */
10320     frame : function(color, count, o){
10321         var el = this.getFxEl();
10322         o = o || {};
10323
10324         el.queueFx(o, function(){
10325             color = color || "#C3DAF9";
10326             if(color.length == 6){
10327                 color = "#" + color;
10328             }
10329             count = count || 1;
10330             duration = o.duration || 1;
10331             this.show();
10332
10333             var b = this.getBox();
10334             var animFn = function(){
10335                 var proxy = this.createProxy({
10336
10337                      style:{
10338                         visbility:"hidden",
10339                         position:"absolute",
10340                         "z-index":"35000", // yee haw
10341                         border:"0px solid " + color
10342                      }
10343                   });
10344                 var scale = Roo.isBorderBox ? 2 : 1;
10345                 proxy.animate({
10346                     top:{from:b.y, to:b.y - 20},
10347                     left:{from:b.x, to:b.x - 20},
10348                     borderWidth:{from:0, to:10},
10349                     opacity:{from:1, to:0},
10350                     height:{from:b.height, to:(b.height + (20*scale))},
10351                     width:{from:b.width, to:(b.width + (20*scale))}
10352                 }, duration, function(){
10353                     proxy.remove();
10354                 });
10355                 if(--count > 0){
10356                      animFn.defer((duration/2)*1000, this);
10357                 }else{
10358                     el.afterFx(o);
10359                 }
10360             };
10361             animFn.call(this);
10362         });
10363         return this;
10364     },
10365
10366    /**
10367     * Creates a pause before any subsequent queued effects begin.  If there are
10368     * no effects queued after the pause it will have no effect.
10369     * Usage:
10370 <pre><code>
10371 el.pause(1);
10372 </code></pre>
10373     * @param {Number} seconds The length of time to pause (in seconds)
10374     * @return {Roo.Element} The Element
10375     */
10376     pause : function(seconds){
10377         var el = this.getFxEl();
10378         var o = {};
10379
10380         el.queueFx(o, function(){
10381             setTimeout(function(){
10382                 el.afterFx(o);
10383             }, seconds * 1000);
10384         });
10385         return this;
10386     },
10387
10388    /**
10389     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10390     * using the "endOpacity" config option.
10391     * Usage:
10392 <pre><code>
10393 // default: fade in from opacity 0 to 100%
10394 el.fadeIn();
10395
10396 // custom: fade in from opacity 0 to 75% over 2 seconds
10397 el.fadeIn({ endOpacity: .75, duration: 2});
10398
10399 // common config options shown with default values
10400 el.fadeIn({
10401     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10402     easing: 'easeOut',
10403     duration: .5
10404 });
10405 </code></pre>
10406     * @param {Object} options (optional) Object literal with any of the Fx config options
10407     * @return {Roo.Element} The Element
10408     */
10409     fadeIn : function(o){
10410         var el = this.getFxEl();
10411         o = o || {};
10412         el.queueFx(o, function(){
10413             this.setOpacity(0);
10414             this.fixDisplay();
10415             this.dom.style.visibility = 'visible';
10416             var to = o.endOpacity || 1;
10417             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10418                 o, null, .5, "easeOut", function(){
10419                 if(to == 1){
10420                     this.clearOpacity();
10421                 }
10422                 el.afterFx(o);
10423             });
10424         });
10425         return this;
10426     },
10427
10428    /**
10429     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10430     * using the "endOpacity" config option.
10431     * Usage:
10432 <pre><code>
10433 // default: fade out from the element's current opacity to 0
10434 el.fadeOut();
10435
10436 // custom: fade out from the element's current opacity to 25% over 2 seconds
10437 el.fadeOut({ endOpacity: .25, duration: 2});
10438
10439 // common config options shown with default values
10440 el.fadeOut({
10441     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10442     easing: 'easeOut',
10443     duration: .5
10444     remove: false,
10445     useDisplay: false
10446 });
10447 </code></pre>
10448     * @param {Object} options (optional) Object literal with any of the Fx config options
10449     * @return {Roo.Element} The Element
10450     */
10451     fadeOut : function(o){
10452         var el = this.getFxEl();
10453         o = o || {};
10454         el.queueFx(o, function(){
10455             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10456                 o, null, .5, "easeOut", function(){
10457                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10458                      this.dom.style.display = "none";
10459                 }else{
10460                      this.dom.style.visibility = "hidden";
10461                 }
10462                 this.clearOpacity();
10463                 el.afterFx(o);
10464             });
10465         });
10466         return this;
10467     },
10468
10469    /**
10470     * Animates the transition of an element's dimensions from a starting height/width
10471     * to an ending height/width.
10472     * Usage:
10473 <pre><code>
10474 // change height and width to 100x100 pixels
10475 el.scale(100, 100);
10476
10477 // common config options shown with default values.  The height and width will default to
10478 // the element's existing values if passed as null.
10479 el.scale(
10480     [element's width],
10481     [element's height], {
10482     easing: 'easeOut',
10483     duration: .35
10484 });
10485 </code></pre>
10486     * @param {Number} width  The new width (pass undefined to keep the original width)
10487     * @param {Number} height  The new height (pass undefined to keep the original height)
10488     * @param {Object} options (optional) Object literal with any of the Fx config options
10489     * @return {Roo.Element} The Element
10490     */
10491     scale : function(w, h, o){
10492         this.shift(Roo.apply({}, o, {
10493             width: w,
10494             height: h
10495         }));
10496         return this;
10497     },
10498
10499    /**
10500     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10501     * Any of these properties not specified in the config object will not be changed.  This effect 
10502     * requires that at least one new dimension, position or opacity setting must be passed in on
10503     * the config object in order for the function to have any effect.
10504     * Usage:
10505 <pre><code>
10506 // slide the element horizontally to x position 200 while changing the height and opacity
10507 el.shift({ x: 200, height: 50, opacity: .8 });
10508
10509 // common config options shown with default values.
10510 el.shift({
10511     width: [element's width],
10512     height: [element's height],
10513     x: [element's x position],
10514     y: [element's y position],
10515     opacity: [element's opacity],
10516     easing: 'easeOut',
10517     duration: .35
10518 });
10519 </code></pre>
10520     * @param {Object} options  Object literal with any of the Fx config options
10521     * @return {Roo.Element} The Element
10522     */
10523     shift : function(o){
10524         var el = this.getFxEl();
10525         o = o || {};
10526         el.queueFx(o, function(){
10527             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10528             if(w !== undefined){
10529                 a.width = {to: this.adjustWidth(w)};
10530             }
10531             if(h !== undefined){
10532                 a.height = {to: this.adjustHeight(h)};
10533             }
10534             if(x !== undefined || y !== undefined){
10535                 a.points = {to: [
10536                     x !== undefined ? x : this.getX(),
10537                     y !== undefined ? y : this.getY()
10538                 ]};
10539             }
10540             if(op !== undefined){
10541                 a.opacity = {to: op};
10542             }
10543             if(o.xy !== undefined){
10544                 a.points = {to: o.xy};
10545             }
10546             arguments.callee.anim = this.fxanim(a,
10547                 o, 'motion', .35, "easeOut", function(){
10548                 el.afterFx(o);
10549             });
10550         });
10551         return this;
10552     },
10553
10554         /**
10555          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10556          * ending point of the effect.
10557          * Usage:
10558          *<pre><code>
10559 // default: slide the element downward while fading out
10560 el.ghost();
10561
10562 // custom: slide the element out to the right with a 2-second duration
10563 el.ghost('r', { duration: 2 });
10564
10565 // common config options shown with default values
10566 el.ghost('b', {
10567     easing: 'easeOut',
10568     duration: .5
10569     remove: false,
10570     useDisplay: false
10571 });
10572 </code></pre>
10573          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10574          * @param {Object} options (optional) Object literal with any of the Fx config options
10575          * @return {Roo.Element} The Element
10576          */
10577     ghost : function(anchor, o){
10578         var el = this.getFxEl();
10579         o = o || {};
10580
10581         el.queueFx(o, function(){
10582             anchor = anchor || "b";
10583
10584             // restore values after effect
10585             var r = this.getFxRestore();
10586             var w = this.getWidth(),
10587                 h = this.getHeight();
10588
10589             var st = this.dom.style;
10590
10591             var after = function(){
10592                 if(o.useDisplay){
10593                     el.setDisplayed(false);
10594                 }else{
10595                     el.hide();
10596                 }
10597
10598                 el.clearOpacity();
10599                 el.setPositioning(r.pos);
10600                 st.width = r.width;
10601                 st.height = r.height;
10602
10603                 el.afterFx(o);
10604             };
10605
10606             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10607             switch(anchor.toLowerCase()){
10608                 case "t":
10609                     pt.by = [0, -h];
10610                 break;
10611                 case "l":
10612                     pt.by = [-w, 0];
10613                 break;
10614                 case "r":
10615                     pt.by = [w, 0];
10616                 break;
10617                 case "b":
10618                     pt.by = [0, h];
10619                 break;
10620                 case "tl":
10621                     pt.by = [-w, -h];
10622                 break;
10623                 case "bl":
10624                     pt.by = [-w, h];
10625                 break;
10626                 case "br":
10627                     pt.by = [w, h];
10628                 break;
10629                 case "tr":
10630                     pt.by = [w, -h];
10631                 break;
10632             }
10633
10634             arguments.callee.anim = this.fxanim(a,
10635                 o,
10636                 'motion',
10637                 .5,
10638                 "easeOut", after);
10639         });
10640         return this;
10641     },
10642
10643         /**
10644          * Ensures that all effects queued after syncFx is called on the element are
10645          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10646          * @return {Roo.Element} The Element
10647          */
10648     syncFx : function(){
10649         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10650             block : false,
10651             concurrent : true,
10652             stopFx : false
10653         });
10654         return this;
10655     },
10656
10657         /**
10658          * Ensures that all effects queued after sequenceFx is called on the element are
10659          * run in sequence.  This is the opposite of {@link #syncFx}.
10660          * @return {Roo.Element} The Element
10661          */
10662     sequenceFx : function(){
10663         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10664             block : false,
10665             concurrent : false,
10666             stopFx : false
10667         });
10668         return this;
10669     },
10670
10671         /* @private */
10672     nextFx : function(){
10673         var ef = this.fxQueue[0];
10674         if(ef){
10675             ef.call(this);
10676         }
10677     },
10678
10679         /**
10680          * Returns true if the element has any effects actively running or queued, else returns false.
10681          * @return {Boolean} True if element has active effects, else false
10682          */
10683     hasActiveFx : function(){
10684         return this.fxQueue && this.fxQueue[0];
10685     },
10686
10687         /**
10688          * Stops any running effects and clears the element's internal effects queue if it contains
10689          * any additional effects that haven't started yet.
10690          * @return {Roo.Element} The Element
10691          */
10692     stopFx : function(){
10693         if(this.hasActiveFx()){
10694             var cur = this.fxQueue[0];
10695             if(cur && cur.anim && cur.anim.isAnimated()){
10696                 this.fxQueue = [cur]; // clear out others
10697                 cur.anim.stop(true);
10698             }
10699         }
10700         return this;
10701     },
10702
10703         /* @private */
10704     beforeFx : function(o){
10705         if(this.hasActiveFx() && !o.concurrent){
10706            if(o.stopFx){
10707                this.stopFx();
10708                return true;
10709            }
10710            return false;
10711         }
10712         return true;
10713     },
10714
10715         /**
10716          * Returns true if the element is currently blocking so that no other effect can be queued
10717          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10718          * used to ensure that an effect initiated by a user action runs to completion prior to the
10719          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10720          * @return {Boolean} True if blocking, else false
10721          */
10722     hasFxBlock : function(){
10723         var q = this.fxQueue;
10724         return q && q[0] && q[0].block;
10725     },
10726
10727         /* @private */
10728     queueFx : function(o, fn){
10729         if(!this.fxQueue){
10730             this.fxQueue = [];
10731         }
10732         if(!this.hasFxBlock()){
10733             Roo.applyIf(o, this.fxDefaults);
10734             if(!o.concurrent){
10735                 var run = this.beforeFx(o);
10736                 fn.block = o.block;
10737                 this.fxQueue.push(fn);
10738                 if(run){
10739                     this.nextFx();
10740                 }
10741             }else{
10742                 fn.call(this);
10743             }
10744         }
10745         return this;
10746     },
10747
10748         /* @private */
10749     fxWrap : function(pos, o, vis){
10750         var wrap;
10751         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10752             var wrapXY;
10753             if(o.fixPosition){
10754                 wrapXY = this.getXY();
10755             }
10756             var div = document.createElement("div");
10757             div.style.visibility = vis;
10758             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10759             wrap.setPositioning(pos);
10760             if(wrap.getStyle("position") == "static"){
10761                 wrap.position("relative");
10762             }
10763             this.clearPositioning('auto');
10764             wrap.clip();
10765             wrap.dom.appendChild(this.dom);
10766             if(wrapXY){
10767                 wrap.setXY(wrapXY);
10768             }
10769         }
10770         return wrap;
10771     },
10772
10773         /* @private */
10774     fxUnwrap : function(wrap, pos, o){
10775         this.clearPositioning();
10776         this.setPositioning(pos);
10777         if(!o.wrap){
10778             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10779             wrap.remove();
10780         }
10781     },
10782
10783         /* @private */
10784     getFxRestore : function(){
10785         var st = this.dom.style;
10786         return {pos: this.getPositioning(), width: st.width, height : st.height};
10787     },
10788
10789         /* @private */
10790     afterFx : function(o){
10791         if(o.afterStyle){
10792             this.applyStyles(o.afterStyle);
10793         }
10794         if(o.afterCls){
10795             this.addClass(o.afterCls);
10796         }
10797         if(o.remove === true){
10798             this.remove();
10799         }
10800         Roo.callback(o.callback, o.scope, [this]);
10801         if(!o.concurrent){
10802             this.fxQueue.shift();
10803             this.nextFx();
10804         }
10805     },
10806
10807         /* @private */
10808     getFxEl : function(){ // support for composite element fx
10809         return Roo.get(this.dom);
10810     },
10811
10812         /* @private */
10813     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10814         animType = animType || 'run';
10815         opt = opt || {};
10816         var anim = Roo.lib.Anim[animType](
10817             this.dom, args,
10818             (opt.duration || defaultDur) || .35,
10819             (opt.easing || defaultEase) || 'easeOut',
10820             function(){
10821                 Roo.callback(cb, this);
10822             },
10823             this
10824         );
10825         opt.anim = anim;
10826         return anim;
10827     }
10828 };
10829
10830 // backwords compat
10831 Roo.Fx.resize = Roo.Fx.scale;
10832
10833 //When included, Roo.Fx is automatically applied to Element so that all basic
10834 //effects are available directly via the Element API
10835 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10836  * Based on:
10837  * Ext JS Library 1.1.1
10838  * Copyright(c) 2006-2007, Ext JS, LLC.
10839  *
10840  * Originally Released Under LGPL - original licence link has changed is not relivant.
10841  *
10842  * Fork - LGPL
10843  * <script type="text/javascript">
10844  */
10845
10846
10847 /**
10848  * @class Roo.CompositeElement
10849  * Standard composite class. Creates a Roo.Element for every element in the collection.
10850  * <br><br>
10851  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10852  * actions will be performed on all the elements in this collection.</b>
10853  * <br><br>
10854  * All methods return <i>this</i> and can be chained.
10855  <pre><code>
10856  var els = Roo.select("#some-el div.some-class", true);
10857  // or select directly from an existing element
10858  var el = Roo.get('some-el');
10859  el.select('div.some-class', true);
10860
10861  els.setWidth(100); // all elements become 100 width
10862  els.hide(true); // all elements fade out and hide
10863  // or
10864  els.setWidth(100).hide(true);
10865  </code></pre>
10866  */
10867 Roo.CompositeElement = function(els){
10868     this.elements = [];
10869     this.addElements(els);
10870 };
10871 Roo.CompositeElement.prototype = {
10872     isComposite: true,
10873     addElements : function(els){
10874         if(!els) return this;
10875         if(typeof els == "string"){
10876             els = Roo.Element.selectorFunction(els);
10877         }
10878         var yels = this.elements;
10879         var index = yels.length-1;
10880         for(var i = 0, len = els.length; i < len; i++) {
10881                 yels[++index] = Roo.get(els[i]);
10882         }
10883         return this;
10884     },
10885
10886     /**
10887     * Clears this composite and adds the elements returned by the passed selector.
10888     * @param {String/Array} els A string CSS selector, an array of elements or an element
10889     * @return {CompositeElement} this
10890     */
10891     fill : function(els){
10892         this.elements = [];
10893         this.add(els);
10894         return this;
10895     },
10896
10897     /**
10898     * Filters this composite to only elements that match the passed selector.
10899     * @param {String} selector A string CSS selector
10900     * @return {CompositeElement} this
10901     */
10902     filter : function(selector){
10903         var els = [];
10904         this.each(function(el){
10905             if(el.is(selector)){
10906                 els[els.length] = el.dom;
10907             }
10908         });
10909         this.fill(els);
10910         return this;
10911     },
10912
10913     invoke : function(fn, args){
10914         var els = this.elements;
10915         for(var i = 0, len = els.length; i < len; i++) {
10916                 Roo.Element.prototype[fn].apply(els[i], args);
10917         }
10918         return this;
10919     },
10920     /**
10921     * Adds elements to this composite.
10922     * @param {String/Array} els A string CSS selector, an array of elements or an element
10923     * @return {CompositeElement} this
10924     */
10925     add : function(els){
10926         if(typeof els == "string"){
10927             this.addElements(Roo.Element.selectorFunction(els));
10928         }else if(els.length !== undefined){
10929             this.addElements(els);
10930         }else{
10931             this.addElements([els]);
10932         }
10933         return this;
10934     },
10935     /**
10936     * Calls the passed function passing (el, this, index) for each element in this composite.
10937     * @param {Function} fn The function to call
10938     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10939     * @return {CompositeElement} this
10940     */
10941     each : function(fn, scope){
10942         var els = this.elements;
10943         for(var i = 0, len = els.length; i < len; i++){
10944             if(fn.call(scope || els[i], els[i], this, i) === false) {
10945                 break;
10946             }
10947         }
10948         return this;
10949     },
10950
10951     /**
10952      * Returns the Element object at the specified index
10953      * @param {Number} index
10954      * @return {Roo.Element}
10955      */
10956     item : function(index){
10957         return this.elements[index] || null;
10958     },
10959
10960     /**
10961      * Returns the first Element
10962      * @return {Roo.Element}
10963      */
10964     first : function(){
10965         return this.item(0);
10966     },
10967
10968     /**
10969      * Returns the last Element
10970      * @return {Roo.Element}
10971      */
10972     last : function(){
10973         return this.item(this.elements.length-1);
10974     },
10975
10976     /**
10977      * Returns the number of elements in this composite
10978      * @return Number
10979      */
10980     getCount : function(){
10981         return this.elements.length;
10982     },
10983
10984     /**
10985      * Returns true if this composite contains the passed element
10986      * @return Boolean
10987      */
10988     contains : function(el){
10989         return this.indexOf(el) !== -1;
10990     },
10991
10992     /**
10993      * Returns true if this composite contains the passed element
10994      * @return Boolean
10995      */
10996     indexOf : function(el){
10997         return this.elements.indexOf(Roo.get(el));
10998     },
10999
11000
11001     /**
11002     * Removes the specified element(s).
11003     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11004     * or an array of any of those.
11005     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11006     * @return {CompositeElement} this
11007     */
11008     removeElement : function(el, removeDom){
11009         if(el instanceof Array){
11010             for(var i = 0, len = el.length; i < len; i++){
11011                 this.removeElement(el[i]);
11012             }
11013             return this;
11014         }
11015         var index = typeof el == 'number' ? el : this.indexOf(el);
11016         if(index !== -1){
11017             if(removeDom){
11018                 var d = this.elements[index];
11019                 if(d.dom){
11020                     d.remove();
11021                 }else{
11022                     d.parentNode.removeChild(d);
11023                 }
11024             }
11025             this.elements.splice(index, 1);
11026         }
11027         return this;
11028     },
11029
11030     /**
11031     * Replaces the specified element with the passed element.
11032     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11033     * to replace.
11034     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11035     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11036     * @return {CompositeElement} this
11037     */
11038     replaceElement : function(el, replacement, domReplace){
11039         var index = typeof el == 'number' ? el : this.indexOf(el);
11040         if(index !== -1){
11041             if(domReplace){
11042                 this.elements[index].replaceWith(replacement);
11043             }else{
11044                 this.elements.splice(index, 1, Roo.get(replacement))
11045             }
11046         }
11047         return this;
11048     },
11049
11050     /**
11051      * Removes all elements.
11052      */
11053     clear : function(){
11054         this.elements = [];
11055     }
11056 };
11057 (function(){
11058     Roo.CompositeElement.createCall = function(proto, fnName){
11059         if(!proto[fnName]){
11060             proto[fnName] = function(){
11061                 return this.invoke(fnName, arguments);
11062             };
11063         }
11064     };
11065     for(var fnName in Roo.Element.prototype){
11066         if(typeof Roo.Element.prototype[fnName] == "function"){
11067             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11068         }
11069     };
11070 })();
11071 /*
11072  * Based on:
11073  * Ext JS Library 1.1.1
11074  * Copyright(c) 2006-2007, Ext JS, LLC.
11075  *
11076  * Originally Released Under LGPL - original licence link has changed is not relivant.
11077  *
11078  * Fork - LGPL
11079  * <script type="text/javascript">
11080  */
11081
11082 /**
11083  * @class Roo.CompositeElementLite
11084  * @extends Roo.CompositeElement
11085  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11086  <pre><code>
11087  var els = Roo.select("#some-el div.some-class");
11088  // or select directly from an existing element
11089  var el = Roo.get('some-el');
11090  el.select('div.some-class');
11091
11092  els.setWidth(100); // all elements become 100 width
11093  els.hide(true); // all elements fade out and hide
11094  // or
11095  els.setWidth(100).hide(true);
11096  </code></pre><br><br>
11097  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11098  * actions will be performed on all the elements in this collection.</b>
11099  */
11100 Roo.CompositeElementLite = function(els){
11101     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11102     this.el = new Roo.Element.Flyweight();
11103 };
11104 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11105     addElements : function(els){
11106         if(els){
11107             if(els instanceof Array){
11108                 this.elements = this.elements.concat(els);
11109             }else{
11110                 var yels = this.elements;
11111                 var index = yels.length-1;
11112                 for(var i = 0, len = els.length; i < len; i++) {
11113                     yels[++index] = els[i];
11114                 }
11115             }
11116         }
11117         return this;
11118     },
11119     invoke : function(fn, args){
11120         var els = this.elements;
11121         var el = this.el;
11122         for(var i = 0, len = els.length; i < len; i++) {
11123             el.dom = els[i];
11124                 Roo.Element.prototype[fn].apply(el, args);
11125         }
11126         return this;
11127     },
11128     /**
11129      * Returns a flyweight Element of the dom element object at the specified index
11130      * @param {Number} index
11131      * @return {Roo.Element}
11132      */
11133     item : function(index){
11134         if(!this.elements[index]){
11135             return null;
11136         }
11137         this.el.dom = this.elements[index];
11138         return this.el;
11139     },
11140
11141     // fixes scope with flyweight
11142     addListener : function(eventName, handler, scope, opt){
11143         var els = this.elements;
11144         for(var i = 0, len = els.length; i < len; i++) {
11145             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11146         }
11147         return this;
11148     },
11149
11150     /**
11151     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11152     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11153     * a reference to the dom node, use el.dom.</b>
11154     * @param {Function} fn The function to call
11155     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11156     * @return {CompositeElement} this
11157     */
11158     each : function(fn, scope){
11159         var els = this.elements;
11160         var el = this.el;
11161         for(var i = 0, len = els.length; i < len; i++){
11162             el.dom = els[i];
11163                 if(fn.call(scope || el, el, this, i) === false){
11164                 break;
11165             }
11166         }
11167         return this;
11168     },
11169
11170     indexOf : function(el){
11171         return this.elements.indexOf(Roo.getDom(el));
11172     },
11173
11174     replaceElement : function(el, replacement, domReplace){
11175         var index = typeof el == 'number' ? el : this.indexOf(el);
11176         if(index !== -1){
11177             replacement = Roo.getDom(replacement);
11178             if(domReplace){
11179                 var d = this.elements[index];
11180                 d.parentNode.insertBefore(replacement, d);
11181                 d.parentNode.removeChild(d);
11182             }
11183             this.elements.splice(index, 1, replacement);
11184         }
11185         return this;
11186     }
11187 });
11188 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11189
11190 /*
11191  * Based on:
11192  * Ext JS Library 1.1.1
11193  * Copyright(c) 2006-2007, Ext JS, LLC.
11194  *
11195  * Originally Released Under LGPL - original licence link has changed is not relivant.
11196  *
11197  * Fork - LGPL
11198  * <script type="text/javascript">
11199  */
11200
11201  
11202
11203 /**
11204  * @class Roo.data.Connection
11205  * @extends Roo.util.Observable
11206  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11207  * either to a configured URL, or to a URL specified at request time.<br><br>
11208  * <p>
11209  * Requests made by this class are asynchronous, and will return immediately. No data from
11210  * the server will be available to the statement immediately following the {@link #request} call.
11211  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11212  * <p>
11213  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11214  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11215  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11216  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11217  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11218  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11219  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11220  * standard DOM methods.
11221  * @constructor
11222  * @param {Object} config a configuration object.
11223  */
11224 Roo.data.Connection = function(config){
11225     Roo.apply(this, config);
11226     this.addEvents({
11227         /**
11228          * @event beforerequest
11229          * Fires before a network request is made to retrieve a data object.
11230          * @param {Connection} conn This Connection object.
11231          * @param {Object} options The options config object passed to the {@link #request} method.
11232          */
11233         "beforerequest" : true,
11234         /**
11235          * @event requestcomplete
11236          * Fires if the request was successfully completed.
11237          * @param {Connection} conn This Connection object.
11238          * @param {Object} response The XHR object containing the response data.
11239          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11240          * @param {Object} options The options config object passed to the {@link #request} method.
11241          */
11242         "requestcomplete" : true,
11243         /**
11244          * @event requestexception
11245          * Fires if an error HTTP status was returned from the server.
11246          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11247          * @param {Connection} conn This Connection object.
11248          * @param {Object} response The XHR object containing the response data.
11249          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11250          * @param {Object} options The options config object passed to the {@link #request} method.
11251          */
11252         "requestexception" : true
11253     });
11254     Roo.data.Connection.superclass.constructor.call(this);
11255 };
11256
11257 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11258     /**
11259      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11260      */
11261     /**
11262      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11263      * extra parameters to each request made by this object. (defaults to undefined)
11264      */
11265     /**
11266      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11267      *  to each request made by this object. (defaults to undefined)
11268      */
11269     /**
11270      * @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)
11271      */
11272     /**
11273      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11274      */
11275     timeout : 30000,
11276     /**
11277      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11278      * @type Boolean
11279      */
11280     autoAbort:false,
11281
11282     /**
11283      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11284      * @type Boolean
11285      */
11286     disableCaching: true,
11287
11288     /**
11289      * Sends an HTTP request to a remote server.
11290      * @param {Object} options An object which may contain the following properties:<ul>
11291      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11292      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11293      * request, a url encoded string or a function to call to get either.</li>
11294      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11295      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11296      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11297      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11298      * <li>options {Object} The parameter to the request call.</li>
11299      * <li>success {Boolean} True if the request succeeded.</li>
11300      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11301      * </ul></li>
11302      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11303      * The callback is passed the following parameters:<ul>
11304      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11305      * <li>options {Object} The parameter to the request call.</li>
11306      * </ul></li>
11307      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11308      * The callback is passed the following parameters:<ul>
11309      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11310      * <li>options {Object} The parameter to the request call.</li>
11311      * </ul></li>
11312      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11313      * for the callback function. Defaults to the browser window.</li>
11314      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11315      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11316      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11317      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11318      * params for the post data. Any params will be appended to the URL.</li>
11319      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11320      * </ul>
11321      * @return {Number} transactionId
11322      */
11323     request : function(o){
11324         if(this.fireEvent("beforerequest", this, o) !== false){
11325             var p = o.params;
11326
11327             if(typeof p == "function"){
11328                 p = p.call(o.scope||window, o);
11329             }
11330             if(typeof p == "object"){
11331                 p = Roo.urlEncode(o.params);
11332             }
11333             if(this.extraParams){
11334                 var extras = Roo.urlEncode(this.extraParams);
11335                 p = p ? (p + '&' + extras) : extras;
11336             }
11337
11338             var url = o.url || this.url;
11339             if(typeof url == 'function'){
11340                 url = url.call(o.scope||window, o);
11341             }
11342
11343             if(o.form){
11344                 var form = Roo.getDom(o.form);
11345                 url = url || form.action;
11346
11347                 var enctype = form.getAttribute("enctype");
11348                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11349                     return this.doFormUpload(o, p, url);
11350                 }
11351                 var f = Roo.lib.Ajax.serializeForm(form);
11352                 p = p ? (p + '&' + f) : f;
11353             }
11354
11355             var hs = o.headers;
11356             if(this.defaultHeaders){
11357                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11358                 if(!o.headers){
11359                     o.headers = hs;
11360                 }
11361             }
11362
11363             var cb = {
11364                 success: this.handleResponse,
11365                 failure: this.handleFailure,
11366                 scope: this,
11367                 argument: {options: o},
11368                 timeout : this.timeout
11369             };
11370
11371             var method = o.method||this.method||(p ? "POST" : "GET");
11372
11373             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11374                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11375             }
11376
11377             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11378                 if(o.autoAbort){
11379                     this.abort();
11380                 }
11381             }else if(this.autoAbort !== false){
11382                 this.abort();
11383             }
11384
11385             if((method == 'GET' && p) || o.xmlData){
11386                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11387                 p = '';
11388             }
11389             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11390             return this.transId;
11391         }else{
11392             Roo.callback(o.callback, o.scope, [o, null, null]);
11393             return null;
11394         }
11395     },
11396
11397     /**
11398      * Determine whether this object has a request outstanding.
11399      * @param {Number} transactionId (Optional) defaults to the last transaction
11400      * @return {Boolean} True if there is an outstanding request.
11401      */
11402     isLoading : function(transId){
11403         if(transId){
11404             return Roo.lib.Ajax.isCallInProgress(transId);
11405         }else{
11406             return this.transId ? true : false;
11407         }
11408     },
11409
11410     /**
11411      * Aborts any outstanding request.
11412      * @param {Number} transactionId (Optional) defaults to the last transaction
11413      */
11414     abort : function(transId){
11415         if(transId || this.isLoading()){
11416             Roo.lib.Ajax.abort(transId || this.transId);
11417         }
11418     },
11419
11420     // private
11421     handleResponse : function(response){
11422         this.transId = false;
11423         var options = response.argument.options;
11424         response.argument = options ? options.argument : null;
11425         this.fireEvent("requestcomplete", this, response, options);
11426         Roo.callback(options.success, options.scope, [response, options]);
11427         Roo.callback(options.callback, options.scope, [options, true, response]);
11428     },
11429
11430     // private
11431     handleFailure : function(response, e){
11432         this.transId = false;
11433         var options = response.argument.options;
11434         response.argument = options ? options.argument : null;
11435         this.fireEvent("requestexception", this, response, options, e);
11436         Roo.callback(options.failure, options.scope, [response, options]);
11437         Roo.callback(options.callback, options.scope, [options, false, response]);
11438     },
11439
11440     // private
11441     doFormUpload : function(o, ps, url){
11442         var id = Roo.id();
11443         var frame = document.createElement('iframe');
11444         frame.id = id;
11445         frame.name = id;
11446         frame.className = 'x-hidden';
11447         if(Roo.isIE){
11448             frame.src = Roo.SSL_SECURE_URL;
11449         }
11450         document.body.appendChild(frame);
11451
11452         if(Roo.isIE){
11453            document.frames[id].name = id;
11454         }
11455
11456         var form = Roo.getDom(o.form);
11457         form.target = id;
11458         form.method = 'POST';
11459         form.enctype = form.encoding = 'multipart/form-data';
11460         if(url){
11461             form.action = url;
11462         }
11463
11464         var hiddens, hd;
11465         if(ps){ // add dynamic params
11466             hiddens = [];
11467             ps = Roo.urlDecode(ps, false);
11468             for(var k in ps){
11469                 if(ps.hasOwnProperty(k)){
11470                     hd = document.createElement('input');
11471                     hd.type = 'hidden';
11472                     hd.name = k;
11473                     hd.value = ps[k];
11474                     form.appendChild(hd);
11475                     hiddens.push(hd);
11476                 }
11477             }
11478         }
11479
11480         function cb(){
11481             var r = {  // bogus response object
11482                 responseText : '',
11483                 responseXML : null
11484             };
11485
11486             r.argument = o ? o.argument : null;
11487
11488             try { //
11489                 var doc;
11490                 if(Roo.isIE){
11491                     doc = frame.contentWindow.document;
11492                 }else {
11493                     doc = (frame.contentDocument || window.frames[id].document);
11494                 }
11495                 if(doc && doc.body){
11496                     r.responseText = doc.body.innerHTML;
11497                 }
11498                 if(doc && doc.XMLDocument){
11499                     r.responseXML = doc.XMLDocument;
11500                 }else {
11501                     r.responseXML = doc;
11502                 }
11503             }
11504             catch(e) {
11505                 // ignore
11506             }
11507
11508             Roo.EventManager.removeListener(frame, 'load', cb, this);
11509
11510             this.fireEvent("requestcomplete", this, r, o);
11511             Roo.callback(o.success, o.scope, [r, o]);
11512             Roo.callback(o.callback, o.scope, [o, true, r]);
11513
11514             setTimeout(function(){document.body.removeChild(frame);}, 100);
11515         }
11516
11517         Roo.EventManager.on(frame, 'load', cb, this);
11518         form.submit();
11519
11520         if(hiddens){ // remove dynamic params
11521             for(var i = 0, len = hiddens.length; i < len; i++){
11522                 form.removeChild(hiddens[i]);
11523             }
11524         }
11525     }
11526 });
11527
11528 /**
11529  * @class Roo.Ajax
11530  * @extends Roo.data.Connection
11531  * Global Ajax request class.
11532  *
11533  * @singleton
11534  */
11535 Roo.Ajax = new Roo.data.Connection({
11536     // fix up the docs
11537    /**
11538      * @cfg {String} url @hide
11539      */
11540     /**
11541      * @cfg {Object} extraParams @hide
11542      */
11543     /**
11544      * @cfg {Object} defaultHeaders @hide
11545      */
11546     /**
11547      * @cfg {String} method (Optional) @hide
11548      */
11549     /**
11550      * @cfg {Number} timeout (Optional) @hide
11551      */
11552     /**
11553      * @cfg {Boolean} autoAbort (Optional) @hide
11554      */
11555
11556     /**
11557      * @cfg {Boolean} disableCaching (Optional) @hide
11558      */
11559
11560     /**
11561      * @property  disableCaching
11562      * True to add a unique cache-buster param to GET requests. (defaults to true)
11563      * @type Boolean
11564      */
11565     /**
11566      * @property  url
11567      * The default URL to be used for requests to the server. (defaults to undefined)
11568      * @type String
11569      */
11570     /**
11571      * @property  extraParams
11572      * An object containing properties which are used as
11573      * extra parameters to each request made by this object. (defaults to undefined)
11574      * @type Object
11575      */
11576     /**
11577      * @property  defaultHeaders
11578      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11579      * @type Object
11580      */
11581     /**
11582      * @property  method
11583      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11584      * @type String
11585      */
11586     /**
11587      * @property  timeout
11588      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11589      * @type Number
11590      */
11591
11592     /**
11593      * @property  autoAbort
11594      * Whether a new request should abort any pending requests. (defaults to false)
11595      * @type Boolean
11596      */
11597     autoAbort : false,
11598
11599     /**
11600      * Serialize the passed form into a url encoded string
11601      * @param {String/HTMLElement} form
11602      * @return {String}
11603      */
11604     serializeForm : function(form){
11605         return Roo.lib.Ajax.serializeForm(form);
11606     }
11607 });/*
11608  * Based on:
11609  * Ext JS Library 1.1.1
11610  * Copyright(c) 2006-2007, Ext JS, LLC.
11611  *
11612  * Originally Released Under LGPL - original licence link has changed is not relivant.
11613  *
11614  * Fork - LGPL
11615  * <script type="text/javascript">
11616  */
11617  
11618 /**
11619  * Global Ajax request class.
11620  * 
11621  * @class Roo.Ajax
11622  * @extends Roo.data.Connection
11623  * @static
11624  * 
11625  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11626  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11627  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11628  * @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)
11629  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11630  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11631  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11632  */
11633 Roo.Ajax = new Roo.data.Connection({
11634     // fix up the docs
11635     /**
11636      * @scope Roo.Ajax
11637      * @type {Boolear} 
11638      */
11639     autoAbort : false,
11640
11641     /**
11642      * Serialize the passed form into a url encoded string
11643      * @scope Roo.Ajax
11644      * @param {String/HTMLElement} form
11645      * @return {String}
11646      */
11647     serializeForm : function(form){
11648         return Roo.lib.Ajax.serializeForm(form);
11649     }
11650 });/*
11651  * Based on:
11652  * Ext JS Library 1.1.1
11653  * Copyright(c) 2006-2007, Ext JS, LLC.
11654  *
11655  * Originally Released Under LGPL - original licence link has changed is not relivant.
11656  *
11657  * Fork - LGPL
11658  * <script type="text/javascript">
11659  */
11660
11661  
11662 /**
11663  * @class Roo.UpdateManager
11664  * @extends Roo.util.Observable
11665  * Provides AJAX-style update for Element object.<br><br>
11666  * Usage:<br>
11667  * <pre><code>
11668  * // Get it from a Roo.Element object
11669  * var el = Roo.get("foo");
11670  * var mgr = el.getUpdateManager();
11671  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11672  * ...
11673  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11674  * <br>
11675  * // or directly (returns the same UpdateManager instance)
11676  * var mgr = new Roo.UpdateManager("myElementId");
11677  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11678  * mgr.on("update", myFcnNeedsToKnow);
11679  * <br>
11680    // short handed call directly from the element object
11681    Roo.get("foo").load({
11682         url: "bar.php",
11683         scripts:true,
11684         params: "for=bar",
11685         text: "Loading Foo..."
11686    });
11687  * </code></pre>
11688  * @constructor
11689  * Create new UpdateManager directly.
11690  * @param {String/HTMLElement/Roo.Element} el The element to update
11691  * @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).
11692  */
11693 Roo.UpdateManager = function(el, forceNew){
11694     el = Roo.get(el);
11695     if(!forceNew && el.updateManager){
11696         return el.updateManager;
11697     }
11698     /**
11699      * The Element object
11700      * @type Roo.Element
11701      */
11702     this.el = el;
11703     /**
11704      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11705      * @type String
11706      */
11707     this.defaultUrl = null;
11708
11709     this.addEvents({
11710         /**
11711          * @event beforeupdate
11712          * Fired before an update is made, return false from your handler and the update is cancelled.
11713          * @param {Roo.Element} el
11714          * @param {String/Object/Function} url
11715          * @param {String/Object} params
11716          */
11717         "beforeupdate": true,
11718         /**
11719          * @event update
11720          * Fired after successful update is made.
11721          * @param {Roo.Element} el
11722          * @param {Object} oResponseObject The response Object
11723          */
11724         "update": true,
11725         /**
11726          * @event failure
11727          * Fired on update failure.
11728          * @param {Roo.Element} el
11729          * @param {Object} oResponseObject The response Object
11730          */
11731         "failure": true
11732     });
11733     var d = Roo.UpdateManager.defaults;
11734     /**
11735      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11736      * @type String
11737      */
11738     this.sslBlankUrl = d.sslBlankUrl;
11739     /**
11740      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11741      * @type Boolean
11742      */
11743     this.disableCaching = d.disableCaching;
11744     /**
11745      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11746      * @type String
11747      */
11748     this.indicatorText = d.indicatorText;
11749     /**
11750      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11751      * @type String
11752      */
11753     this.showLoadIndicator = d.showLoadIndicator;
11754     /**
11755      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11756      * @type Number
11757      */
11758     this.timeout = d.timeout;
11759
11760     /**
11761      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11762      * @type Boolean
11763      */
11764     this.loadScripts = d.loadScripts;
11765
11766     /**
11767      * Transaction object of current executing transaction
11768      */
11769     this.transaction = null;
11770
11771     /**
11772      * @private
11773      */
11774     this.autoRefreshProcId = null;
11775     /**
11776      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11777      * @type Function
11778      */
11779     this.refreshDelegate = this.refresh.createDelegate(this);
11780     /**
11781      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11782      * @type Function
11783      */
11784     this.updateDelegate = this.update.createDelegate(this);
11785     /**
11786      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11787      * @type Function
11788      */
11789     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11790     /**
11791      * @private
11792      */
11793     this.successDelegate = this.processSuccess.createDelegate(this);
11794     /**
11795      * @private
11796      */
11797     this.failureDelegate = this.processFailure.createDelegate(this);
11798
11799     if(!this.renderer){
11800      /**
11801       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11802       */
11803     this.renderer = new Roo.UpdateManager.BasicRenderer();
11804     }
11805     
11806     Roo.UpdateManager.superclass.constructor.call(this);
11807 };
11808
11809 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11810     /**
11811      * Get the Element this UpdateManager is bound to
11812      * @return {Roo.Element} The element
11813      */
11814     getEl : function(){
11815         return this.el;
11816     },
11817     /**
11818      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11819      * @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:
11820 <pre><code>
11821 um.update({<br/>
11822     url: "your-url.php",<br/>
11823     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11824     callback: yourFunction,<br/>
11825     scope: yourObject, //(optional scope)  <br/>
11826     discardUrl: false, <br/>
11827     nocache: false,<br/>
11828     text: "Loading...",<br/>
11829     timeout: 30,<br/>
11830     scripts: false<br/>
11831 });
11832 </code></pre>
11833      * The only required property is url. The optional properties nocache, text and scripts
11834      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11835      * @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}
11836      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11837      * @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.
11838      */
11839     update : function(url, params, callback, discardUrl){
11840         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11841             var method = this.method, cfg;
11842             if(typeof url == "object"){ // must be config object
11843                 cfg = url;
11844                 url = cfg.url;
11845                 params = params || cfg.params;
11846                 callback = callback || cfg.callback;
11847                 discardUrl = discardUrl || cfg.discardUrl;
11848                 if(callback && cfg.scope){
11849                     callback = callback.createDelegate(cfg.scope);
11850                 }
11851                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11852                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11853                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11854                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11855                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11856             }
11857             this.showLoading();
11858             if(!discardUrl){
11859                 this.defaultUrl = url;
11860             }
11861             if(typeof url == "function"){
11862                 url = url.call(this);
11863             }
11864
11865             method = method || (params ? "POST" : "GET");
11866             if(method == "GET"){
11867                 url = this.prepareUrl(url);
11868             }
11869
11870             var o = Roo.apply(cfg ||{}, {
11871                 url : url,
11872                 params: params,
11873                 success: this.successDelegate,
11874                 failure: this.failureDelegate,
11875                 callback: undefined,
11876                 timeout: (this.timeout*1000),
11877                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11878             });
11879
11880             this.transaction = Roo.Ajax.request(o);
11881         }
11882     },
11883
11884     /**
11885      * 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.
11886      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11887      * @param {String/HTMLElement} form The form Id or form element
11888      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11889      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11890      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11891      */
11892     formUpdate : function(form, url, reset, callback){
11893         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11894             if(typeof url == "function"){
11895                 url = url.call(this);
11896             }
11897             form = Roo.getDom(form);
11898             this.transaction = Roo.Ajax.request({
11899                 form: form,
11900                 url:url,
11901                 success: this.successDelegate,
11902                 failure: this.failureDelegate,
11903                 timeout: (this.timeout*1000),
11904                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11905             });
11906             this.showLoading.defer(1, this);
11907         }
11908     },
11909
11910     /**
11911      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11912      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11913      */
11914     refresh : function(callback){
11915         if(this.defaultUrl == null){
11916             return;
11917         }
11918         this.update(this.defaultUrl, null, callback, true);
11919     },
11920
11921     /**
11922      * Set this element to auto refresh.
11923      * @param {Number} interval How often to update (in seconds).
11924      * @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)
11925      * @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}
11926      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11927      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11928      */
11929     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11930         if(refreshNow){
11931             this.update(url || this.defaultUrl, params, callback, true);
11932         }
11933         if(this.autoRefreshProcId){
11934             clearInterval(this.autoRefreshProcId);
11935         }
11936         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11937     },
11938
11939     /**
11940      * Stop auto refresh on this element.
11941      */
11942      stopAutoRefresh : function(){
11943         if(this.autoRefreshProcId){
11944             clearInterval(this.autoRefreshProcId);
11945             delete this.autoRefreshProcId;
11946         }
11947     },
11948
11949     isAutoRefreshing : function(){
11950        return this.autoRefreshProcId ? true : false;
11951     },
11952     /**
11953      * Called to update the element to "Loading" state. Override to perform custom action.
11954      */
11955     showLoading : function(){
11956         if(this.showLoadIndicator){
11957             this.el.update(this.indicatorText);
11958         }
11959     },
11960
11961     /**
11962      * Adds unique parameter to query string if disableCaching = true
11963      * @private
11964      */
11965     prepareUrl : function(url){
11966         if(this.disableCaching){
11967             var append = "_dc=" + (new Date().getTime());
11968             if(url.indexOf("?") !== -1){
11969                 url += "&" + append;
11970             }else{
11971                 url += "?" + append;
11972             }
11973         }
11974         return url;
11975     },
11976
11977     /**
11978      * @private
11979      */
11980     processSuccess : function(response){
11981         this.transaction = null;
11982         if(response.argument.form && response.argument.reset){
11983             try{ // put in try/catch since some older FF releases had problems with this
11984                 response.argument.form.reset();
11985             }catch(e){}
11986         }
11987         if(this.loadScripts){
11988             this.renderer.render(this.el, response, this,
11989                 this.updateComplete.createDelegate(this, [response]));
11990         }else{
11991             this.renderer.render(this.el, response, this);
11992             this.updateComplete(response);
11993         }
11994     },
11995
11996     updateComplete : function(response){
11997         this.fireEvent("update", this.el, response);
11998         if(typeof response.argument.callback == "function"){
11999             response.argument.callback(this.el, true, response);
12000         }
12001     },
12002
12003     /**
12004      * @private
12005      */
12006     processFailure : function(response){
12007         this.transaction = null;
12008         this.fireEvent("failure", this.el, response);
12009         if(typeof response.argument.callback == "function"){
12010             response.argument.callback(this.el, false, response);
12011         }
12012     },
12013
12014     /**
12015      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12016      * @param {Object} renderer The object implementing the render() method
12017      */
12018     setRenderer : function(renderer){
12019         this.renderer = renderer;
12020     },
12021
12022     getRenderer : function(){
12023        return this.renderer;
12024     },
12025
12026     /**
12027      * Set the defaultUrl used for updates
12028      * @param {String/Function} defaultUrl The url or a function to call to get the url
12029      */
12030     setDefaultUrl : function(defaultUrl){
12031         this.defaultUrl = defaultUrl;
12032     },
12033
12034     /**
12035      * Aborts the executing transaction
12036      */
12037     abort : function(){
12038         if(this.transaction){
12039             Roo.Ajax.abort(this.transaction);
12040         }
12041     },
12042
12043     /**
12044      * Returns true if an update is in progress
12045      * @return {Boolean}
12046      */
12047     isUpdating : function(){
12048         if(this.transaction){
12049             return Roo.Ajax.isLoading(this.transaction);
12050         }
12051         return false;
12052     }
12053 });
12054
12055 /**
12056  * @class Roo.UpdateManager.defaults
12057  * @static (not really - but it helps the doc tool)
12058  * The defaults collection enables customizing the default properties of UpdateManager
12059  */
12060    Roo.UpdateManager.defaults = {
12061        /**
12062          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12063          * @type Number
12064          */
12065          timeout : 30,
12066
12067          /**
12068          * True to process scripts by default (Defaults to false).
12069          * @type Boolean
12070          */
12071         loadScripts : false,
12072
12073         /**
12074         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12075         * @type String
12076         */
12077         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12078         /**
12079          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12080          * @type Boolean
12081          */
12082         disableCaching : false,
12083         /**
12084          * Whether to show indicatorText when loading (Defaults to true).
12085          * @type Boolean
12086          */
12087         showLoadIndicator : true,
12088         /**
12089          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12090          * @type String
12091          */
12092         indicatorText : '<div class="loading-indicator">Loading...</div>'
12093    };
12094
12095 /**
12096  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12097  *Usage:
12098  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12099  * @param {String/HTMLElement/Roo.Element} el The element to update
12100  * @param {String} url The url
12101  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12102  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12103  * @static
12104  * @deprecated
12105  * @member Roo.UpdateManager
12106  */
12107 Roo.UpdateManager.updateElement = function(el, url, params, options){
12108     var um = Roo.get(el, true).getUpdateManager();
12109     Roo.apply(um, options);
12110     um.update(url, params, options ? options.callback : null);
12111 };
12112 // alias for backwards compat
12113 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12114 /**
12115  * @class Roo.UpdateManager.BasicRenderer
12116  * Default Content renderer. Updates the elements innerHTML with the responseText.
12117  */
12118 Roo.UpdateManager.BasicRenderer = function(){};
12119
12120 Roo.UpdateManager.BasicRenderer.prototype = {
12121     /**
12122      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12123      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12124      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12125      * @param {Roo.Element} el The element being rendered
12126      * @param {Object} response The YUI Connect response object
12127      * @param {UpdateManager} updateManager The calling update manager
12128      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12129      */
12130      render : function(el, response, updateManager, callback){
12131         el.update(response.responseText, updateManager.loadScripts, callback);
12132     }
12133 };
12134 /*
12135  * Based on:
12136  * Ext JS Library 1.1.1
12137  * Copyright(c) 2006-2007, Ext JS, LLC.
12138  *
12139  * Originally Released Under LGPL - original licence link has changed is not relivant.
12140  *
12141  * Fork - LGPL
12142  * <script type="text/javascript">
12143  */
12144
12145 /**
12146  * @class Roo.util.DelayedTask
12147  * Provides a convenient method of performing setTimeout where a new
12148  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12149  * You can use this class to buffer
12150  * the keypress events for a certain number of milliseconds, and perform only if they stop
12151  * for that amount of time.
12152  * @constructor The parameters to this constructor serve as defaults and are not required.
12153  * @param {Function} fn (optional) The default function to timeout
12154  * @param {Object} scope (optional) The default scope of that timeout
12155  * @param {Array} args (optional) The default Array of arguments
12156  */
12157 Roo.util.DelayedTask = function(fn, scope, args){
12158     var id = null, d, t;
12159
12160     var call = function(){
12161         var now = new Date().getTime();
12162         if(now - t >= d){
12163             clearInterval(id);
12164             id = null;
12165             fn.apply(scope, args || []);
12166         }
12167     };
12168     /**
12169      * Cancels any pending timeout and queues a new one
12170      * @param {Number} delay The milliseconds to delay
12171      * @param {Function} newFn (optional) Overrides function passed to constructor
12172      * @param {Object} newScope (optional) Overrides scope passed to constructor
12173      * @param {Array} newArgs (optional) Overrides args passed to constructor
12174      */
12175     this.delay = function(delay, newFn, newScope, newArgs){
12176         if(id && delay != d){
12177             this.cancel();
12178         }
12179         d = delay;
12180         t = new Date().getTime();
12181         fn = newFn || fn;
12182         scope = newScope || scope;
12183         args = newArgs || args;
12184         if(!id){
12185             id = setInterval(call, d);
12186         }
12187     };
12188
12189     /**
12190      * Cancel the last queued timeout
12191      */
12192     this.cancel = function(){
12193         if(id){
12194             clearInterval(id);
12195             id = null;
12196         }
12197     };
12198 };/*
12199  * Based on:
12200  * Ext JS Library 1.1.1
12201  * Copyright(c) 2006-2007, Ext JS, LLC.
12202  *
12203  * Originally Released Under LGPL - original licence link has changed is not relivant.
12204  *
12205  * Fork - LGPL
12206  * <script type="text/javascript">
12207  */
12208  
12209  
12210 Roo.util.TaskRunner = function(interval){
12211     interval = interval || 10;
12212     var tasks = [], removeQueue = [];
12213     var id = 0;
12214     var running = false;
12215
12216     var stopThread = function(){
12217         running = false;
12218         clearInterval(id);
12219         id = 0;
12220     };
12221
12222     var startThread = function(){
12223         if(!running){
12224             running = true;
12225             id = setInterval(runTasks, interval);
12226         }
12227     };
12228
12229     var removeTask = function(task){
12230         removeQueue.push(task);
12231         if(task.onStop){
12232             task.onStop();
12233         }
12234     };
12235
12236     var runTasks = function(){
12237         if(removeQueue.length > 0){
12238             for(var i = 0, len = removeQueue.length; i < len; i++){
12239                 tasks.remove(removeQueue[i]);
12240             }
12241             removeQueue = [];
12242             if(tasks.length < 1){
12243                 stopThread();
12244                 return;
12245             }
12246         }
12247         var now = new Date().getTime();
12248         for(var i = 0, len = tasks.length; i < len; ++i){
12249             var t = tasks[i];
12250             var itime = now - t.taskRunTime;
12251             if(t.interval <= itime){
12252                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12253                 t.taskRunTime = now;
12254                 if(rt === false || t.taskRunCount === t.repeat){
12255                     removeTask(t);
12256                     return;
12257                 }
12258             }
12259             if(t.duration && t.duration <= (now - t.taskStartTime)){
12260                 removeTask(t);
12261             }
12262         }
12263     };
12264
12265     /**
12266      * Queues a new task.
12267      * @param {Object} task
12268      */
12269     this.start = function(task){
12270         tasks.push(task);
12271         task.taskStartTime = new Date().getTime();
12272         task.taskRunTime = 0;
12273         task.taskRunCount = 0;
12274         startThread();
12275         return task;
12276     };
12277
12278     this.stop = function(task){
12279         removeTask(task);
12280         return task;
12281     };
12282
12283     this.stopAll = function(){
12284         stopThread();
12285         for(var i = 0, len = tasks.length; i < len; i++){
12286             if(tasks[i].onStop){
12287                 tasks[i].onStop();
12288             }
12289         }
12290         tasks = [];
12291         removeQueue = [];
12292     };
12293 };
12294
12295 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12296  * Based on:
12297  * Ext JS Library 1.1.1
12298  * Copyright(c) 2006-2007, Ext JS, LLC.
12299  *
12300  * Originally Released Under LGPL - original licence link has changed is not relivant.
12301  *
12302  * Fork - LGPL
12303  * <script type="text/javascript">
12304  */
12305
12306  
12307 /**
12308  * @class Roo.util.MixedCollection
12309  * @extends Roo.util.Observable
12310  * A Collection class that maintains both numeric indexes and keys and exposes events.
12311  * @constructor
12312  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12313  * collection (defaults to false)
12314  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12315  * and return the key value for that item.  This is used when available to look up the key on items that
12316  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12317  * equivalent to providing an implementation for the {@link #getKey} method.
12318  */
12319 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12320     this.items = [];
12321     this.map = {};
12322     this.keys = [];
12323     this.length = 0;
12324     this.addEvents({
12325         /**
12326          * @event clear
12327          * Fires when the collection is cleared.
12328          */
12329         "clear" : true,
12330         /**
12331          * @event add
12332          * Fires when an item is added to the collection.
12333          * @param {Number} index The index at which the item was added.
12334          * @param {Object} o The item added.
12335          * @param {String} key The key associated with the added item.
12336          */
12337         "add" : true,
12338         /**
12339          * @event replace
12340          * Fires when an item is replaced in the collection.
12341          * @param {String} key he key associated with the new added.
12342          * @param {Object} old The item being replaced.
12343          * @param {Object} new The new item.
12344          */
12345         "replace" : true,
12346         /**
12347          * @event remove
12348          * Fires when an item is removed from the collection.
12349          * @param {Object} o The item being removed.
12350          * @param {String} key (optional) The key associated with the removed item.
12351          */
12352         "remove" : true,
12353         "sort" : true
12354     });
12355     this.allowFunctions = allowFunctions === true;
12356     if(keyFn){
12357         this.getKey = keyFn;
12358     }
12359     Roo.util.MixedCollection.superclass.constructor.call(this);
12360 };
12361
12362 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12363     allowFunctions : false,
12364     
12365 /**
12366  * Adds an item to the collection.
12367  * @param {String} key The key to associate with the item
12368  * @param {Object} o The item to add.
12369  * @return {Object} The item added.
12370  */
12371     add : function(key, o){
12372         if(arguments.length == 1){
12373             o = arguments[0];
12374             key = this.getKey(o);
12375         }
12376         if(typeof key == "undefined" || key === null){
12377             this.length++;
12378             this.items.push(o);
12379             this.keys.push(null);
12380         }else{
12381             var old = this.map[key];
12382             if(old){
12383                 return this.replace(key, o);
12384             }
12385             this.length++;
12386             this.items.push(o);
12387             this.map[key] = o;
12388             this.keys.push(key);
12389         }
12390         this.fireEvent("add", this.length-1, o, key);
12391         return o;
12392     },
12393        
12394 /**
12395   * MixedCollection has a generic way to fetch keys if you implement getKey.
12396 <pre><code>
12397 // normal way
12398 var mc = new Roo.util.MixedCollection();
12399 mc.add(someEl.dom.id, someEl);
12400 mc.add(otherEl.dom.id, otherEl);
12401 //and so on
12402
12403 // using getKey
12404 var mc = new Roo.util.MixedCollection();
12405 mc.getKey = function(el){
12406    return el.dom.id;
12407 };
12408 mc.add(someEl);
12409 mc.add(otherEl);
12410
12411 // or via the constructor
12412 var mc = new Roo.util.MixedCollection(false, function(el){
12413    return el.dom.id;
12414 });
12415 mc.add(someEl);
12416 mc.add(otherEl);
12417 </code></pre>
12418  * @param o {Object} The item for which to find the key.
12419  * @return {Object} The key for the passed item.
12420  */
12421     getKey : function(o){
12422          return o.id; 
12423     },
12424    
12425 /**
12426  * Replaces an item in the collection.
12427  * @param {String} key The key associated with the item to replace, or the item to replace.
12428  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12429  * @return {Object}  The new item.
12430  */
12431     replace : function(key, o){
12432         if(arguments.length == 1){
12433             o = arguments[0];
12434             key = this.getKey(o);
12435         }
12436         var old = this.item(key);
12437         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12438              return this.add(key, o);
12439         }
12440         var index = this.indexOfKey(key);
12441         this.items[index] = o;
12442         this.map[key] = o;
12443         this.fireEvent("replace", key, old, o);
12444         return o;
12445     },
12446    
12447 /**
12448  * Adds all elements of an Array or an Object to the collection.
12449  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12450  * an Array of values, each of which are added to the collection.
12451  */
12452     addAll : function(objs){
12453         if(arguments.length > 1 || objs instanceof Array){
12454             var args = arguments.length > 1 ? arguments : objs;
12455             for(var i = 0, len = args.length; i < len; i++){
12456                 this.add(args[i]);
12457             }
12458         }else{
12459             for(var key in objs){
12460                 if(this.allowFunctions || typeof objs[key] != "function"){
12461                     this.add(key, objs[key]);
12462                 }
12463             }
12464         }
12465     },
12466    
12467 /**
12468  * Executes the specified function once for every item in the collection, passing each
12469  * item as the first and only parameter. returning false from the function will stop the iteration.
12470  * @param {Function} fn The function to execute for each item.
12471  * @param {Object} scope (optional) The scope in which to execute the function.
12472  */
12473     each : function(fn, scope){
12474         var items = [].concat(this.items); // each safe for removal
12475         for(var i = 0, len = items.length; i < len; i++){
12476             if(fn.call(scope || items[i], items[i], i, len) === false){
12477                 break;
12478             }
12479         }
12480     },
12481    
12482 /**
12483  * Executes the specified function once for every key in the collection, passing each
12484  * key, and its associated item as the first two parameters.
12485  * @param {Function} fn The function to execute for each item.
12486  * @param {Object} scope (optional) The scope in which to execute the function.
12487  */
12488     eachKey : function(fn, scope){
12489         for(var i = 0, len = this.keys.length; i < len; i++){
12490             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12491         }
12492     },
12493    
12494 /**
12495  * Returns the first item in the collection which elicits a true return value from the
12496  * passed selection function.
12497  * @param {Function} fn The selection function to execute for each item.
12498  * @param {Object} scope (optional) The scope in which to execute the function.
12499  * @return {Object} The first item in the collection which returned true from the selection function.
12500  */
12501     find : function(fn, scope){
12502         for(var i = 0, len = this.items.length; i < len; i++){
12503             if(fn.call(scope || window, this.items[i], this.keys[i])){
12504                 return this.items[i];
12505             }
12506         }
12507         return null;
12508     },
12509    
12510 /**
12511  * Inserts an item at the specified index in the collection.
12512  * @param {Number} index The index to insert the item at.
12513  * @param {String} key The key to associate with the new item, or the item itself.
12514  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12515  * @return {Object} The item inserted.
12516  */
12517     insert : function(index, key, o){
12518         if(arguments.length == 2){
12519             o = arguments[1];
12520             key = this.getKey(o);
12521         }
12522         if(index >= this.length){
12523             return this.add(key, o);
12524         }
12525         this.length++;
12526         this.items.splice(index, 0, o);
12527         if(typeof key != "undefined" && key != null){
12528             this.map[key] = o;
12529         }
12530         this.keys.splice(index, 0, key);
12531         this.fireEvent("add", index, o, key);
12532         return o;
12533     },
12534    
12535 /**
12536  * Removed an item from the collection.
12537  * @param {Object} o The item to remove.
12538  * @return {Object} The item removed.
12539  */
12540     remove : function(o){
12541         return this.removeAt(this.indexOf(o));
12542     },
12543    
12544 /**
12545  * Remove an item from a specified index in the collection.
12546  * @param {Number} index The index within the collection of the item to remove.
12547  */
12548     removeAt : function(index){
12549         if(index < this.length && index >= 0){
12550             this.length--;
12551             var o = this.items[index];
12552             this.items.splice(index, 1);
12553             var key = this.keys[index];
12554             if(typeof key != "undefined"){
12555                 delete this.map[key];
12556             }
12557             this.keys.splice(index, 1);
12558             this.fireEvent("remove", o, key);
12559         }
12560     },
12561    
12562 /**
12563  * Removed an item associated with the passed key fom the collection.
12564  * @param {String} key The key of the item to remove.
12565  */
12566     removeKey : function(key){
12567         return this.removeAt(this.indexOfKey(key));
12568     },
12569    
12570 /**
12571  * Returns the number of items in the collection.
12572  * @return {Number} the number of items in the collection.
12573  */
12574     getCount : function(){
12575         return this.length; 
12576     },
12577    
12578 /**
12579  * Returns index within the collection of the passed Object.
12580  * @param {Object} o The item to find the index of.
12581  * @return {Number} index of the item.
12582  */
12583     indexOf : function(o){
12584         if(!this.items.indexOf){
12585             for(var i = 0, len = this.items.length; i < len; i++){
12586                 if(this.items[i] == o) return i;
12587             }
12588             return -1;
12589         }else{
12590             return this.items.indexOf(o);
12591         }
12592     },
12593    
12594 /**
12595  * Returns index within the collection of the passed key.
12596  * @param {String} key The key to find the index of.
12597  * @return {Number} index of the key.
12598  */
12599     indexOfKey : function(key){
12600         if(!this.keys.indexOf){
12601             for(var i = 0, len = this.keys.length; i < len; i++){
12602                 if(this.keys[i] == key) return i;
12603             }
12604             return -1;
12605         }else{
12606             return this.keys.indexOf(key);
12607         }
12608     },
12609    
12610 /**
12611  * Returns the item associated with the passed key OR index. Key has priority over index.
12612  * @param {String/Number} key The key or index of the item.
12613  * @return {Object} The item associated with the passed key.
12614  */
12615     item : function(key){
12616         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12617         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12618     },
12619     
12620 /**
12621  * Returns the item at the specified index.
12622  * @param {Number} index The index of the item.
12623  * @return {Object}
12624  */
12625     itemAt : function(index){
12626         return this.items[index];
12627     },
12628     
12629 /**
12630  * Returns the item associated with the passed key.
12631  * @param {String/Number} key The key of the item.
12632  * @return {Object} The item associated with the passed key.
12633  */
12634     key : function(key){
12635         return this.map[key];
12636     },
12637    
12638 /**
12639  * Returns true if the collection contains the passed Object as an item.
12640  * @param {Object} o  The Object to look for in the collection.
12641  * @return {Boolean} True if the collection contains the Object as an item.
12642  */
12643     contains : function(o){
12644         return this.indexOf(o) != -1;
12645     },
12646    
12647 /**
12648  * Returns true if the collection contains the passed Object as a key.
12649  * @param {String} key The key to look for in the collection.
12650  * @return {Boolean} True if the collection contains the Object as a key.
12651  */
12652     containsKey : function(key){
12653         return typeof this.map[key] != "undefined";
12654     },
12655    
12656 /**
12657  * Removes all items from the collection.
12658  */
12659     clear : function(){
12660         this.length = 0;
12661         this.items = [];
12662         this.keys = [];
12663         this.map = {};
12664         this.fireEvent("clear");
12665     },
12666    
12667 /**
12668  * Returns the first item in the collection.
12669  * @return {Object} the first item in the collection..
12670  */
12671     first : function(){
12672         return this.items[0]; 
12673     },
12674    
12675 /**
12676  * Returns the last item in the collection.
12677  * @return {Object} the last item in the collection..
12678  */
12679     last : function(){
12680         return this.items[this.length-1];   
12681     },
12682     
12683     _sort : function(property, dir, fn){
12684         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12685         fn = fn || function(a, b){
12686             return a-b;
12687         };
12688         var c = [], k = this.keys, items = this.items;
12689         for(var i = 0, len = items.length; i < len; i++){
12690             c[c.length] = {key: k[i], value: items[i], index: i};
12691         }
12692         c.sort(function(a, b){
12693             var v = fn(a[property], b[property]) * dsc;
12694             if(v == 0){
12695                 v = (a.index < b.index ? -1 : 1);
12696             }
12697             return v;
12698         });
12699         for(var i = 0, len = c.length; i < len; i++){
12700             items[i] = c[i].value;
12701             k[i] = c[i].key;
12702         }
12703         this.fireEvent("sort", this);
12704     },
12705     
12706     /**
12707      * Sorts this collection with the passed comparison function
12708      * @param {String} direction (optional) "ASC" or "DESC"
12709      * @param {Function} fn (optional) comparison function
12710      */
12711     sort : function(dir, fn){
12712         this._sort("value", dir, fn);
12713     },
12714     
12715     /**
12716      * Sorts this collection by keys
12717      * @param {String} direction (optional) "ASC" or "DESC"
12718      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12719      */
12720     keySort : function(dir, fn){
12721         this._sort("key", dir, fn || function(a, b){
12722             return String(a).toUpperCase()-String(b).toUpperCase();
12723         });
12724     },
12725     
12726     /**
12727      * Returns a range of items in this collection
12728      * @param {Number} startIndex (optional) defaults to 0
12729      * @param {Number} endIndex (optional) default to the last item
12730      * @return {Array} An array of items
12731      */
12732     getRange : function(start, end){
12733         var items = this.items;
12734         if(items.length < 1){
12735             return [];
12736         }
12737         start = start || 0;
12738         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12739         var r = [];
12740         if(start <= end){
12741             for(var i = start; i <= end; i++) {
12742                     r[r.length] = items[i];
12743             }
12744         }else{
12745             for(var i = start; i >= end; i--) {
12746                     r[r.length] = items[i];
12747             }
12748         }
12749         return r;
12750     },
12751         
12752     /**
12753      * Filter the <i>objects</i> in this collection by a specific property. 
12754      * Returns a new collection that has been filtered.
12755      * @param {String} property A property on your objects
12756      * @param {String/RegExp} value Either string that the property values 
12757      * should start with or a RegExp to test against the property
12758      * @return {MixedCollection} The new filtered collection
12759      */
12760     filter : function(property, value){
12761         if(!value.exec){ // not a regex
12762             value = String(value);
12763             if(value.length == 0){
12764                 return this.clone();
12765             }
12766             value = new RegExp("^" + Roo.escapeRe(value), "i");
12767         }
12768         return this.filterBy(function(o){
12769             return o && value.test(o[property]);
12770         });
12771         },
12772     
12773     /**
12774      * Filter by a function. * Returns a new collection that has been filtered.
12775      * The passed function will be called with each 
12776      * object in the collection. If the function returns true, the value is included 
12777      * otherwise it is filtered.
12778      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12779      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12780      * @return {MixedCollection} The new filtered collection
12781      */
12782     filterBy : function(fn, scope){
12783         var r = new Roo.util.MixedCollection();
12784         r.getKey = this.getKey;
12785         var k = this.keys, it = this.items;
12786         for(var i = 0, len = it.length; i < len; i++){
12787             if(fn.call(scope||this, it[i], k[i])){
12788                                 r.add(k[i], it[i]);
12789                         }
12790         }
12791         return r;
12792     },
12793     
12794     /**
12795      * Creates a duplicate of this collection
12796      * @return {MixedCollection}
12797      */
12798     clone : function(){
12799         var r = new Roo.util.MixedCollection();
12800         var k = this.keys, it = this.items;
12801         for(var i = 0, len = it.length; i < len; i++){
12802             r.add(k[i], it[i]);
12803         }
12804         r.getKey = this.getKey;
12805         return r;
12806     }
12807 });
12808 /**
12809  * Returns the item associated with the passed key or index.
12810  * @method
12811  * @param {String/Number} key The key or index of the item.
12812  * @return {Object} The item associated with the passed key.
12813  */
12814 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12815  * Based on:
12816  * Ext JS Library 1.1.1
12817  * Copyright(c) 2006-2007, Ext JS, LLC.
12818  *
12819  * Originally Released Under LGPL - original licence link has changed is not relivant.
12820  *
12821  * Fork - LGPL
12822  * <script type="text/javascript">
12823  */
12824 /**
12825  * @class Roo.util.JSON
12826  * Modified version of Douglas Crockford"s json.js that doesn"t
12827  * mess with the Object prototype 
12828  * http://www.json.org/js.html
12829  * @singleton
12830  */
12831 Roo.util.JSON = new (function(){
12832     var useHasOwn = {}.hasOwnProperty ? true : false;
12833     
12834     // crashes Safari in some instances
12835     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12836     
12837     var pad = function(n) {
12838         return n < 10 ? "0" + n : n;
12839     };
12840     
12841     var m = {
12842         "\b": '\\b',
12843         "\t": '\\t',
12844         "\n": '\\n',
12845         "\f": '\\f',
12846         "\r": '\\r',
12847         '"' : '\\"',
12848         "\\": '\\\\'
12849     };
12850
12851     var encodeString = function(s){
12852         if (/["\\\x00-\x1f]/.test(s)) {
12853             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12854                 var c = m[b];
12855                 if(c){
12856                     return c;
12857                 }
12858                 c = b.charCodeAt();
12859                 return "\\u00" +
12860                     Math.floor(c / 16).toString(16) +
12861                     (c % 16).toString(16);
12862             }) + '"';
12863         }
12864         return '"' + s + '"';
12865     };
12866     
12867     var encodeArray = function(o){
12868         var a = ["["], b, i, l = o.length, v;
12869             for (i = 0; i < l; i += 1) {
12870                 v = o[i];
12871                 switch (typeof v) {
12872                     case "undefined":
12873                     case "function":
12874                     case "unknown":
12875                         break;
12876                     default:
12877                         if (b) {
12878                             a.push(',');
12879                         }
12880                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12881                         b = true;
12882                 }
12883             }
12884             a.push("]");
12885             return a.join("");
12886     };
12887     
12888     var encodeDate = function(o){
12889         return '"' + o.getFullYear() + "-" +
12890                 pad(o.getMonth() + 1) + "-" +
12891                 pad(o.getDate()) + "T" +
12892                 pad(o.getHours()) + ":" +
12893                 pad(o.getMinutes()) + ":" +
12894                 pad(o.getSeconds()) + '"';
12895     };
12896     
12897     /**
12898      * Encodes an Object, Array or other value
12899      * @param {Mixed} o The variable to encode
12900      * @return {String} The JSON string
12901      */
12902     this.encode = function(o)
12903     {
12904         // should this be extended to fully wrap stringify..
12905         
12906         if(typeof o == "undefined" || o === null){
12907             return "null";
12908         }else if(o instanceof Array){
12909             return encodeArray(o);
12910         }else if(o instanceof Date){
12911             return encodeDate(o);
12912         }else if(typeof o == "string"){
12913             return encodeString(o);
12914         }else if(typeof o == "number"){
12915             return isFinite(o) ? String(o) : "null";
12916         }else if(typeof o == "boolean"){
12917             return String(o);
12918         }else {
12919             var a = ["{"], b, i, v;
12920             for (i in o) {
12921                 if(!useHasOwn || o.hasOwnProperty(i)) {
12922                     v = o[i];
12923                     switch (typeof v) {
12924                     case "undefined":
12925                     case "function":
12926                     case "unknown":
12927                         break;
12928                     default:
12929                         if(b){
12930                             a.push(',');
12931                         }
12932                         a.push(this.encode(i), ":",
12933                                 v === null ? "null" : this.encode(v));
12934                         b = true;
12935                     }
12936                 }
12937             }
12938             a.push("}");
12939             return a.join("");
12940         }
12941     };
12942     
12943     /**
12944      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12945      * @param {String} json The JSON string
12946      * @return {Object} The resulting object
12947      */
12948     this.decode = function(json){
12949         
12950         return  /** eval:var:json */ eval("(" + json + ')');
12951     };
12952 })();
12953 /** 
12954  * Shorthand for {@link Roo.util.JSON#encode}
12955  * @member Roo encode 
12956  * @method */
12957 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12958 /** 
12959  * Shorthand for {@link Roo.util.JSON#decode}
12960  * @member Roo decode 
12961  * @method */
12962 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12963 /*
12964  * Based on:
12965  * Ext JS Library 1.1.1
12966  * Copyright(c) 2006-2007, Ext JS, LLC.
12967  *
12968  * Originally Released Under LGPL - original licence link has changed is not relivant.
12969  *
12970  * Fork - LGPL
12971  * <script type="text/javascript">
12972  */
12973  
12974 /**
12975  * @class Roo.util.Format
12976  * Reusable data formatting functions
12977  * @singleton
12978  */
12979 Roo.util.Format = function(){
12980     var trimRe = /^\s+|\s+$/g;
12981     return {
12982         /**
12983          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12984          * @param {String} value The string to truncate
12985          * @param {Number} length The maximum length to allow before truncating
12986          * @return {String} The converted text
12987          */
12988         ellipsis : function(value, len){
12989             if(value && value.length > len){
12990                 return value.substr(0, len-3)+"...";
12991             }
12992             return value;
12993         },
12994
12995         /**
12996          * Checks a reference and converts it to empty string if it is undefined
12997          * @param {Mixed} value Reference to check
12998          * @return {Mixed} Empty string if converted, otherwise the original value
12999          */
13000         undef : function(value){
13001             return typeof value != "undefined" ? value : "";
13002         },
13003
13004         /**
13005          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13006          * @param {String} value The string to encode
13007          * @return {String} The encoded text
13008          */
13009         htmlEncode : function(value){
13010             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13011         },
13012
13013         /**
13014          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13015          * @param {String} value The string to decode
13016          * @return {String} The decoded text
13017          */
13018         htmlDecode : function(value){
13019             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13020         },
13021
13022         /**
13023          * Trims any whitespace from either side of a string
13024          * @param {String} value The text to trim
13025          * @return {String} The trimmed text
13026          */
13027         trim : function(value){
13028             return String(value).replace(trimRe, "");
13029         },
13030
13031         /**
13032          * Returns a substring from within an original string
13033          * @param {String} value The original text
13034          * @param {Number} start The start index of the substring
13035          * @param {Number} length The length of the substring
13036          * @return {String} The substring
13037          */
13038         substr : function(value, start, length){
13039             return String(value).substr(start, length);
13040         },
13041
13042         /**
13043          * Converts a string to all lower case letters
13044          * @param {String} value The text to convert
13045          * @return {String} The converted text
13046          */
13047         lowercase : function(value){
13048             return String(value).toLowerCase();
13049         },
13050
13051         /**
13052          * Converts a string to all upper case letters
13053          * @param {String} value The text to convert
13054          * @return {String} The converted text
13055          */
13056         uppercase : function(value){
13057             return String(value).toUpperCase();
13058         },
13059
13060         /**
13061          * Converts the first character only of a string to upper case
13062          * @param {String} value The text to convert
13063          * @return {String} The converted text
13064          */
13065         capitalize : function(value){
13066             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13067         },
13068
13069         // private
13070         call : function(value, fn){
13071             if(arguments.length > 2){
13072                 var args = Array.prototype.slice.call(arguments, 2);
13073                 args.unshift(value);
13074                  
13075                 return /** eval:var:value */  eval(fn).apply(window, args);
13076             }else{
13077                 /** eval:var:value */
13078                 return /** eval:var:value */ eval(fn).call(window, value);
13079             }
13080         },
13081
13082        
13083         /**
13084          * safer version of Math.toFixed..??/
13085          * @param {Number/String} value The numeric value to format
13086          * @param {Number/String} value Decimal places 
13087          * @return {String} The formatted currency string
13088          */
13089         toFixed : function(v, n)
13090         {
13091             // why not use to fixed - precision is buggered???
13092             if (!n) {
13093                 return Math.round(v-0);
13094             }
13095             var fact = Math.pow(10,n+1);
13096             v = (Math.round((v-0)*fact))/fact;
13097             var z = (''+fact).substring(2);
13098             if (v == Math.floor(v)) {
13099                 return Math.floor(v) + '.' + z;
13100             }
13101             
13102             // now just padd decimals..
13103             var ps = String(v).split('.');
13104             var fd = (ps[1] + z);
13105             var r = fd.substring(0,n); 
13106             var rm = fd.substring(n); 
13107             if (rm < 5) {
13108                 return ps[0] + '.' + r;
13109             }
13110             r*=1; // turn it into a number;
13111             r++;
13112             if (String(r).length != n) {
13113                 ps[0]*=1;
13114                 ps[0]++;
13115                 r = String(r).substring(1); // chop the end off.
13116             }
13117             
13118             return ps[0] + '.' + r;
13119              
13120         },
13121         
13122         /**
13123          * Format a number as US currency
13124          * @param {Number/String} value The numeric value to format
13125          * @return {String} The formatted currency string
13126          */
13127         usMoney : function(v){
13128             v = (Math.round((v-0)*100))/100;
13129             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13130             v = String(v);
13131             var ps = v.split('.');
13132             var whole = ps[0];
13133             var sub = ps[1] ? '.'+ ps[1] : '.00';
13134             var r = /(\d+)(\d{3})/;
13135             while (r.test(whole)) {
13136                 whole = whole.replace(r, '$1' + ',' + '$2');
13137             }
13138             return "$" + whole + sub ;
13139         },
13140         
13141         /**
13142          * Parse a value into a formatted date using the specified format pattern.
13143          * @param {Mixed} value The value to format
13144          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13145          * @return {String} The formatted date string
13146          */
13147         date : function(v, format){
13148             if(!v){
13149                 return "";
13150             }
13151             if(!(v instanceof Date)){
13152                 v = new Date(Date.parse(v));
13153             }
13154             return v.dateFormat(format || "m/d/Y");
13155         },
13156
13157         /**
13158          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13159          * @param {String} format Any valid date format string
13160          * @return {Function} The date formatting function
13161          */
13162         dateRenderer : function(format){
13163             return function(v){
13164                 return Roo.util.Format.date(v, format);  
13165             };
13166         },
13167
13168         // private
13169         stripTagsRE : /<\/?[^>]+>/gi,
13170         
13171         /**
13172          * Strips all HTML tags
13173          * @param {Mixed} value The text from which to strip tags
13174          * @return {String} The stripped text
13175          */
13176         stripTags : function(v){
13177             return !v ? v : String(v).replace(this.stripTagsRE, "");
13178         }
13179     };
13180 }();/*
13181  * Based on:
13182  * Ext JS Library 1.1.1
13183  * Copyright(c) 2006-2007, Ext JS, LLC.
13184  *
13185  * Originally Released Under LGPL - original licence link has changed is not relivant.
13186  *
13187  * Fork - LGPL
13188  * <script type="text/javascript">
13189  */
13190
13191
13192  
13193
13194 /**
13195  * @class Roo.MasterTemplate
13196  * @extends Roo.Template
13197  * Provides a template that can have child templates. The syntax is:
13198 <pre><code>
13199 var t = new Roo.MasterTemplate(
13200         '&lt;select name="{name}"&gt;',
13201                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13202         '&lt;/select&gt;'
13203 );
13204 t.add('options', {value: 'foo', text: 'bar'});
13205 // or you can add multiple child elements in one shot
13206 t.addAll('options', [
13207     {value: 'foo', text: 'bar'},
13208     {value: 'foo2', text: 'bar2'},
13209     {value: 'foo3', text: 'bar3'}
13210 ]);
13211 // then append, applying the master template values
13212 t.append('my-form', {name: 'my-select'});
13213 </code></pre>
13214 * A name attribute for the child template is not required if you have only one child
13215 * template or you want to refer to them by index.
13216  */
13217 Roo.MasterTemplate = function(){
13218     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13219     this.originalHtml = this.html;
13220     var st = {};
13221     var m, re = this.subTemplateRe;
13222     re.lastIndex = 0;
13223     var subIndex = 0;
13224     while(m = re.exec(this.html)){
13225         var name = m[1], content = m[2];
13226         st[subIndex] = {
13227             name: name,
13228             index: subIndex,
13229             buffer: [],
13230             tpl : new Roo.Template(content)
13231         };
13232         if(name){
13233             st[name] = st[subIndex];
13234         }
13235         st[subIndex].tpl.compile();
13236         st[subIndex].tpl.call = this.call.createDelegate(this);
13237         subIndex++;
13238     }
13239     this.subCount = subIndex;
13240     this.subs = st;
13241 };
13242 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13243     /**
13244     * The regular expression used to match sub templates
13245     * @type RegExp
13246     * @property
13247     */
13248     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13249
13250     /**
13251      * Applies the passed values to a child template.
13252      * @param {String/Number} name (optional) The name or index of the child template
13253      * @param {Array/Object} values The values to be applied to the template
13254      * @return {MasterTemplate} this
13255      */
13256      add : function(name, values){
13257         if(arguments.length == 1){
13258             values = arguments[0];
13259             name = 0;
13260         }
13261         var s = this.subs[name];
13262         s.buffer[s.buffer.length] = s.tpl.apply(values);
13263         return this;
13264     },
13265
13266     /**
13267      * Applies all the passed values to a child template.
13268      * @param {String/Number} name (optional) The name or index of the child template
13269      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13270      * @param {Boolean} reset (optional) True to reset the template first
13271      * @return {MasterTemplate} this
13272      */
13273     fill : function(name, values, reset){
13274         var a = arguments;
13275         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13276             values = a[0];
13277             name = 0;
13278             reset = a[1];
13279         }
13280         if(reset){
13281             this.reset();
13282         }
13283         for(var i = 0, len = values.length; i < len; i++){
13284             this.add(name, values[i]);
13285         }
13286         return this;
13287     },
13288
13289     /**
13290      * Resets the template for reuse
13291      * @return {MasterTemplate} this
13292      */
13293      reset : function(){
13294         var s = this.subs;
13295         for(var i = 0; i < this.subCount; i++){
13296             s[i].buffer = [];
13297         }
13298         return this;
13299     },
13300
13301     applyTemplate : function(values){
13302         var s = this.subs;
13303         var replaceIndex = -1;
13304         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13305             return s[++replaceIndex].buffer.join("");
13306         });
13307         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13308     },
13309
13310     apply : function(){
13311         return this.applyTemplate.apply(this, arguments);
13312     },
13313
13314     compile : function(){return this;}
13315 });
13316
13317 /**
13318  * Alias for fill().
13319  * @method
13320  */
13321 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13322  /**
13323  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13324  * var tpl = Roo.MasterTemplate.from('element-id');
13325  * @param {String/HTMLElement} el
13326  * @param {Object} config
13327  * @static
13328  */
13329 Roo.MasterTemplate.from = function(el, config){
13330     el = Roo.getDom(el);
13331     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13332 };/*
13333  * Based on:
13334  * Ext JS Library 1.1.1
13335  * Copyright(c) 2006-2007, Ext JS, LLC.
13336  *
13337  * Originally Released Under LGPL - original licence link has changed is not relivant.
13338  *
13339  * Fork - LGPL
13340  * <script type="text/javascript">
13341  */
13342
13343  
13344 /**
13345  * @class Roo.util.CSS
13346  * Utility class for manipulating CSS rules
13347  * @singleton
13348  */
13349 Roo.util.CSS = function(){
13350         var rules = null;
13351         var doc = document;
13352
13353     var camelRe = /(-[a-z])/gi;
13354     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13355
13356    return {
13357    /**
13358     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13359     * tag and appended to the HEAD of the document.
13360     * @param {String|Object} cssText The text containing the css rules
13361     * @param {String} id An id to add to the stylesheet for later removal
13362     * @return {StyleSheet}
13363     */
13364     createStyleSheet : function(cssText, id){
13365         var ss;
13366         var head = doc.getElementsByTagName("head")[0];
13367         var nrules = doc.createElement("style");
13368         nrules.setAttribute("type", "text/css");
13369         if(id){
13370             nrules.setAttribute("id", id);
13371         }
13372         if (typeof(cssText) != 'string') {
13373             // support object maps..
13374             // not sure if this a good idea.. 
13375             // perhaps it should be merged with the general css handling
13376             // and handle js style props.
13377             var cssTextNew = [];
13378             for(var n in cssText) {
13379                 var citems = [];
13380                 for(var k in cssText[n]) {
13381                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13382                 }
13383                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13384                 
13385             }
13386             cssText = cssTextNew.join("\n");
13387             
13388         }
13389        
13390        
13391        if(Roo.isIE){
13392            head.appendChild(nrules);
13393            ss = nrules.styleSheet;
13394            ss.cssText = cssText;
13395        }else{
13396            try{
13397                 nrules.appendChild(doc.createTextNode(cssText));
13398            }catch(e){
13399                nrules.cssText = cssText; 
13400            }
13401            head.appendChild(nrules);
13402            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13403        }
13404        this.cacheStyleSheet(ss);
13405        return ss;
13406    },
13407
13408    /**
13409     * Removes a style or link tag by id
13410     * @param {String} id The id of the tag
13411     */
13412    removeStyleSheet : function(id){
13413        var existing = doc.getElementById(id);
13414        if(existing){
13415            existing.parentNode.removeChild(existing);
13416        }
13417    },
13418
13419    /**
13420     * Dynamically swaps an existing stylesheet reference for a new one
13421     * @param {String} id The id of an existing link tag to remove
13422     * @param {String} url The href of the new stylesheet to include
13423     */
13424    swapStyleSheet : function(id, url){
13425        this.removeStyleSheet(id);
13426        var ss = doc.createElement("link");
13427        ss.setAttribute("rel", "stylesheet");
13428        ss.setAttribute("type", "text/css");
13429        ss.setAttribute("id", id);
13430        ss.setAttribute("href", url);
13431        doc.getElementsByTagName("head")[0].appendChild(ss);
13432    },
13433    
13434    /**
13435     * Refresh the rule cache if you have dynamically added stylesheets
13436     * @return {Object} An object (hash) of rules indexed by selector
13437     */
13438    refreshCache : function(){
13439        return this.getRules(true);
13440    },
13441
13442    // private
13443    cacheStyleSheet : function(stylesheet){
13444        if(!rules){
13445            rules = {};
13446        }
13447        try{// try catch for cross domain access issue
13448            var ssRules = stylesheet.cssRules || stylesheet.rules;
13449            for(var j = ssRules.length-1; j >= 0; --j){
13450                rules[ssRules[j].selectorText] = ssRules[j];
13451            }
13452        }catch(e){}
13453    },
13454    
13455    /**
13456     * Gets all css rules for the document
13457     * @param {Boolean} refreshCache true to refresh the internal cache
13458     * @return {Object} An object (hash) of rules indexed by selector
13459     */
13460    getRules : function(refreshCache){
13461                 if(rules == null || refreshCache){
13462                         rules = {};
13463                         var ds = doc.styleSheets;
13464                         for(var i =0, len = ds.length; i < len; i++){
13465                             try{
13466                         this.cacheStyleSheet(ds[i]);
13467                     }catch(e){} 
13468                 }
13469                 }
13470                 return rules;
13471         },
13472         
13473         /**
13474     * Gets an an individual CSS rule by selector(s)
13475     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13476     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13477     * @return {CSSRule} The CSS rule or null if one is not found
13478     */
13479    getRule : function(selector, refreshCache){
13480                 var rs = this.getRules(refreshCache);
13481                 if(!(selector instanceof Array)){
13482                     return rs[selector];
13483                 }
13484                 for(var i = 0; i < selector.length; i++){
13485                         if(rs[selector[i]]){
13486                                 return rs[selector[i]];
13487                         }
13488                 }
13489                 return null;
13490         },
13491         
13492         
13493         /**
13494     * Updates a rule property
13495     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13496     * @param {String} property The css property
13497     * @param {String} value The new value for the property
13498     * @return {Boolean} true If a rule was found and updated
13499     */
13500    updateRule : function(selector, property, value){
13501                 if(!(selector instanceof Array)){
13502                         var rule = this.getRule(selector);
13503                         if(rule){
13504                                 rule.style[property.replace(camelRe, camelFn)] = value;
13505                                 return true;
13506                         }
13507                 }else{
13508                         for(var i = 0; i < selector.length; i++){
13509                                 if(this.updateRule(selector[i], property, value)){
13510                                         return true;
13511                                 }
13512                         }
13513                 }
13514                 return false;
13515         }
13516    };   
13517 }();/*
13518  * Based on:
13519  * Ext JS Library 1.1.1
13520  * Copyright(c) 2006-2007, Ext JS, LLC.
13521  *
13522  * Originally Released Under LGPL - original licence link has changed is not relivant.
13523  *
13524  * Fork - LGPL
13525  * <script type="text/javascript">
13526  */
13527
13528  
13529
13530 /**
13531  * @class Roo.util.ClickRepeater
13532  * @extends Roo.util.Observable
13533  * 
13534  * A wrapper class which can be applied to any element. Fires a "click" event while the
13535  * mouse is pressed. The interval between firings may be specified in the config but
13536  * defaults to 10 milliseconds.
13537  * 
13538  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13539  * 
13540  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13541  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13542  * Similar to an autorepeat key delay.
13543  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13544  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13545  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13546  *           "interval" and "delay" are ignored. "immediate" is honored.
13547  * @cfg {Boolean} preventDefault True to prevent the default click event
13548  * @cfg {Boolean} stopDefault True to stop the default click event
13549  * 
13550  * @history
13551  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13552  *     2007-02-02 jvs Renamed to ClickRepeater
13553  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13554  *
13555  *  @constructor
13556  * @param {String/HTMLElement/Element} el The element to listen on
13557  * @param {Object} config
13558  **/
13559 Roo.util.ClickRepeater = function(el, config)
13560 {
13561     this.el = Roo.get(el);
13562     this.el.unselectable();
13563
13564     Roo.apply(this, config);
13565
13566     this.addEvents({
13567     /**
13568      * @event mousedown
13569      * Fires when the mouse button is depressed.
13570      * @param {Roo.util.ClickRepeater} this
13571      */
13572         "mousedown" : true,
13573     /**
13574      * @event click
13575      * Fires on a specified interval during the time the element is pressed.
13576      * @param {Roo.util.ClickRepeater} this
13577      */
13578         "click" : true,
13579     /**
13580      * @event mouseup
13581      * Fires when the mouse key is released.
13582      * @param {Roo.util.ClickRepeater} this
13583      */
13584         "mouseup" : true
13585     });
13586
13587     this.el.on("mousedown", this.handleMouseDown, this);
13588     if(this.preventDefault || this.stopDefault){
13589         this.el.on("click", function(e){
13590             if(this.preventDefault){
13591                 e.preventDefault();
13592             }
13593             if(this.stopDefault){
13594                 e.stopEvent();
13595             }
13596         }, this);
13597     }
13598
13599     // allow inline handler
13600     if(this.handler){
13601         this.on("click", this.handler,  this.scope || this);
13602     }
13603
13604     Roo.util.ClickRepeater.superclass.constructor.call(this);
13605 };
13606
13607 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13608     interval : 20,
13609     delay: 250,
13610     preventDefault : true,
13611     stopDefault : false,
13612     timer : 0,
13613
13614     // private
13615     handleMouseDown : function(){
13616         clearTimeout(this.timer);
13617         this.el.blur();
13618         if(this.pressClass){
13619             this.el.addClass(this.pressClass);
13620         }
13621         this.mousedownTime = new Date();
13622
13623         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13624         this.el.on("mouseout", this.handleMouseOut, this);
13625
13626         this.fireEvent("mousedown", this);
13627         this.fireEvent("click", this);
13628         
13629         this.timer = this.click.defer(this.delay || this.interval, this);
13630     },
13631
13632     // private
13633     click : function(){
13634         this.fireEvent("click", this);
13635         this.timer = this.click.defer(this.getInterval(), this);
13636     },
13637
13638     // private
13639     getInterval: function(){
13640         if(!this.accelerate){
13641             return this.interval;
13642         }
13643         var pressTime = this.mousedownTime.getElapsed();
13644         if(pressTime < 500){
13645             return 400;
13646         }else if(pressTime < 1700){
13647             return 320;
13648         }else if(pressTime < 2600){
13649             return 250;
13650         }else if(pressTime < 3500){
13651             return 180;
13652         }else if(pressTime < 4400){
13653             return 140;
13654         }else if(pressTime < 5300){
13655             return 80;
13656         }else if(pressTime < 6200){
13657             return 50;
13658         }else{
13659             return 10;
13660         }
13661     },
13662
13663     // private
13664     handleMouseOut : function(){
13665         clearTimeout(this.timer);
13666         if(this.pressClass){
13667             this.el.removeClass(this.pressClass);
13668         }
13669         this.el.on("mouseover", this.handleMouseReturn, this);
13670     },
13671
13672     // private
13673     handleMouseReturn : function(){
13674         this.el.un("mouseover", this.handleMouseReturn);
13675         if(this.pressClass){
13676             this.el.addClass(this.pressClass);
13677         }
13678         this.click();
13679     },
13680
13681     // private
13682     handleMouseUp : function(){
13683         clearTimeout(this.timer);
13684         this.el.un("mouseover", this.handleMouseReturn);
13685         this.el.un("mouseout", this.handleMouseOut);
13686         Roo.get(document).un("mouseup", this.handleMouseUp);
13687         this.el.removeClass(this.pressClass);
13688         this.fireEvent("mouseup", this);
13689     }
13690 });/*
13691  * Based on:
13692  * Ext JS Library 1.1.1
13693  * Copyright(c) 2006-2007, Ext JS, LLC.
13694  *
13695  * Originally Released Under LGPL - original licence link has changed is not relivant.
13696  *
13697  * Fork - LGPL
13698  * <script type="text/javascript">
13699  */
13700
13701  
13702 /**
13703  * @class Roo.KeyNav
13704  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13705  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13706  * way to implement custom navigation schemes for any UI component.</p>
13707  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13708  * pageUp, pageDown, del, home, end.  Usage:</p>
13709  <pre><code>
13710 var nav = new Roo.KeyNav("my-element", {
13711     "left" : function(e){
13712         this.moveLeft(e.ctrlKey);
13713     },
13714     "right" : function(e){
13715         this.moveRight(e.ctrlKey);
13716     },
13717     "enter" : function(e){
13718         this.save();
13719     },
13720     scope : this
13721 });
13722 </code></pre>
13723  * @constructor
13724  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13725  * @param {Object} config The config
13726  */
13727 Roo.KeyNav = function(el, config){
13728     this.el = Roo.get(el);
13729     Roo.apply(this, config);
13730     if(!this.disabled){
13731         this.disabled = true;
13732         this.enable();
13733     }
13734 };
13735
13736 Roo.KeyNav.prototype = {
13737     /**
13738      * @cfg {Boolean} disabled
13739      * True to disable this KeyNav instance (defaults to false)
13740      */
13741     disabled : false,
13742     /**
13743      * @cfg {String} defaultEventAction
13744      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13745      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13746      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13747      */
13748     defaultEventAction: "stopEvent",
13749     /**
13750      * @cfg {Boolean} forceKeyDown
13751      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13752      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13753      * handle keydown instead of keypress.
13754      */
13755     forceKeyDown : false,
13756
13757     // private
13758     prepareEvent : function(e){
13759         var k = e.getKey();
13760         var h = this.keyToHandler[k];
13761         //if(h && this[h]){
13762         //    e.stopPropagation();
13763         //}
13764         if(Roo.isSafari && h && k >= 37 && k <= 40){
13765             e.stopEvent();
13766         }
13767     },
13768
13769     // private
13770     relay : function(e){
13771         var k = e.getKey();
13772         var h = this.keyToHandler[k];
13773         if(h && this[h]){
13774             if(this.doRelay(e, this[h], h) !== true){
13775                 e[this.defaultEventAction]();
13776             }
13777         }
13778     },
13779
13780     // private
13781     doRelay : function(e, h, hname){
13782         return h.call(this.scope || this, e);
13783     },
13784
13785     // possible handlers
13786     enter : false,
13787     left : false,
13788     right : false,
13789     up : false,
13790     down : false,
13791     tab : false,
13792     esc : false,
13793     pageUp : false,
13794     pageDown : false,
13795     del : false,
13796     home : false,
13797     end : false,
13798
13799     // quick lookup hash
13800     keyToHandler : {
13801         37 : "left",
13802         39 : "right",
13803         38 : "up",
13804         40 : "down",
13805         33 : "pageUp",
13806         34 : "pageDown",
13807         46 : "del",
13808         36 : "home",
13809         35 : "end",
13810         13 : "enter",
13811         27 : "esc",
13812         9  : "tab"
13813     },
13814
13815         /**
13816          * Enable this KeyNav
13817          */
13818         enable: function(){
13819                 if(this.disabled){
13820             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13821             // the EventObject will normalize Safari automatically
13822             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13823                 this.el.on("keydown", this.relay,  this);
13824             }else{
13825                 this.el.on("keydown", this.prepareEvent,  this);
13826                 this.el.on("keypress", this.relay,  this);
13827             }
13828                     this.disabled = false;
13829                 }
13830         },
13831
13832         /**
13833          * Disable this KeyNav
13834          */
13835         disable: function(){
13836                 if(!this.disabled){
13837                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13838                 this.el.un("keydown", this.relay);
13839             }else{
13840                 this.el.un("keydown", this.prepareEvent);
13841                 this.el.un("keypress", this.relay);
13842             }
13843                     this.disabled = true;
13844                 }
13845         }
13846 };/*
13847  * Based on:
13848  * Ext JS Library 1.1.1
13849  * Copyright(c) 2006-2007, Ext JS, LLC.
13850  *
13851  * Originally Released Under LGPL - original licence link has changed is not relivant.
13852  *
13853  * Fork - LGPL
13854  * <script type="text/javascript">
13855  */
13856
13857  
13858 /**
13859  * @class Roo.KeyMap
13860  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13861  * The constructor accepts the same config object as defined by {@link #addBinding}.
13862  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13863  * combination it will call the function with this signature (if the match is a multi-key
13864  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13865  * A KeyMap can also handle a string representation of keys.<br />
13866  * Usage:
13867  <pre><code>
13868 // map one key by key code
13869 var map = new Roo.KeyMap("my-element", {
13870     key: 13, // or Roo.EventObject.ENTER
13871     fn: myHandler,
13872     scope: myObject
13873 });
13874
13875 // map multiple keys to one action by string
13876 var map = new Roo.KeyMap("my-element", {
13877     key: "a\r\n\t",
13878     fn: myHandler,
13879     scope: myObject
13880 });
13881
13882 // map multiple keys to multiple actions by strings and array of codes
13883 var map = new Roo.KeyMap("my-element", [
13884     {
13885         key: [10,13],
13886         fn: function(){ alert("Return was pressed"); }
13887     }, {
13888         key: "abc",
13889         fn: function(){ alert('a, b or c was pressed'); }
13890     }, {
13891         key: "\t",
13892         ctrl:true,
13893         shift:true,
13894         fn: function(){ alert('Control + shift + tab was pressed.'); }
13895     }
13896 ]);
13897 </code></pre>
13898  * <b>Note: A KeyMap starts enabled</b>
13899  * @constructor
13900  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13901  * @param {Object} config The config (see {@link #addBinding})
13902  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13903  */
13904 Roo.KeyMap = function(el, config, eventName){
13905     this.el  = Roo.get(el);
13906     this.eventName = eventName || "keydown";
13907     this.bindings = [];
13908     if(config){
13909         this.addBinding(config);
13910     }
13911     this.enable();
13912 };
13913
13914 Roo.KeyMap.prototype = {
13915     /**
13916      * True to stop the event from bubbling and prevent the default browser action if the
13917      * key was handled by the KeyMap (defaults to false)
13918      * @type Boolean
13919      */
13920     stopEvent : false,
13921
13922     /**
13923      * Add a new binding to this KeyMap. The following config object properties are supported:
13924      * <pre>
13925 Property    Type             Description
13926 ----------  ---------------  ----------------------------------------------------------------------
13927 key         String/Array     A single keycode or an array of keycodes to handle
13928 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13929 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13930 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13931 fn          Function         The function to call when KeyMap finds the expected key combination
13932 scope       Object           The scope of the callback function
13933 </pre>
13934      *
13935      * Usage:
13936      * <pre><code>
13937 // Create a KeyMap
13938 var map = new Roo.KeyMap(document, {
13939     key: Roo.EventObject.ENTER,
13940     fn: handleKey,
13941     scope: this
13942 });
13943
13944 //Add a new binding to the existing KeyMap later
13945 map.addBinding({
13946     key: 'abc',
13947     shift: true,
13948     fn: handleKey,
13949     scope: this
13950 });
13951 </code></pre>
13952      * @param {Object/Array} config A single KeyMap config or an array of configs
13953      */
13954         addBinding : function(config){
13955         if(config instanceof Array){
13956             for(var i = 0, len = config.length; i < len; i++){
13957                 this.addBinding(config[i]);
13958             }
13959             return;
13960         }
13961         var keyCode = config.key,
13962             shift = config.shift, 
13963             ctrl = config.ctrl, 
13964             alt = config.alt,
13965             fn = config.fn,
13966             scope = config.scope;
13967         if(typeof keyCode == "string"){
13968             var ks = [];
13969             var keyString = keyCode.toUpperCase();
13970             for(var j = 0, len = keyString.length; j < len; j++){
13971                 ks.push(keyString.charCodeAt(j));
13972             }
13973             keyCode = ks;
13974         }
13975         var keyArray = keyCode instanceof Array;
13976         var handler = function(e){
13977             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13978                 var k = e.getKey();
13979                 if(keyArray){
13980                     for(var i = 0, len = keyCode.length; i < len; i++){
13981                         if(keyCode[i] == k){
13982                           if(this.stopEvent){
13983                               e.stopEvent();
13984                           }
13985                           fn.call(scope || window, k, e);
13986                           return;
13987                         }
13988                     }
13989                 }else{
13990                     if(k == keyCode){
13991                         if(this.stopEvent){
13992                            e.stopEvent();
13993                         }
13994                         fn.call(scope || window, k, e);
13995                     }
13996                 }
13997             }
13998         };
13999         this.bindings.push(handler);  
14000         },
14001
14002     /**
14003      * Shorthand for adding a single key listener
14004      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14005      * following options:
14006      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14007      * @param {Function} fn The function to call
14008      * @param {Object} scope (optional) The scope of the function
14009      */
14010     on : function(key, fn, scope){
14011         var keyCode, shift, ctrl, alt;
14012         if(typeof key == "object" && !(key instanceof Array)){
14013             keyCode = key.key;
14014             shift = key.shift;
14015             ctrl = key.ctrl;
14016             alt = key.alt;
14017         }else{
14018             keyCode = key;
14019         }
14020         this.addBinding({
14021             key: keyCode,
14022             shift: shift,
14023             ctrl: ctrl,
14024             alt: alt,
14025             fn: fn,
14026             scope: scope
14027         })
14028     },
14029
14030     // private
14031     handleKeyDown : function(e){
14032             if(this.enabled){ //just in case
14033             var b = this.bindings;
14034             for(var i = 0, len = b.length; i < len; i++){
14035                 b[i].call(this, e);
14036             }
14037             }
14038         },
14039         
14040         /**
14041          * Returns true if this KeyMap is enabled
14042          * @return {Boolean} 
14043          */
14044         isEnabled : function(){
14045             return this.enabled;  
14046         },
14047         
14048         /**
14049          * Enables this KeyMap
14050          */
14051         enable: function(){
14052                 if(!this.enabled){
14053                     this.el.on(this.eventName, this.handleKeyDown, this);
14054                     this.enabled = true;
14055                 }
14056         },
14057
14058         /**
14059          * Disable this KeyMap
14060          */
14061         disable: function(){
14062                 if(this.enabled){
14063                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14064                     this.enabled = false;
14065                 }
14066         }
14067 };/*
14068  * Based on:
14069  * Ext JS Library 1.1.1
14070  * Copyright(c) 2006-2007, Ext JS, LLC.
14071  *
14072  * Originally Released Under LGPL - original licence link has changed is not relivant.
14073  *
14074  * Fork - LGPL
14075  * <script type="text/javascript">
14076  */
14077
14078  
14079 /**
14080  * @class Roo.util.TextMetrics
14081  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14082  * wide, in pixels, a given block of text will be.
14083  * @singleton
14084  */
14085 Roo.util.TextMetrics = function(){
14086     var shared;
14087     return {
14088         /**
14089          * Measures the size of the specified text
14090          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14091          * that can affect the size of the rendered text
14092          * @param {String} text The text to measure
14093          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14094          * in order to accurately measure the text height
14095          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14096          */
14097         measure : function(el, text, fixedWidth){
14098             if(!shared){
14099                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14100             }
14101             shared.bind(el);
14102             shared.setFixedWidth(fixedWidth || 'auto');
14103             return shared.getSize(text);
14104         },
14105
14106         /**
14107          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14108          * the overhead of multiple calls to initialize the style properties on each measurement.
14109          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14110          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14111          * in order to accurately measure the text height
14112          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14113          */
14114         createInstance : function(el, fixedWidth){
14115             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14116         }
14117     };
14118 }();
14119
14120  
14121
14122 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14123     var ml = new Roo.Element(document.createElement('div'));
14124     document.body.appendChild(ml.dom);
14125     ml.position('absolute');
14126     ml.setLeftTop(-1000, -1000);
14127     ml.hide();
14128
14129     if(fixedWidth){
14130         ml.setWidth(fixedWidth);
14131     }
14132      
14133     var instance = {
14134         /**
14135          * Returns the size of the specified text based on the internal element's style and width properties
14136          * @memberOf Roo.util.TextMetrics.Instance#
14137          * @param {String} text The text to measure
14138          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14139          */
14140         getSize : function(text){
14141             ml.update(text);
14142             var s = ml.getSize();
14143             ml.update('');
14144             return s;
14145         },
14146
14147         /**
14148          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14149          * that can affect the size of the rendered text
14150          * @memberOf Roo.util.TextMetrics.Instance#
14151          * @param {String/HTMLElement} el The element, dom node or id
14152          */
14153         bind : function(el){
14154             ml.setStyle(
14155                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14156             );
14157         },
14158
14159         /**
14160          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14161          * to set a fixed width in order to accurately measure the text height.
14162          * @memberOf Roo.util.TextMetrics.Instance#
14163          * @param {Number} width The width to set on the element
14164          */
14165         setFixedWidth : function(width){
14166             ml.setWidth(width);
14167         },
14168
14169         /**
14170          * Returns the measured width of the specified text
14171          * @memberOf Roo.util.TextMetrics.Instance#
14172          * @param {String} text The text to measure
14173          * @return {Number} width The width in pixels
14174          */
14175         getWidth : function(text){
14176             ml.dom.style.width = 'auto';
14177             return this.getSize(text).width;
14178         },
14179
14180         /**
14181          * Returns the measured height of the specified text.  For multiline text, be sure to call
14182          * {@link #setFixedWidth} if necessary.
14183          * @memberOf Roo.util.TextMetrics.Instance#
14184          * @param {String} text The text to measure
14185          * @return {Number} height The height in pixels
14186          */
14187         getHeight : function(text){
14188             return this.getSize(text).height;
14189         }
14190     };
14191
14192     instance.bind(bindTo);
14193
14194     return instance;
14195 };
14196
14197 // backwards compat
14198 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14199  * Based on:
14200  * Ext JS Library 1.1.1
14201  * Copyright(c) 2006-2007, Ext JS, LLC.
14202  *
14203  * Originally Released Under LGPL - original licence link has changed is not relivant.
14204  *
14205  * Fork - LGPL
14206  * <script type="text/javascript">
14207  */
14208
14209 /**
14210  * @class Roo.state.Provider
14211  * Abstract base class for state provider implementations. This class provides methods
14212  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14213  * Provider interface.
14214  */
14215 Roo.state.Provider = function(){
14216     /**
14217      * @event statechange
14218      * Fires when a state change occurs.
14219      * @param {Provider} this This state provider
14220      * @param {String} key The state key which was changed
14221      * @param {String} value The encoded value for the state
14222      */
14223     this.addEvents({
14224         "statechange": true
14225     });
14226     this.state = {};
14227     Roo.state.Provider.superclass.constructor.call(this);
14228 };
14229 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14230     /**
14231      * Returns the current value for a key
14232      * @param {String} name The key name
14233      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14234      * @return {Mixed} The state data
14235      */
14236     get : function(name, defaultValue){
14237         return typeof this.state[name] == "undefined" ?
14238             defaultValue : this.state[name];
14239     },
14240     
14241     /**
14242      * Clears a value from the state
14243      * @param {String} name The key name
14244      */
14245     clear : function(name){
14246         delete this.state[name];
14247         this.fireEvent("statechange", this, name, null);
14248     },
14249     
14250     /**
14251      * Sets the value for a key
14252      * @param {String} name The key name
14253      * @param {Mixed} value The value to set
14254      */
14255     set : function(name, value){
14256         this.state[name] = value;
14257         this.fireEvent("statechange", this, name, value);
14258     },
14259     
14260     /**
14261      * Decodes a string previously encoded with {@link #encodeValue}.
14262      * @param {String} value The value to decode
14263      * @return {Mixed} The decoded value
14264      */
14265     decodeValue : function(cookie){
14266         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14267         var matches = re.exec(unescape(cookie));
14268         if(!matches || !matches[1]) return; // non state cookie
14269         var type = matches[1];
14270         var v = matches[2];
14271         switch(type){
14272             case "n":
14273                 return parseFloat(v);
14274             case "d":
14275                 return new Date(Date.parse(v));
14276             case "b":
14277                 return (v == "1");
14278             case "a":
14279                 var all = [];
14280                 var values = v.split("^");
14281                 for(var i = 0, len = values.length; i < len; i++){
14282                     all.push(this.decodeValue(values[i]));
14283                 }
14284                 return all;
14285            case "o":
14286                 var all = {};
14287                 var values = v.split("^");
14288                 for(var i = 0, len = values.length; i < len; i++){
14289                     var kv = values[i].split("=");
14290                     all[kv[0]] = this.decodeValue(kv[1]);
14291                 }
14292                 return all;
14293            default:
14294                 return v;
14295         }
14296     },
14297     
14298     /**
14299      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14300      * @param {Mixed} value The value to encode
14301      * @return {String} The encoded value
14302      */
14303     encodeValue : function(v){
14304         var enc;
14305         if(typeof v == "number"){
14306             enc = "n:" + v;
14307         }else if(typeof v == "boolean"){
14308             enc = "b:" + (v ? "1" : "0");
14309         }else if(v instanceof Date){
14310             enc = "d:" + v.toGMTString();
14311         }else if(v instanceof Array){
14312             var flat = "";
14313             for(var i = 0, len = v.length; i < len; i++){
14314                 flat += this.encodeValue(v[i]);
14315                 if(i != len-1) flat += "^";
14316             }
14317             enc = "a:" + flat;
14318         }else if(typeof v == "object"){
14319             var flat = "";
14320             for(var key in v){
14321                 if(typeof v[key] != "function"){
14322                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14323                 }
14324             }
14325             enc = "o:" + flat.substring(0, flat.length-1);
14326         }else{
14327             enc = "s:" + v;
14328         }
14329         return escape(enc);        
14330     }
14331 });
14332
14333 /*
14334  * Based on:
14335  * Ext JS Library 1.1.1
14336  * Copyright(c) 2006-2007, Ext JS, LLC.
14337  *
14338  * Originally Released Under LGPL - original licence link has changed is not relivant.
14339  *
14340  * Fork - LGPL
14341  * <script type="text/javascript">
14342  */
14343 /**
14344  * @class Roo.state.Manager
14345  * This is the global state manager. By default all components that are "state aware" check this class
14346  * for state information if you don't pass them a custom state provider. In order for this class
14347  * to be useful, it must be initialized with a provider when your application initializes.
14348  <pre><code>
14349 // in your initialization function
14350 init : function(){
14351    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14352    ...
14353    // supposed you have a {@link Roo.BorderLayout}
14354    var layout = new Roo.BorderLayout(...);
14355    layout.restoreState();
14356    // or a {Roo.BasicDialog}
14357    var dialog = new Roo.BasicDialog(...);
14358    dialog.restoreState();
14359  </code></pre>
14360  * @singleton
14361  */
14362 Roo.state.Manager = function(){
14363     var provider = new Roo.state.Provider();
14364     
14365     return {
14366         /**
14367          * Configures the default state provider for your application
14368          * @param {Provider} stateProvider The state provider to set
14369          */
14370         setProvider : function(stateProvider){
14371             provider = stateProvider;
14372         },
14373         
14374         /**
14375          * Returns the current value for a key
14376          * @param {String} name The key name
14377          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14378          * @return {Mixed} The state data
14379          */
14380         get : function(key, defaultValue){
14381             return provider.get(key, defaultValue);
14382         },
14383         
14384         /**
14385          * Sets the value for a key
14386          * @param {String} name The key name
14387          * @param {Mixed} value The state data
14388          */
14389          set : function(key, value){
14390             provider.set(key, value);
14391         },
14392         
14393         /**
14394          * Clears a value from the state
14395          * @param {String} name The key name
14396          */
14397         clear : function(key){
14398             provider.clear(key);
14399         },
14400         
14401         /**
14402          * Gets the currently configured state provider
14403          * @return {Provider} The state provider
14404          */
14405         getProvider : function(){
14406             return provider;
14407         }
14408     };
14409 }();
14410 /*
14411  * Based on:
14412  * Ext JS Library 1.1.1
14413  * Copyright(c) 2006-2007, Ext JS, LLC.
14414  *
14415  * Originally Released Under LGPL - original licence link has changed is not relivant.
14416  *
14417  * Fork - LGPL
14418  * <script type="text/javascript">
14419  */
14420 /**
14421  * @class Roo.state.CookieProvider
14422  * @extends Roo.state.Provider
14423  * The default Provider implementation which saves state via cookies.
14424  * <br />Usage:
14425  <pre><code>
14426    var cp = new Roo.state.CookieProvider({
14427        path: "/cgi-bin/",
14428        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14429        domain: "roojs.com"
14430    })
14431    Roo.state.Manager.setProvider(cp);
14432  </code></pre>
14433  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14434  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14435  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14436  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14437  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14438  * domain the page is running on including the 'www' like 'www.roojs.com')
14439  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14440  * @constructor
14441  * Create a new CookieProvider
14442  * @param {Object} config The configuration object
14443  */
14444 Roo.state.CookieProvider = function(config){
14445     Roo.state.CookieProvider.superclass.constructor.call(this);
14446     this.path = "/";
14447     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14448     this.domain = null;
14449     this.secure = false;
14450     Roo.apply(this, config);
14451     this.state = this.readCookies();
14452 };
14453
14454 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14455     // private
14456     set : function(name, value){
14457         if(typeof value == "undefined" || value === null){
14458             this.clear(name);
14459             return;
14460         }
14461         this.setCookie(name, value);
14462         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14463     },
14464
14465     // private
14466     clear : function(name){
14467         this.clearCookie(name);
14468         Roo.state.CookieProvider.superclass.clear.call(this, name);
14469     },
14470
14471     // private
14472     readCookies : function(){
14473         var cookies = {};
14474         var c = document.cookie + ";";
14475         var re = /\s?(.*?)=(.*?);/g;
14476         var matches;
14477         while((matches = re.exec(c)) != null){
14478             var name = matches[1];
14479             var value = matches[2];
14480             if(name && name.substring(0,3) == "ys-"){
14481                 cookies[name.substr(3)] = this.decodeValue(value);
14482             }
14483         }
14484         return cookies;
14485     },
14486
14487     // private
14488     setCookie : function(name, value){
14489         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14490            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14491            ((this.path == null) ? "" : ("; path=" + this.path)) +
14492            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14493            ((this.secure == true) ? "; secure" : "");
14494     },
14495
14496     // private
14497     clearCookie : function(name){
14498         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14499            ((this.path == null) ? "" : ("; path=" + this.path)) +
14500            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14501            ((this.secure == true) ? "; secure" : "");
14502     }
14503 });