Roo/Template.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: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
4534 * @constructor
4535 * @param {Object} cfg - Configuration object.
4536 */
4537 Roo.Template = function(cfg){
4538     // BC!
4539     if(cfg instanceof Array){
4540         cfg = cfg.join("");
4541     }else if(arguments.length > 1){
4542         cfg = Array.prototype.join.call(arguments, "");
4543     }
4544     
4545     
4546     if (typeof(cfg) == 'object') {
4547         Roo.apply(this,cfg)
4548     } else {
4549         // bc
4550         this.html = cfg;
4551     }
4552     
4553     
4554 };
4555 Roo.Template.prototype = {
4556     
4557     /**
4558      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4559      */
4560     html : '',
4561     /**
4562      * Returns an HTML fragment of this template with the specified values applied.
4563      * @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'})
4564      * @return {String} The HTML fragment
4565      */
4566     applyTemplate : function(values){
4567         try {
4568             
4569             if(this.compiled){
4570                 return this.compiled(values);
4571             }
4572             var useF = this.disableFormats !== true;
4573             var fm = Roo.util.Format, tpl = this;
4574             var fn = function(m, name, format, args){
4575                 if(format && useF){
4576                     if(format.substr(0, 5) == "this."){
4577                         return tpl.call(format.substr(5), values[name], values);
4578                     }else{
4579                         if(args){
4580                             // quoted values are required for strings in compiled templates, 
4581                             // but for non compiled we need to strip them
4582                             // quoted reversed for jsmin
4583                             var re = /^\s*['"](.*)["']\s*$/;
4584                             args = args.split(',');
4585                             for(var i = 0, len = args.length; i < len; i++){
4586                                 args[i] = args[i].replace(re, "$1");
4587                             }
4588                             args = [values[name]].concat(args);
4589                         }else{
4590                             args = [values[name]];
4591                         }
4592                         return fm[format].apply(fm, args);
4593                     }
4594                 }else{
4595                     return values[name] !== undefined ? values[name] : "";
4596                 }
4597             };
4598             return this.html.replace(this.re, fn);
4599         } catch (e) {
4600             Roo.log(e);
4601             throw e;
4602         }
4603          
4604     },
4605     
4606     /**
4607      * Sets the HTML used as the template and optionally compiles it.
4608      * @param {String} html
4609      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4610      * @return {Roo.Template} this
4611      */
4612     set : function(html, compile){
4613         this.html = html;
4614         this.compiled = null;
4615         if(compile){
4616             this.compile();
4617         }
4618         return this;
4619     },
4620     
4621     /**
4622      * True to disable format functions (defaults to false)
4623      * @type Boolean
4624      */
4625     disableFormats : false,
4626     
4627     /**
4628     * The regular expression used to match template variables 
4629     * @type RegExp
4630     * @property 
4631     */
4632     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4633     
4634     /**
4635      * Compiles the template into an internal function, eliminating the RegEx overhead.
4636      * @return {Roo.Template} this
4637      */
4638     compile : function(){
4639         var fm = Roo.util.Format;
4640         var useF = this.disableFormats !== true;
4641         var sep = Roo.isGecko ? "+" : ",";
4642         var fn = function(m, name, format, args){
4643             if(format && useF){
4644                 args = args ? ',' + args : "";
4645                 if(format.substr(0, 5) != "this."){
4646                     format = "fm." + format + '(';
4647                 }else{
4648                     format = 'this.call("'+ format.substr(5) + '", ';
4649                     args = ", values";
4650                 }
4651             }else{
4652                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4653             }
4654             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4655         };
4656         var body;
4657         // branched to use + in gecko and [].join() in others
4658         if(Roo.isGecko){
4659             body = "this.compiled = function(values){ return '" +
4660                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4661                     "';};";
4662         }else{
4663             body = ["this.compiled = function(values){ return ['"];
4664             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4665             body.push("'].join('');};");
4666             body = body.join('');
4667         }
4668         /**
4669          * eval:var:values
4670          * eval:var:fm
4671          */
4672         eval(body);
4673         return this;
4674     },
4675     
4676     // private function used to call members
4677     call : function(fnName, value, allValues){
4678         return this[fnName](value, allValues);
4679     },
4680     
4681     /**
4682      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4683      * @param {String/HTMLElement/Roo.Element} el The context element
4684      * @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'})
4685      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4686      * @return {HTMLElement/Roo.Element} The new node or Element
4687      */
4688     insertFirst: function(el, values, returnElement){
4689         return this.doInsert('afterBegin', el, values, returnElement);
4690     },
4691
4692     /**
4693      * Applies the supplied values to the template and inserts the new node(s) before el.
4694      * @param {String/HTMLElement/Roo.Element} el The context element
4695      * @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'})
4696      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4697      * @return {HTMLElement/Roo.Element} The new node or Element
4698      */
4699     insertBefore: function(el, values, returnElement){
4700         return this.doInsert('beforeBegin', el, values, returnElement);
4701     },
4702
4703     /**
4704      * Applies the supplied values to the template and inserts the new node(s) after el.
4705      * @param {String/HTMLElement/Roo.Element} el The context element
4706      * @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'})
4707      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4708      * @return {HTMLElement/Roo.Element} The new node or Element
4709      */
4710     insertAfter : function(el, values, returnElement){
4711         return this.doInsert('afterEnd', el, values, returnElement);
4712     },
4713     
4714     /**
4715      * Applies the supplied values to the template and appends the new node(s) to el.
4716      * @param {String/HTMLElement/Roo.Element} el The context element
4717      * @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'})
4718      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4719      * @return {HTMLElement/Roo.Element} The new node or Element
4720      */
4721     append : function(el, values, returnElement){
4722         return this.doInsert('beforeEnd', el, values, returnElement);
4723     },
4724
4725     doInsert : function(where, el, values, returnEl){
4726         el = Roo.getDom(el);
4727         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4728         return returnEl ? Roo.get(newNode, true) : newNode;
4729     },
4730
4731     /**
4732      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
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     overwrite : function(el, values, returnElement){
4739         el = Roo.getDom(el);
4740         el.innerHTML = this.applyTemplate(values);
4741         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4742     }
4743 };
4744 /**
4745  * Alias for {@link #applyTemplate}
4746  * @method
4747  */
4748 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4749
4750 // backwards compat
4751 Roo.DomHelper.Template = Roo.Template;
4752
4753 /**
4754  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4755  * @param {String/HTMLElement} el A DOM element or its id
4756  * @returns {Roo.Template} The created template
4757  * @static
4758  */
4759 Roo.Template.from = function(el){
4760     el = Roo.getDom(el);
4761     return new Roo.Template(el.value || el.innerHTML);
4762 };/*
4763  * Based on:
4764  * Ext JS Library 1.1.1
4765  * Copyright(c) 2006-2007, Ext JS, LLC.
4766  *
4767  * Originally Released Under LGPL - original licence link has changed is not relivant.
4768  *
4769  * Fork - LGPL
4770  * <script type="text/javascript">
4771  */
4772  
4773
4774 /*
4775  * This is code is also distributed under MIT license for use
4776  * with jQuery and prototype JavaScript libraries.
4777  */
4778 /**
4779  * @class Roo.DomQuery
4780 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).
4781 <p>
4782 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>
4783
4784 <p>
4785 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.
4786 </p>
4787 <h4>Element Selectors:</h4>
4788 <ul class="list">
4789     <li> <b>*</b> any element</li>
4790     <li> <b>E</b> an element with the tag E</li>
4791     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4792     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4793     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4794     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4795 </ul>
4796 <h4>Attribute Selectors:</h4>
4797 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4798 <ul class="list">
4799     <li> <b>E[foo]</b> has an attribute "foo"</li>
4800     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4801     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4802     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4803     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4804     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4805     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4806 </ul>
4807 <h4>Pseudo Classes:</h4>
4808 <ul class="list">
4809     <li> <b>E:first-child</b> E is the first child of its parent</li>
4810     <li> <b>E:last-child</b> E is the last child of its parent</li>
4811     <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>
4812     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4813     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4814     <li> <b>E:only-child</b> E is the only child of its parent</li>
4815     <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>
4816     <li> <b>E:first</b> the first E in the resultset</li>
4817     <li> <b>E:last</b> the last E in the resultset</li>
4818     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4819     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4820     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4821     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4822     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4823     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4824     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4825     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4826     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4827 </ul>
4828 <h4>CSS Value Selectors:</h4>
4829 <ul class="list">
4830     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4831     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4832     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4833     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4834     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4835     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4836 </ul>
4837  * @singleton
4838  */
4839 Roo.DomQuery = function(){
4840     var cache = {}, simpleCache = {}, valueCache = {};
4841     var nonSpace = /\S/;
4842     var trimRe = /^\s+|\s+$/g;
4843     var tplRe = /\{(\d+)\}/g;
4844     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4845     var tagTokenRe = /^(#)?([\w-\*]+)/;
4846     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4847
4848     function child(p, index){
4849         var i = 0;
4850         var n = p.firstChild;
4851         while(n){
4852             if(n.nodeType == 1){
4853                if(++i == index){
4854                    return n;
4855                }
4856             }
4857             n = n.nextSibling;
4858         }
4859         return null;
4860     };
4861
4862     function next(n){
4863         while((n = n.nextSibling) && n.nodeType != 1);
4864         return n;
4865     };
4866
4867     function prev(n){
4868         while((n = n.previousSibling) && n.nodeType != 1);
4869         return n;
4870     };
4871
4872     function children(d){
4873         var n = d.firstChild, ni = -1;
4874             while(n){
4875                 var nx = n.nextSibling;
4876                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4877                     d.removeChild(n);
4878                 }else{
4879                     n.nodeIndex = ++ni;
4880                 }
4881                 n = nx;
4882             }
4883             return this;
4884         };
4885
4886     function byClassName(c, a, v){
4887         if(!v){
4888             return c;
4889         }
4890         var r = [], ri = -1, cn;
4891         for(var i = 0, ci; ci = c[i]; i++){
4892             if((' '+ci.className+' ').indexOf(v) != -1){
4893                 r[++ri] = ci;
4894             }
4895         }
4896         return r;
4897     };
4898
4899     function attrValue(n, attr){
4900         if(!n.tagName && typeof n.length != "undefined"){
4901             n = n[0];
4902         }
4903         if(!n){
4904             return null;
4905         }
4906         if(attr == "for"){
4907             return n.htmlFor;
4908         }
4909         if(attr == "class" || attr == "className"){
4910             return n.className;
4911         }
4912         return n.getAttribute(attr) || n[attr];
4913
4914     };
4915
4916     function getNodes(ns, mode, tagName){
4917         var result = [], ri = -1, cs;
4918         if(!ns){
4919             return result;
4920         }
4921         tagName = tagName || "*";
4922         if(typeof ns.getElementsByTagName != "undefined"){
4923             ns = [ns];
4924         }
4925         if(!mode){
4926             for(var i = 0, ni; ni = ns[i]; i++){
4927                 cs = ni.getElementsByTagName(tagName);
4928                 for(var j = 0, ci; ci = cs[j]; j++){
4929                     result[++ri] = ci;
4930                 }
4931             }
4932         }else if(mode == "/" || mode == ">"){
4933             var utag = tagName.toUpperCase();
4934             for(var i = 0, ni, cn; ni = ns[i]; i++){
4935                 cn = ni.children || ni.childNodes;
4936                 for(var j = 0, cj; cj = cn[j]; j++){
4937                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4938                         result[++ri] = cj;
4939                     }
4940                 }
4941             }
4942         }else if(mode == "+"){
4943             var utag = tagName.toUpperCase();
4944             for(var i = 0, n; n = ns[i]; i++){
4945                 while((n = n.nextSibling) && n.nodeType != 1);
4946                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4947                     result[++ri] = n;
4948                 }
4949             }
4950         }else if(mode == "~"){
4951             for(var i = 0, n; n = ns[i]; i++){
4952                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4953                 if(n){
4954                     result[++ri] = n;
4955                 }
4956             }
4957         }
4958         return result;
4959     };
4960
4961     function concat(a, b){
4962         if(b.slice){
4963             return a.concat(b);
4964         }
4965         for(var i = 0, l = b.length; i < l; i++){
4966             a[a.length] = b[i];
4967         }
4968         return a;
4969     }
4970
4971     function byTag(cs, tagName){
4972         if(cs.tagName || cs == document){
4973             cs = [cs];
4974         }
4975         if(!tagName){
4976             return cs;
4977         }
4978         var r = [], ri = -1;
4979         tagName = tagName.toLowerCase();
4980         for(var i = 0, ci; ci = cs[i]; i++){
4981             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4982                 r[++ri] = ci;
4983             }
4984         }
4985         return r;
4986     };
4987
4988     function byId(cs, attr, id){
4989         if(cs.tagName || cs == document){
4990             cs = [cs];
4991         }
4992         if(!id){
4993             return cs;
4994         }
4995         var r = [], ri = -1;
4996         for(var i = 0,ci; ci = cs[i]; i++){
4997             if(ci && ci.id == id){
4998                 r[++ri] = ci;
4999                 return r;
5000             }
5001         }
5002         return r;
5003     };
5004
5005     function byAttribute(cs, attr, value, op, custom){
5006         var r = [], ri = -1, st = custom=="{";
5007         var f = Roo.DomQuery.operators[op];
5008         for(var i = 0, ci; ci = cs[i]; i++){
5009             var a;
5010             if(st){
5011                 a = Roo.DomQuery.getStyle(ci, attr);
5012             }
5013             else if(attr == "class" || attr == "className"){
5014                 a = ci.className;
5015             }else if(attr == "for"){
5016                 a = ci.htmlFor;
5017             }else if(attr == "href"){
5018                 a = ci.getAttribute("href", 2);
5019             }else{
5020                 a = ci.getAttribute(attr);
5021             }
5022             if((f && f(a, value)) || (!f && a)){
5023                 r[++ri] = ci;
5024             }
5025         }
5026         return r;
5027     };
5028
5029     function byPseudo(cs, name, value){
5030         return Roo.DomQuery.pseudos[name](cs, value);
5031     };
5032
5033     // This is for IE MSXML which does not support expandos.
5034     // IE runs the same speed using setAttribute, however FF slows way down
5035     // and Safari completely fails so they need to continue to use expandos.
5036     var isIE = window.ActiveXObject ? true : false;
5037
5038     // this eval is stop the compressor from
5039     // renaming the variable to something shorter
5040     
5041     /** eval:var:batch */
5042     var batch = 30803; 
5043
5044     var key = 30803;
5045
5046     function nodupIEXml(cs){
5047         var d = ++key;
5048         cs[0].setAttribute("_nodup", d);
5049         var r = [cs[0]];
5050         for(var i = 1, len = cs.length; i < len; i++){
5051             var c = cs[i];
5052             if(!c.getAttribute("_nodup") != d){
5053                 c.setAttribute("_nodup", d);
5054                 r[r.length] = c;
5055             }
5056         }
5057         for(var i = 0, len = cs.length; i < len; i++){
5058             cs[i].removeAttribute("_nodup");
5059         }
5060         return r;
5061     }
5062
5063     function nodup(cs){
5064         if(!cs){
5065             return [];
5066         }
5067         var len = cs.length, c, i, r = cs, cj, ri = -1;
5068         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5069             return cs;
5070         }
5071         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5072             return nodupIEXml(cs);
5073         }
5074         var d = ++key;
5075         cs[0]._nodup = d;
5076         for(i = 1; c = cs[i]; i++){
5077             if(c._nodup != d){
5078                 c._nodup = d;
5079             }else{
5080                 r = [];
5081                 for(var j = 0; j < i; j++){
5082                     r[++ri] = cs[j];
5083                 }
5084                 for(j = i+1; cj = cs[j]; j++){
5085                     if(cj._nodup != d){
5086                         cj._nodup = d;
5087                         r[++ri] = cj;
5088                     }
5089                 }
5090                 return r;
5091             }
5092         }
5093         return r;
5094     }
5095
5096     function quickDiffIEXml(c1, c2){
5097         var d = ++key;
5098         for(var i = 0, len = c1.length; i < len; i++){
5099             c1[i].setAttribute("_qdiff", d);
5100         }
5101         var r = [];
5102         for(var i = 0, len = c2.length; i < len; i++){
5103             if(c2[i].getAttribute("_qdiff") != d){
5104                 r[r.length] = c2[i];
5105             }
5106         }
5107         for(var i = 0, len = c1.length; i < len; i++){
5108            c1[i].removeAttribute("_qdiff");
5109         }
5110         return r;
5111     }
5112
5113     function quickDiff(c1, c2){
5114         var len1 = c1.length;
5115         if(!len1){
5116             return c2;
5117         }
5118         if(isIE && c1[0].selectSingleNode){
5119             return quickDiffIEXml(c1, c2);
5120         }
5121         var d = ++key;
5122         for(var i = 0; i < len1; i++){
5123             c1[i]._qdiff = d;
5124         }
5125         var r = [];
5126         for(var i = 0, len = c2.length; i < len; i++){
5127             if(c2[i]._qdiff != d){
5128                 r[r.length] = c2[i];
5129             }
5130         }
5131         return r;
5132     }
5133
5134     function quickId(ns, mode, root, id){
5135         if(ns == root){
5136            var d = root.ownerDocument || root;
5137            return d.getElementById(id);
5138         }
5139         ns = getNodes(ns, mode, "*");
5140         return byId(ns, null, id);
5141     }
5142
5143     return {
5144         getStyle : function(el, name){
5145             return Roo.fly(el).getStyle(name);
5146         },
5147         /**
5148          * Compiles a selector/xpath query into a reusable function. The returned function
5149          * takes one parameter "root" (optional), which is the context node from where the query should start.
5150          * @param {String} selector The selector/xpath query
5151          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5152          * @return {Function}
5153          */
5154         compile : function(path, type){
5155             type = type || "select";
5156             
5157             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5158             var q = path, mode, lq;
5159             var tk = Roo.DomQuery.matchers;
5160             var tklen = tk.length;
5161             var mm;
5162
5163             // accept leading mode switch
5164             var lmode = q.match(modeRe);
5165             if(lmode && lmode[1]){
5166                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5167                 q = q.replace(lmode[1], "");
5168             }
5169             // strip leading slashes
5170             while(path.substr(0, 1)=="/"){
5171                 path = path.substr(1);
5172             }
5173
5174             while(q && lq != q){
5175                 lq = q;
5176                 var tm = q.match(tagTokenRe);
5177                 if(type == "select"){
5178                     if(tm){
5179                         if(tm[1] == "#"){
5180                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5181                         }else{
5182                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5183                         }
5184                         q = q.replace(tm[0], "");
5185                     }else if(q.substr(0, 1) != '@'){
5186                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5187                     }
5188                 }else{
5189                     if(tm){
5190                         if(tm[1] == "#"){
5191                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5192                         }else{
5193                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5194                         }
5195                         q = q.replace(tm[0], "");
5196                     }
5197                 }
5198                 while(!(mm = q.match(modeRe))){
5199                     var matched = false;
5200                     for(var j = 0; j < tklen; j++){
5201                         var t = tk[j];
5202                         var m = q.match(t.re);
5203                         if(m){
5204                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5205                                                     return m[i];
5206                                                 });
5207                             q = q.replace(m[0], "");
5208                             matched = true;
5209                             break;
5210                         }
5211                     }
5212                     // prevent infinite loop on bad selector
5213                     if(!matched){
5214                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5215                     }
5216                 }
5217                 if(mm[1]){
5218                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5219                     q = q.replace(mm[1], "");
5220                 }
5221             }
5222             fn[fn.length] = "return nodup(n);\n}";
5223             
5224              /** 
5225               * list of variables that need from compression as they are used by eval.
5226              *  eval:var:batch 
5227              *  eval:var:nodup
5228              *  eval:var:byTag
5229              *  eval:var:ById
5230              *  eval:var:getNodes
5231              *  eval:var:quickId
5232              *  eval:var:mode
5233              *  eval:var:root
5234              *  eval:var:n
5235              *  eval:var:byClassName
5236              *  eval:var:byPseudo
5237              *  eval:var:byAttribute
5238              *  eval:var:attrValue
5239              * 
5240              **/ 
5241             eval(fn.join(""));
5242             return f;
5243         },
5244
5245         /**
5246          * Selects a group of elements.
5247          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5248          * @param {Node} root (optional) The start of the query (defaults to document).
5249          * @return {Array}
5250          */
5251         select : function(path, root, type){
5252             if(!root || root == document){
5253                 root = document;
5254             }
5255             if(typeof root == "string"){
5256                 root = document.getElementById(root);
5257             }
5258             var paths = path.split(",");
5259             var results = [];
5260             for(var i = 0, len = paths.length; i < len; i++){
5261                 var p = paths[i].replace(trimRe, "");
5262                 if(!cache[p]){
5263                     cache[p] = Roo.DomQuery.compile(p);
5264                     if(!cache[p]){
5265                         throw p + " is not a valid selector";
5266                     }
5267                 }
5268                 var result = cache[p](root);
5269                 if(result && result != document){
5270                     results = results.concat(result);
5271                 }
5272             }
5273             if(paths.length > 1){
5274                 return nodup(results);
5275             }
5276             return results;
5277         },
5278
5279         /**
5280          * Selects a single element.
5281          * @param {String} selector The selector/xpath query
5282          * @param {Node} root (optional) The start of the query (defaults to document).
5283          * @return {Element}
5284          */
5285         selectNode : function(path, root){
5286             return Roo.DomQuery.select(path, root)[0];
5287         },
5288
5289         /**
5290          * Selects the value of a node, optionally replacing null with the defaultValue.
5291          * @param {String} selector The selector/xpath query
5292          * @param {Node} root (optional) The start of the query (defaults to document).
5293          * @param {String} defaultValue
5294          */
5295         selectValue : function(path, root, defaultValue){
5296             path = path.replace(trimRe, "");
5297             if(!valueCache[path]){
5298                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5299             }
5300             var n = valueCache[path](root);
5301             n = n[0] ? n[0] : n;
5302             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5303             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5304         },
5305
5306         /**
5307          * Selects the value of a node, parsing integers and floats.
5308          * @param {String} selector The selector/xpath query
5309          * @param {Node} root (optional) The start of the query (defaults to document).
5310          * @param {Number} defaultValue
5311          * @return {Number}
5312          */
5313         selectNumber : function(path, root, defaultValue){
5314             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5315             return parseFloat(v);
5316         },
5317
5318         /**
5319          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5320          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5321          * @param {String} selector The simple selector to test
5322          * @return {Boolean}
5323          */
5324         is : function(el, ss){
5325             if(typeof el == "string"){
5326                 el = document.getElementById(el);
5327             }
5328             var isArray = (el instanceof Array);
5329             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5330             return isArray ? (result.length == el.length) : (result.length > 0);
5331         },
5332
5333         /**
5334          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5335          * @param {Array} el An array of elements to filter
5336          * @param {String} selector The simple selector to test
5337          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5338          * the selector instead of the ones that match
5339          * @return {Array}
5340          */
5341         filter : function(els, ss, nonMatches){
5342             ss = ss.replace(trimRe, "");
5343             if(!simpleCache[ss]){
5344                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5345             }
5346             var result = simpleCache[ss](els);
5347             return nonMatches ? quickDiff(result, els) : result;
5348         },
5349
5350         /**
5351          * Collection of matching regular expressions and code snippets.
5352          */
5353         matchers : [{
5354                 re: /^\.([\w-]+)/,
5355                 select: 'n = byClassName(n, null, " {1} ");'
5356             }, {
5357                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5358                 select: 'n = byPseudo(n, "{1}", "{2}");'
5359             },{
5360                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5361                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5362             }, {
5363                 re: /^#([\w-]+)/,
5364                 select: 'n = byId(n, null, "{1}");'
5365             },{
5366                 re: /^@([\w-]+)/,
5367                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5368             }
5369         ],
5370
5371         /**
5372          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5373          * 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;.
5374          */
5375         operators : {
5376             "=" : function(a, v){
5377                 return a == v;
5378             },
5379             "!=" : function(a, v){
5380                 return a != v;
5381             },
5382             "^=" : function(a, v){
5383                 return a && a.substr(0, v.length) == v;
5384             },
5385             "$=" : function(a, v){
5386                 return a && a.substr(a.length-v.length) == v;
5387             },
5388             "*=" : function(a, v){
5389                 return a && a.indexOf(v) !== -1;
5390             },
5391             "%=" : function(a, v){
5392                 return (a % v) == 0;
5393             },
5394             "|=" : function(a, v){
5395                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5396             },
5397             "~=" : function(a, v){
5398                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5399             }
5400         },
5401
5402         /**
5403          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5404          * and the argument (if any) supplied in the selector.
5405          */
5406         pseudos : {
5407             "first-child" : function(c){
5408                 var r = [], ri = -1, n;
5409                 for(var i = 0, ci; ci = n = c[i]; i++){
5410                     while((n = n.previousSibling) && n.nodeType != 1);
5411                     if(!n){
5412                         r[++ri] = ci;
5413                     }
5414                 }
5415                 return r;
5416             },
5417
5418             "last-child" : function(c){
5419                 var r = [], ri = -1, n;
5420                 for(var i = 0, ci; ci = n = c[i]; i++){
5421                     while((n = n.nextSibling) && n.nodeType != 1);
5422                     if(!n){
5423                         r[++ri] = ci;
5424                     }
5425                 }
5426                 return r;
5427             },
5428
5429             "nth-child" : function(c, a) {
5430                 var r = [], ri = -1;
5431                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5432                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5433                 for(var i = 0, n; n = c[i]; i++){
5434                     var pn = n.parentNode;
5435                     if (batch != pn._batch) {
5436                         var j = 0;
5437                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5438                             if(cn.nodeType == 1){
5439                                cn.nodeIndex = ++j;
5440                             }
5441                         }
5442                         pn._batch = batch;
5443                     }
5444                     if (f == 1) {
5445                         if (l == 0 || n.nodeIndex == l){
5446                             r[++ri] = n;
5447                         }
5448                     } else if ((n.nodeIndex + l) % f == 0){
5449                         r[++ri] = n;
5450                     }
5451                 }
5452
5453                 return r;
5454             },
5455
5456             "only-child" : function(c){
5457                 var r = [], ri = -1;;
5458                 for(var i = 0, ci; ci = c[i]; i++){
5459                     if(!prev(ci) && !next(ci)){
5460                         r[++ri] = ci;
5461                     }
5462                 }
5463                 return r;
5464             },
5465
5466             "empty" : function(c){
5467                 var r = [], ri = -1;
5468                 for(var i = 0, ci; ci = c[i]; i++){
5469                     var cns = ci.childNodes, j = 0, cn, empty = true;
5470                     while(cn = cns[j]){
5471                         ++j;
5472                         if(cn.nodeType == 1 || cn.nodeType == 3){
5473                             empty = false;
5474                             break;
5475                         }
5476                     }
5477                     if(empty){
5478                         r[++ri] = ci;
5479                     }
5480                 }
5481                 return r;
5482             },
5483
5484             "contains" : function(c, v){
5485                 var r = [], ri = -1;
5486                 for(var i = 0, ci; ci = c[i]; i++){
5487                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5488                         r[++ri] = ci;
5489                     }
5490                 }
5491                 return r;
5492             },
5493
5494             "nodeValue" : function(c, v){
5495                 var r = [], ri = -1;
5496                 for(var i = 0, ci; ci = c[i]; i++){
5497                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5498                         r[++ri] = ci;
5499                     }
5500                 }
5501                 return r;
5502             },
5503
5504             "checked" : function(c){
5505                 var r = [], ri = -1;
5506                 for(var i = 0, ci; ci = c[i]; i++){
5507                     if(ci.checked == true){
5508                         r[++ri] = ci;
5509                     }
5510                 }
5511                 return r;
5512             },
5513
5514             "not" : function(c, ss){
5515                 return Roo.DomQuery.filter(c, ss, true);
5516             },
5517
5518             "odd" : function(c){
5519                 return this["nth-child"](c, "odd");
5520             },
5521
5522             "even" : function(c){
5523                 return this["nth-child"](c, "even");
5524             },
5525
5526             "nth" : function(c, a){
5527                 return c[a-1] || [];
5528             },
5529
5530             "first" : function(c){
5531                 return c[0] || [];
5532             },
5533
5534             "last" : function(c){
5535                 return c[c.length-1] || [];
5536             },
5537
5538             "has" : function(c, ss){
5539                 var s = Roo.DomQuery.select;
5540                 var r = [], ri = -1;
5541                 for(var i = 0, ci; ci = c[i]; i++){
5542                     if(s(ss, ci).length > 0){
5543                         r[++ri] = ci;
5544                     }
5545                 }
5546                 return r;
5547             },
5548
5549             "next" : function(c, ss){
5550                 var is = Roo.DomQuery.is;
5551                 var r = [], ri = -1;
5552                 for(var i = 0, ci; ci = c[i]; i++){
5553                     var n = next(ci);
5554                     if(n && is(n, ss)){
5555                         r[++ri] = ci;
5556                     }
5557                 }
5558                 return r;
5559             },
5560
5561             "prev" : function(c, ss){
5562                 var is = Roo.DomQuery.is;
5563                 var r = [], ri = -1;
5564                 for(var i = 0, ci; ci = c[i]; i++){
5565                     var n = prev(ci);
5566                     if(n && is(n, ss)){
5567                         r[++ri] = ci;
5568                     }
5569                 }
5570                 return r;
5571             }
5572         }
5573     };
5574 }();
5575
5576 /**
5577  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5578  * @param {String} path The selector/xpath query
5579  * @param {Node} root (optional) The start of the query (defaults to document).
5580  * @return {Array}
5581  * @member Roo
5582  * @method query
5583  */
5584 Roo.query = Roo.DomQuery.select;
5585 /*
5586  * Based on:
5587  * Ext JS Library 1.1.1
5588  * Copyright(c) 2006-2007, Ext JS, LLC.
5589  *
5590  * Originally Released Under LGPL - original licence link has changed is not relivant.
5591  *
5592  * Fork - LGPL
5593  * <script type="text/javascript">
5594  */
5595
5596 /**
5597  * @class Roo.util.Observable
5598  * Base class that provides a common interface for publishing events. Subclasses are expected to
5599  * to have a property "events" with all the events defined.<br>
5600  * For example:
5601  * <pre><code>
5602  Employee = function(name){
5603     this.name = name;
5604     this.addEvents({
5605         "fired" : true,
5606         "quit" : true
5607     });
5608  }
5609  Roo.extend(Employee, Roo.util.Observable);
5610 </code></pre>
5611  * @param {Object} config properties to use (incuding events / listeners)
5612  */
5613
5614 Roo.util.Observable = function(cfg){
5615     
5616     cfg = cfg|| {};
5617     this.addEvents(cfg.events || {});
5618     if (cfg.events) {
5619         delete cfg.events; // make sure
5620     }
5621      
5622     Roo.apply(this, cfg);
5623     
5624     if(this.listeners){
5625         this.on(this.listeners);
5626         delete this.listeners;
5627     }
5628 };
5629 Roo.util.Observable.prototype = {
5630     /** 
5631  * @cfg {Object} listeners  list of events and functions to call for this object, 
5632  * For example :
5633  * <pre><code>
5634     listeners :  { 
5635        'click' : function(e) {
5636            ..... 
5637         } ,
5638         .... 
5639     } 
5640   </code></pre>
5641  */
5642     
5643     
5644     /**
5645      * Fires the specified event with the passed parameters (minus the event name).
5646      * @param {String} eventName
5647      * @param {Object...} args Variable number of parameters are passed to handlers
5648      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5649      */
5650     fireEvent : function(){
5651         var ce = this.events[arguments[0].toLowerCase()];
5652         if(typeof ce == "object"){
5653             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5654         }else{
5655             return true;
5656         }
5657     },
5658
5659     // private
5660     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5661
5662     /**
5663      * Appends an event handler to this component
5664      * @param {String}   eventName The type of event to listen for
5665      * @param {Function} handler The method the event invokes
5666      * @param {Object}   scope (optional) The scope in which to execute the handler
5667      * function. The handler function's "this" context.
5668      * @param {Object}   options (optional) An object containing handler configuration
5669      * properties. This may contain any of the following properties:<ul>
5670      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5671      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5672      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5673      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5674      * by the specified number of milliseconds. If the event fires again within that time, the original
5675      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5676      * </ul><br>
5677      * <p>
5678      * <b>Combining Options</b><br>
5679      * Using the options argument, it is possible to combine different types of listeners:<br>
5680      * <br>
5681      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5682                 <pre><code>
5683                 el.on('click', this.onClick, this, {
5684                         single: true,
5685                 delay: 100,
5686                 forumId: 4
5687                 });
5688                 </code></pre>
5689      * <p>
5690      * <b>Attaching multiple handlers in 1 call</b><br>
5691      * The method also allows for a single argument to be passed which is a config object containing properties
5692      * which specify multiple handlers.
5693      * <pre><code>
5694                 el.on({
5695                         'click': {
5696                         fn: this.onClick,
5697                         scope: this,
5698                         delay: 100
5699                 }, 
5700                 'mouseover': {
5701                         fn: this.onMouseOver,
5702                         scope: this
5703                 },
5704                 'mouseout': {
5705                         fn: this.onMouseOut,
5706                         scope: this
5707                 }
5708                 });
5709                 </code></pre>
5710      * <p>
5711      * Or a shorthand syntax which passes the same scope object to all handlers:
5712         <pre><code>
5713                 el.on({
5714                         'click': this.onClick,
5715                 'mouseover': this.onMouseOver,
5716                 'mouseout': this.onMouseOut,
5717                 scope: this
5718                 });
5719                 </code></pre>
5720      */
5721     addListener : function(eventName, fn, scope, o){
5722         if(typeof eventName == "object"){
5723             o = eventName;
5724             for(var e in o){
5725                 if(this.filterOptRe.test(e)){
5726                     continue;
5727                 }
5728                 if(typeof o[e] == "function"){
5729                     // shared options
5730                     this.addListener(e, o[e], o.scope,  o);
5731                 }else{
5732                     // individual options
5733                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5734                 }
5735             }
5736             return;
5737         }
5738         o = (!o || typeof o == "boolean") ? {} : o;
5739         eventName = eventName.toLowerCase();
5740         var ce = this.events[eventName] || true;
5741         if(typeof ce == "boolean"){
5742             ce = new Roo.util.Event(this, eventName);
5743             this.events[eventName] = ce;
5744         }
5745         ce.addListener(fn, scope, o);
5746     },
5747
5748     /**
5749      * Removes a listener
5750      * @param {String}   eventName     The type of event to listen for
5751      * @param {Function} handler        The handler to remove
5752      * @param {Object}   scope  (optional) The scope (this object) for the handler
5753      */
5754     removeListener : function(eventName, fn, scope){
5755         var ce = this.events[eventName.toLowerCase()];
5756         if(typeof ce == "object"){
5757             ce.removeListener(fn, scope);
5758         }
5759     },
5760
5761     /**
5762      * Removes all listeners for this object
5763      */
5764     purgeListeners : function(){
5765         for(var evt in this.events){
5766             if(typeof this.events[evt] == "object"){
5767                  this.events[evt].clearListeners();
5768             }
5769         }
5770     },
5771
5772     relayEvents : function(o, events){
5773         var createHandler = function(ename){
5774             return function(){
5775                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5776             };
5777         };
5778         for(var i = 0, len = events.length; i < len; i++){
5779             var ename = events[i];
5780             if(!this.events[ename]){ this.events[ename] = true; };
5781             o.on(ename, createHandler(ename), this);
5782         }
5783     },
5784
5785     /**
5786      * Used to define events on this Observable
5787      * @param {Object} object The object with the events defined
5788      */
5789     addEvents : function(o){
5790         if(!this.events){
5791             this.events = {};
5792         }
5793         Roo.applyIf(this.events, o);
5794     },
5795
5796     /**
5797      * Checks to see if this object has any listeners for a specified event
5798      * @param {String} eventName The name of the event to check for
5799      * @return {Boolean} True if the event is being listened for, else false
5800      */
5801     hasListener : function(eventName){
5802         var e = this.events[eventName];
5803         return typeof e == "object" && e.listeners.length > 0;
5804     }
5805 };
5806 /**
5807  * Appends an event handler to this element (shorthand for addListener)
5808  * @param {String}   eventName     The type of event to listen for
5809  * @param {Function} handler        The method the event invokes
5810  * @param {Object}   scope (optional) The scope in which to execute the handler
5811  * function. The handler function's "this" context.
5812  * @param {Object}   options  (optional)
5813  * @method
5814  */
5815 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5816 /**
5817  * Removes a listener (shorthand for removeListener)
5818  * @param {String}   eventName     The type of event to listen for
5819  * @param {Function} handler        The handler to remove
5820  * @param {Object}   scope  (optional) The scope (this object) for the handler
5821  * @method
5822  */
5823 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5824
5825 /**
5826  * Starts capture on the specified Observable. All events will be passed
5827  * to the supplied function with the event name + standard signature of the event
5828  * <b>before</b> the event is fired. If the supplied function returns false,
5829  * the event will not fire.
5830  * @param {Observable} o The Observable to capture
5831  * @param {Function} fn The function to call
5832  * @param {Object} scope (optional) The scope (this object) for the fn
5833  * @static
5834  */
5835 Roo.util.Observable.capture = function(o, fn, scope){
5836     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5837 };
5838
5839 /**
5840  * Removes <b>all</b> added captures from the Observable.
5841  * @param {Observable} o The Observable to release
5842  * @static
5843  */
5844 Roo.util.Observable.releaseCapture = function(o){
5845     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5846 };
5847
5848 (function(){
5849
5850     var createBuffered = function(h, o, scope){
5851         var task = new Roo.util.DelayedTask();
5852         return function(){
5853             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5854         };
5855     };
5856
5857     var createSingle = function(h, e, fn, scope){
5858         return function(){
5859             e.removeListener(fn, scope);
5860             return h.apply(scope, arguments);
5861         };
5862     };
5863
5864     var createDelayed = function(h, o, scope){
5865         return function(){
5866             var args = Array.prototype.slice.call(arguments, 0);
5867             setTimeout(function(){
5868                 h.apply(scope, args);
5869             }, o.delay || 10);
5870         };
5871     };
5872
5873     Roo.util.Event = function(obj, name){
5874         this.name = name;
5875         this.obj = obj;
5876         this.listeners = [];
5877     };
5878
5879     Roo.util.Event.prototype = {
5880         addListener : function(fn, scope, options){
5881             var o = options || {};
5882             scope = scope || this.obj;
5883             if(!this.isListening(fn, scope)){
5884                 var l = {fn: fn, scope: scope, options: o};
5885                 var h = fn;
5886                 if(o.delay){
5887                     h = createDelayed(h, o, scope);
5888                 }
5889                 if(o.single){
5890                     h = createSingle(h, this, fn, scope);
5891                 }
5892                 if(o.buffer){
5893                     h = createBuffered(h, o, scope);
5894                 }
5895                 l.fireFn = h;
5896                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5897                     this.listeners.push(l);
5898                 }else{
5899                     this.listeners = this.listeners.slice(0);
5900                     this.listeners.push(l);
5901                 }
5902             }
5903         },
5904
5905         findListener : function(fn, scope){
5906             scope = scope || this.obj;
5907             var ls = this.listeners;
5908             for(var i = 0, len = ls.length; i < len; i++){
5909                 var l = ls[i];
5910                 if(l.fn == fn && l.scope == scope){
5911                     return i;
5912                 }
5913             }
5914             return -1;
5915         },
5916
5917         isListening : function(fn, scope){
5918             return this.findListener(fn, scope) != -1;
5919         },
5920
5921         removeListener : function(fn, scope){
5922             var index;
5923             if((index = this.findListener(fn, scope)) != -1){
5924                 if(!this.firing){
5925                     this.listeners.splice(index, 1);
5926                 }else{
5927                     this.listeners = this.listeners.slice(0);
5928                     this.listeners.splice(index, 1);
5929                 }
5930                 return true;
5931             }
5932             return false;
5933         },
5934
5935         clearListeners : function(){
5936             this.listeners = [];
5937         },
5938
5939         fire : function(){
5940             var ls = this.listeners, scope, len = ls.length;
5941             if(len > 0){
5942                 this.firing = true;
5943                 var args = Array.prototype.slice.call(arguments, 0);
5944                 for(var i = 0; i < len; i++){
5945                     var l = ls[i];
5946                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5947                         this.firing = false;
5948                         return false;
5949                     }
5950                 }
5951                 this.firing = false;
5952             }
5953             return true;
5954         }
5955     };
5956 })();/*
5957  * Based on:
5958  * Ext JS Library 1.1.1
5959  * Copyright(c) 2006-2007, Ext JS, LLC.
5960  *
5961  * Originally Released Under LGPL - original licence link has changed is not relivant.
5962  *
5963  * Fork - LGPL
5964  * <script type="text/javascript">
5965  */
5966
5967 /**
5968  * @class Roo.EventManager
5969  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5970  * several useful events directly.
5971  * See {@link Roo.EventObject} for more details on normalized event objects.
5972  * @singleton
5973  */
5974 Roo.EventManager = function(){
5975     var docReadyEvent, docReadyProcId, docReadyState = false;
5976     var resizeEvent, resizeTask, textEvent, textSize;
5977     var E = Roo.lib.Event;
5978     var D = Roo.lib.Dom;
5979
5980
5981     var fireDocReady = function(){
5982         if(!docReadyState){
5983             docReadyState = true;
5984             Roo.isReady = true;
5985             if(docReadyProcId){
5986                 clearInterval(docReadyProcId);
5987             }
5988             if(Roo.isGecko || Roo.isOpera) {
5989                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5990             }
5991             if(Roo.isIE){
5992                 var defer = document.getElementById("ie-deferred-loader");
5993                 if(defer){
5994                     defer.onreadystatechange = null;
5995                     defer.parentNode.removeChild(defer);
5996                 }
5997             }
5998             if(docReadyEvent){
5999                 docReadyEvent.fire();
6000                 docReadyEvent.clearListeners();
6001             }
6002         }
6003     };
6004     
6005     var initDocReady = function(){
6006         docReadyEvent = new Roo.util.Event();
6007         if(Roo.isGecko || Roo.isOpera) {
6008             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6009         }else if(Roo.isIE){
6010             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6011             var defer = document.getElementById("ie-deferred-loader");
6012             defer.onreadystatechange = function(){
6013                 if(this.readyState == "complete"){
6014                     fireDocReady();
6015                 }
6016             };
6017         }else if(Roo.isSafari){ 
6018             docReadyProcId = setInterval(function(){
6019                 var rs = document.readyState;
6020                 if(rs == "complete") {
6021                     fireDocReady();     
6022                  }
6023             }, 10);
6024         }
6025         // no matter what, make sure it fires on load
6026         E.on(window, "load", fireDocReady);
6027     };
6028
6029     var createBuffered = function(h, o){
6030         var task = new Roo.util.DelayedTask(h);
6031         return function(e){
6032             // create new event object impl so new events don't wipe out properties
6033             e = new Roo.EventObjectImpl(e);
6034             task.delay(o.buffer, h, null, [e]);
6035         };
6036     };
6037
6038     var createSingle = function(h, el, ename, fn){
6039         return function(e){
6040             Roo.EventManager.removeListener(el, ename, fn);
6041             h(e);
6042         };
6043     };
6044
6045     var createDelayed = function(h, o){
6046         return function(e){
6047             // create new event object impl so new events don't wipe out properties
6048             e = new Roo.EventObjectImpl(e);
6049             setTimeout(function(){
6050                 h(e);
6051             }, o.delay || 10);
6052         };
6053     };
6054
6055     var listen = function(element, ename, opt, fn, scope){
6056         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6057         fn = fn || o.fn; scope = scope || o.scope;
6058         var el = Roo.getDom(element);
6059         if(!el){
6060             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6061         }
6062         var h = function(e){
6063             e = Roo.EventObject.setEvent(e);
6064             var t;
6065             if(o.delegate){
6066                 t = e.getTarget(o.delegate, el);
6067                 if(!t){
6068                     return;
6069                 }
6070             }else{
6071                 t = e.target;
6072             }
6073             if(o.stopEvent === true){
6074                 e.stopEvent();
6075             }
6076             if(o.preventDefault === true){
6077                e.preventDefault();
6078             }
6079             if(o.stopPropagation === true){
6080                 e.stopPropagation();
6081             }
6082
6083             if(o.normalized === false){
6084                 e = e.browserEvent;
6085             }
6086
6087             fn.call(scope || el, e, t, o);
6088         };
6089         if(o.delay){
6090             h = createDelayed(h, o);
6091         }
6092         if(o.single){
6093             h = createSingle(h, el, ename, fn);
6094         }
6095         if(o.buffer){
6096             h = createBuffered(h, o);
6097         }
6098         fn._handlers = fn._handlers || [];
6099         fn._handlers.push([Roo.id(el), ename, h]);
6100
6101         E.on(el, ename, h);
6102         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6103             el.addEventListener("DOMMouseScroll", h, false);
6104             E.on(window, 'unload', function(){
6105                 el.removeEventListener("DOMMouseScroll", h, false);
6106             });
6107         }
6108         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6109             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6110         }
6111         return h;
6112     };
6113
6114     var stopListening = function(el, ename, fn){
6115         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6116         if(hds){
6117             for(var i = 0, len = hds.length; i < len; i++){
6118                 var h = hds[i];
6119                 if(h[0] == id && h[1] == ename){
6120                     hd = h[2];
6121                     hds.splice(i, 1);
6122                     break;
6123                 }
6124             }
6125         }
6126         E.un(el, ename, hd);
6127         el = Roo.getDom(el);
6128         if(ename == "mousewheel" && el.addEventListener){
6129             el.removeEventListener("DOMMouseScroll", hd, false);
6130         }
6131         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6132             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6133         }
6134     };
6135
6136     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6137     
6138     var pub = {
6139         
6140         
6141         /** 
6142          * Fix for doc tools
6143          * @scope Roo.EventManager
6144          */
6145         
6146         
6147         /** 
6148          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6149          * object with a Roo.EventObject
6150          * @param {Function} fn        The method the event invokes
6151          * @param {Object}   scope    An object that becomes the scope of the handler
6152          * @param {boolean}  override If true, the obj passed in becomes
6153          *                             the execution scope of the listener
6154          * @return {Function} The wrapped function
6155          * @deprecated
6156          */
6157         wrap : function(fn, scope, override){
6158             return function(e){
6159                 Roo.EventObject.setEvent(e);
6160                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6161             };
6162         },
6163         
6164         /**
6165      * Appends an event handler to an element (shorthand for addListener)
6166      * @param {String/HTMLElement}   element        The html element or id to assign the
6167      * @param {String}   eventName The type of event to listen for
6168      * @param {Function} handler The method the event invokes
6169      * @param {Object}   scope (optional) The scope in which to execute the handler
6170      * function. The handler function's "this" context.
6171      * @param {Object}   options (optional) An object containing handler configuration
6172      * properties. This may contain any of the following properties:<ul>
6173      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6174      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6175      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6176      * <li>preventDefault {Boolean} True to prevent the default action</li>
6177      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6178      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6179      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6180      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6181      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6182      * by the specified number of milliseconds. If the event fires again within that time, the original
6183      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6184      * </ul><br>
6185      * <p>
6186      * <b>Combining Options</b><br>
6187      * Using the options argument, it is possible to combine different types of listeners:<br>
6188      * <br>
6189      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6190      * Code:<pre><code>
6191 el.on('click', this.onClick, this, {
6192     single: true,
6193     delay: 100,
6194     stopEvent : true,
6195     forumId: 4
6196 });</code></pre>
6197      * <p>
6198      * <b>Attaching multiple handlers in 1 call</b><br>
6199       * The method also allows for a single argument to be passed which is a config object containing properties
6200      * which specify multiple handlers.
6201      * <p>
6202      * Code:<pre><code>
6203 el.on({
6204     'click' : {
6205         fn: this.onClick
6206         scope: this,
6207         delay: 100
6208     },
6209     'mouseover' : {
6210         fn: this.onMouseOver
6211         scope: this
6212     },
6213     'mouseout' : {
6214         fn: this.onMouseOut
6215         scope: this
6216     }
6217 });</code></pre>
6218      * <p>
6219      * Or a shorthand syntax:<br>
6220      * Code:<pre><code>
6221 el.on({
6222     'click' : this.onClick,
6223     'mouseover' : this.onMouseOver,
6224     'mouseout' : this.onMouseOut
6225     scope: this
6226 });</code></pre>
6227      */
6228         addListener : function(element, eventName, fn, scope, options){
6229             if(typeof eventName == "object"){
6230                 var o = eventName;
6231                 for(var e in o){
6232                     if(propRe.test(e)){
6233                         continue;
6234                     }
6235                     if(typeof o[e] == "function"){
6236                         // shared options
6237                         listen(element, e, o, o[e], o.scope);
6238                     }else{
6239                         // individual options
6240                         listen(element, e, o[e]);
6241                     }
6242                 }
6243                 return;
6244             }
6245             return listen(element, eventName, options, fn, scope);
6246         },
6247         
6248         /**
6249          * Removes an event handler
6250          *
6251          * @param {String/HTMLElement}   element        The id or html element to remove the 
6252          *                             event from
6253          * @param {String}   eventName     The type of event
6254          * @param {Function} fn
6255          * @return {Boolean} True if a listener was actually removed
6256          */
6257         removeListener : function(element, eventName, fn){
6258             return stopListening(element, eventName, fn);
6259         },
6260         
6261         /**
6262          * Fires when the document is ready (before onload and before images are loaded). Can be 
6263          * accessed shorthanded Roo.onReady().
6264          * @param {Function} fn        The method the event invokes
6265          * @param {Object}   scope    An  object that becomes the scope of the handler
6266          * @param {boolean}  options
6267          */
6268         onDocumentReady : function(fn, scope, options){
6269             if(docReadyState){ // if it already fired
6270                 docReadyEvent.addListener(fn, scope, options);
6271                 docReadyEvent.fire();
6272                 docReadyEvent.clearListeners();
6273                 return;
6274             }
6275             if(!docReadyEvent){
6276                 initDocReady();
6277             }
6278             docReadyEvent.addListener(fn, scope, options);
6279         },
6280         
6281         /**
6282          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6283          * @param {Function} fn        The method the event invokes
6284          * @param {Object}   scope    An object that becomes the scope of the handler
6285          * @param {boolean}  options
6286          */
6287         onWindowResize : function(fn, scope, options){
6288             if(!resizeEvent){
6289                 resizeEvent = new Roo.util.Event();
6290                 resizeTask = new Roo.util.DelayedTask(function(){
6291                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6292                 });
6293                 E.on(window, "resize", function(){
6294                     if(Roo.isIE){
6295                         resizeTask.delay(50);
6296                     }else{
6297                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6298                     }
6299                 });
6300             }
6301             resizeEvent.addListener(fn, scope, options);
6302         },
6303
6304         /**
6305          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6306          * @param {Function} fn        The method the event invokes
6307          * @param {Object}   scope    An object that becomes the scope of the handler
6308          * @param {boolean}  options
6309          */
6310         onTextResize : function(fn, scope, options){
6311             if(!textEvent){
6312                 textEvent = new Roo.util.Event();
6313                 var textEl = new Roo.Element(document.createElement('div'));
6314                 textEl.dom.className = 'x-text-resize';
6315                 textEl.dom.innerHTML = 'X';
6316                 textEl.appendTo(document.body);
6317                 textSize = textEl.dom.offsetHeight;
6318                 setInterval(function(){
6319                     if(textEl.dom.offsetHeight != textSize){
6320                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6321                     }
6322                 }, this.textResizeInterval);
6323             }
6324             textEvent.addListener(fn, scope, options);
6325         },
6326
6327         /**
6328          * Removes the passed window resize listener.
6329          * @param {Function} fn        The method the event invokes
6330          * @param {Object}   scope    The scope of handler
6331          */
6332         removeResizeListener : function(fn, scope){
6333             if(resizeEvent){
6334                 resizeEvent.removeListener(fn, scope);
6335             }
6336         },
6337
6338         // private
6339         fireResize : function(){
6340             if(resizeEvent){
6341                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6342             }   
6343         },
6344         /**
6345          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6346          */
6347         ieDeferSrc : false,
6348         /**
6349          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6350          */
6351         textResizeInterval : 50
6352     };
6353     
6354     /**
6355      * Fix for doc tools
6356      * @scopeAlias pub=Roo.EventManager
6357      */
6358     
6359      /**
6360      * Appends an event handler to an element (shorthand for addListener)
6361      * @param {String/HTMLElement}   element        The html element or id to assign the
6362      * @param {String}   eventName The type of event to listen for
6363      * @param {Function} handler The method the event invokes
6364      * @param {Object}   scope (optional) The scope in which to execute the handler
6365      * function. The handler function's "this" context.
6366      * @param {Object}   options (optional) An object containing handler configuration
6367      * properties. This may contain any of the following properties:<ul>
6368      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6369      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6370      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6371      * <li>preventDefault {Boolean} True to prevent the default action</li>
6372      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6373      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6374      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6375      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6376      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6377      * by the specified number of milliseconds. If the event fires again within that time, the original
6378      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6379      * </ul><br>
6380      * <p>
6381      * <b>Combining Options</b><br>
6382      * Using the options argument, it is possible to combine different types of listeners:<br>
6383      * <br>
6384      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6385      * Code:<pre><code>
6386 el.on('click', this.onClick, this, {
6387     single: true,
6388     delay: 100,
6389     stopEvent : true,
6390     forumId: 4
6391 });</code></pre>
6392      * <p>
6393      * <b>Attaching multiple handlers in 1 call</b><br>
6394       * The method also allows for a single argument to be passed which is a config object containing properties
6395      * which specify multiple handlers.
6396      * <p>
6397      * Code:<pre><code>
6398 el.on({
6399     'click' : {
6400         fn: this.onClick
6401         scope: this,
6402         delay: 100
6403     },
6404     'mouseover' : {
6405         fn: this.onMouseOver
6406         scope: this
6407     },
6408     'mouseout' : {
6409         fn: this.onMouseOut
6410         scope: this
6411     }
6412 });</code></pre>
6413      * <p>
6414      * Or a shorthand syntax:<br>
6415      * Code:<pre><code>
6416 el.on({
6417     'click' : this.onClick,
6418     'mouseover' : this.onMouseOver,
6419     'mouseout' : this.onMouseOut
6420     scope: this
6421 });</code></pre>
6422      */
6423     pub.on = pub.addListener;
6424     pub.un = pub.removeListener;
6425
6426     pub.stoppedMouseDownEvent = new Roo.util.Event();
6427     return pub;
6428 }();
6429 /**
6430   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6431   * @param {Function} fn        The method the event invokes
6432   * @param {Object}   scope    An  object that becomes the scope of the handler
6433   * @param {boolean}  override If true, the obj passed in becomes
6434   *                             the execution scope of the listener
6435   * @member Roo
6436   * @method onReady
6437  */
6438 Roo.onReady = Roo.EventManager.onDocumentReady;
6439
6440 Roo.onReady(function(){
6441     var bd = Roo.get(document.body);
6442     if(!bd){ return; }
6443
6444     var cls = [
6445             Roo.isIE ? "roo-ie"
6446             : Roo.isGecko ? "roo-gecko"
6447             : Roo.isOpera ? "roo-opera"
6448             : Roo.isSafari ? "roo-safari" : ""];
6449
6450     if(Roo.isMac){
6451         cls.push("roo-mac");
6452     }
6453     if(Roo.isLinux){
6454         cls.push("roo-linux");
6455     }
6456     if(Roo.isBorderBox){
6457         cls.push('roo-border-box');
6458     }
6459     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6460         var p = bd.dom.parentNode;
6461         if(p){
6462             p.className += ' roo-strict';
6463         }
6464     }
6465     bd.addClass(cls.join(' '));
6466 });
6467
6468 /**
6469  * @class Roo.EventObject
6470  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6471  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6472  * Example:
6473  * <pre><code>
6474  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6475     e.preventDefault();
6476     var target = e.getTarget();
6477     ...
6478  }
6479  var myDiv = Roo.get("myDiv");
6480  myDiv.on("click", handleClick);
6481  //or
6482  Roo.EventManager.on("myDiv", 'click', handleClick);
6483  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6484  </code></pre>
6485  * @singleton
6486  */
6487 Roo.EventObject = function(){
6488     
6489     var E = Roo.lib.Event;
6490     
6491     // safari keypress events for special keys return bad keycodes
6492     var safariKeys = {
6493         63234 : 37, // left
6494         63235 : 39, // right
6495         63232 : 38, // up
6496         63233 : 40, // down
6497         63276 : 33, // page up
6498         63277 : 34, // page down
6499         63272 : 46, // delete
6500         63273 : 36, // home
6501         63275 : 35  // end
6502     };
6503
6504     // normalize button clicks
6505     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6506                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6507
6508     Roo.EventObjectImpl = function(e){
6509         if(e){
6510             this.setEvent(e.browserEvent || e);
6511         }
6512     };
6513     Roo.EventObjectImpl.prototype = {
6514         /**
6515          * Used to fix doc tools.
6516          * @scope Roo.EventObject.prototype
6517          */
6518             
6519
6520         
6521         
6522         /** The normal browser event */
6523         browserEvent : null,
6524         /** The button pressed in a mouse event */
6525         button : -1,
6526         /** True if the shift key was down during the event */
6527         shiftKey : false,
6528         /** True if the control key was down during the event */
6529         ctrlKey : false,
6530         /** True if the alt key was down during the event */
6531         altKey : false,
6532
6533         /** Key constant 
6534         * @type Number */
6535         BACKSPACE : 8,
6536         /** Key constant 
6537         * @type Number */
6538         TAB : 9,
6539         /** Key constant 
6540         * @type Number */
6541         RETURN : 13,
6542         /** Key constant 
6543         * @type Number */
6544         ENTER : 13,
6545         /** Key constant 
6546         * @type Number */
6547         SHIFT : 16,
6548         /** Key constant 
6549         * @type Number */
6550         CONTROL : 17,
6551         /** Key constant 
6552         * @type Number */
6553         ESC : 27,
6554         /** Key constant 
6555         * @type Number */
6556         SPACE : 32,
6557         /** Key constant 
6558         * @type Number */
6559         PAGEUP : 33,
6560         /** Key constant 
6561         * @type Number */
6562         PAGEDOWN : 34,
6563         /** Key constant 
6564         * @type Number */
6565         END : 35,
6566         /** Key constant 
6567         * @type Number */
6568         HOME : 36,
6569         /** Key constant 
6570         * @type Number */
6571         LEFT : 37,
6572         /** Key constant 
6573         * @type Number */
6574         UP : 38,
6575         /** Key constant 
6576         * @type Number */
6577         RIGHT : 39,
6578         /** Key constant 
6579         * @type Number */
6580         DOWN : 40,
6581         /** Key constant 
6582         * @type Number */
6583         DELETE : 46,
6584         /** Key constant 
6585         * @type Number */
6586         F5 : 116,
6587
6588            /** @private */
6589         setEvent : function(e){
6590             if(e == this || (e && e.browserEvent)){ // already wrapped
6591                 return e;
6592             }
6593             this.browserEvent = e;
6594             if(e){
6595                 // normalize buttons
6596                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6597                 if(e.type == 'click' && this.button == -1){
6598                     this.button = 0;
6599                 }
6600                 this.type = e.type;
6601                 this.shiftKey = e.shiftKey;
6602                 // mac metaKey behaves like ctrlKey
6603                 this.ctrlKey = e.ctrlKey || e.metaKey;
6604                 this.altKey = e.altKey;
6605                 // in getKey these will be normalized for the mac
6606                 this.keyCode = e.keyCode;
6607                 // keyup warnings on firefox.
6608                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6609                 // cache the target for the delayed and or buffered events
6610                 this.target = E.getTarget(e);
6611                 // same for XY
6612                 this.xy = E.getXY(e);
6613             }else{
6614                 this.button = -1;
6615                 this.shiftKey = false;
6616                 this.ctrlKey = false;
6617                 this.altKey = false;
6618                 this.keyCode = 0;
6619                 this.charCode =0;
6620                 this.target = null;
6621                 this.xy = [0, 0];
6622             }
6623             return this;
6624         },
6625
6626         /**
6627          * Stop the event (preventDefault and stopPropagation)
6628          */
6629         stopEvent : function(){
6630             if(this.browserEvent){
6631                 if(this.browserEvent.type == 'mousedown'){
6632                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6633                 }
6634                 E.stopEvent(this.browserEvent);
6635             }
6636         },
6637
6638         /**
6639          * Prevents the browsers default handling of the event.
6640          */
6641         preventDefault : function(){
6642             if(this.browserEvent){
6643                 E.preventDefault(this.browserEvent);
6644             }
6645         },
6646
6647         /** @private */
6648         isNavKeyPress : function(){
6649             var k = this.keyCode;
6650             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6651             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6652         },
6653
6654         isSpecialKey : function(){
6655             var k = this.keyCode;
6656             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6657             (k == 16) || (k == 17) ||
6658             (k >= 18 && k <= 20) ||
6659             (k >= 33 && k <= 35) ||
6660             (k >= 36 && k <= 39) ||
6661             (k >= 44 && k <= 45);
6662         },
6663         /**
6664          * Cancels bubbling of the event.
6665          */
6666         stopPropagation : function(){
6667             if(this.browserEvent){
6668                 if(this.type == 'mousedown'){
6669                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6670                 }
6671                 E.stopPropagation(this.browserEvent);
6672             }
6673         },
6674
6675         /**
6676          * Gets the key code for the event.
6677          * @return {Number}
6678          */
6679         getCharCode : function(){
6680             return this.charCode || this.keyCode;
6681         },
6682
6683         /**
6684          * Returns a normalized keyCode for the event.
6685          * @return {Number} The key code
6686          */
6687         getKey : function(){
6688             var k = this.keyCode || this.charCode;
6689             return Roo.isSafari ? (safariKeys[k] || k) : k;
6690         },
6691
6692         /**
6693          * Gets the x coordinate of the event.
6694          * @return {Number}
6695          */
6696         getPageX : function(){
6697             return this.xy[0];
6698         },
6699
6700         /**
6701          * Gets the y coordinate of the event.
6702          * @return {Number}
6703          */
6704         getPageY : function(){
6705             return this.xy[1];
6706         },
6707
6708         /**
6709          * Gets the time of the event.
6710          * @return {Number}
6711          */
6712         getTime : function(){
6713             if(this.browserEvent){
6714                 return E.getTime(this.browserEvent);
6715             }
6716             return null;
6717         },
6718
6719         /**
6720          * Gets the page coordinates of the event.
6721          * @return {Array} The xy values like [x, y]
6722          */
6723         getXY : function(){
6724             return this.xy;
6725         },
6726
6727         /**
6728          * Gets the target for the event.
6729          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6730          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6731                 search as a number or element (defaults to 10 || document.body)
6732          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6733          * @return {HTMLelement}
6734          */
6735         getTarget : function(selector, maxDepth, returnEl){
6736             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6737         },
6738         /**
6739          * Gets the related target.
6740          * @return {HTMLElement}
6741          */
6742         getRelatedTarget : function(){
6743             if(this.browserEvent){
6744                 return E.getRelatedTarget(this.browserEvent);
6745             }
6746             return null;
6747         },
6748
6749         /**
6750          * Normalizes mouse wheel delta across browsers
6751          * @return {Number} The delta
6752          */
6753         getWheelDelta : function(){
6754             var e = this.browserEvent;
6755             var delta = 0;
6756             if(e.wheelDelta){ /* IE/Opera. */
6757                 delta = e.wheelDelta/120;
6758             }else if(e.detail){ /* Mozilla case. */
6759                 delta = -e.detail/3;
6760             }
6761             return delta;
6762         },
6763
6764         /**
6765          * Returns true if the control, meta, shift or alt key was pressed during this event.
6766          * @return {Boolean}
6767          */
6768         hasModifier : function(){
6769             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6770         },
6771
6772         /**
6773          * Returns true if the target of this event equals el or is a child of el
6774          * @param {String/HTMLElement/Element} el
6775          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6776          * @return {Boolean}
6777          */
6778         within : function(el, related){
6779             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6780             return t && Roo.fly(el).contains(t);
6781         },
6782
6783         getPoint : function(){
6784             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6785         }
6786     };
6787
6788     return new Roo.EventObjectImpl();
6789 }();
6790             
6791     /*
6792  * Based on:
6793  * Ext JS Library 1.1.1
6794  * Copyright(c) 2006-2007, Ext JS, LLC.
6795  *
6796  * Originally Released Under LGPL - original licence link has changed is not relivant.
6797  *
6798  * Fork - LGPL
6799  * <script type="text/javascript">
6800  */
6801
6802  
6803 // was in Composite Element!??!?!
6804  
6805 (function(){
6806     var D = Roo.lib.Dom;
6807     var E = Roo.lib.Event;
6808     var A = Roo.lib.Anim;
6809
6810     // local style camelizing for speed
6811     var propCache = {};
6812     var camelRe = /(-[a-z])/gi;
6813     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6814     var view = document.defaultView;
6815
6816 /**
6817  * @class Roo.Element
6818  * Represents an Element in the DOM.<br><br>
6819  * Usage:<br>
6820 <pre><code>
6821 var el = Roo.get("my-div");
6822
6823 // or with getEl
6824 var el = getEl("my-div");
6825
6826 // or with a DOM element
6827 var el = Roo.get(myDivElement);
6828 </code></pre>
6829  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6830  * each call instead of constructing a new one.<br><br>
6831  * <b>Animations</b><br />
6832  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6833  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6834 <pre>
6835 Option    Default   Description
6836 --------- --------  ---------------------------------------------
6837 duration  .35       The duration of the animation in seconds
6838 easing    easeOut   The YUI easing method
6839 callback  none      A function to execute when the anim completes
6840 scope     this      The scope (this) of the callback function
6841 </pre>
6842 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6843 * manipulate the animation. Here's an example:
6844 <pre><code>
6845 var el = Roo.get("my-div");
6846
6847 // no animation
6848 el.setWidth(100);
6849
6850 // default animation
6851 el.setWidth(100, true);
6852
6853 // animation with some options set
6854 el.setWidth(100, {
6855     duration: 1,
6856     callback: this.foo,
6857     scope: this
6858 });
6859
6860 // using the "anim" property to get the Anim object
6861 var opt = {
6862     duration: 1,
6863     callback: this.foo,
6864     scope: this
6865 };
6866 el.setWidth(100, opt);
6867 ...
6868 if(opt.anim.isAnimated()){
6869     opt.anim.stop();
6870 }
6871 </code></pre>
6872 * <b> Composite (Collections of) Elements</b><br />
6873  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6874  * @constructor Create a new Element directly.
6875  * @param {String/HTMLElement} element
6876  * @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).
6877  */
6878     Roo.Element = function(element, forceNew){
6879         var dom = typeof element == "string" ?
6880                 document.getElementById(element) : element;
6881         if(!dom){ // invalid id/element
6882             return null;
6883         }
6884         var id = dom.id;
6885         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6886             return Roo.Element.cache[id];
6887         }
6888
6889         /**
6890          * The DOM element
6891          * @type HTMLElement
6892          */
6893         this.dom = dom;
6894
6895         /**
6896          * The DOM element ID
6897          * @type String
6898          */
6899         this.id = id || Roo.id(dom);
6900     };
6901
6902     var El = Roo.Element;
6903
6904     El.prototype = {
6905         /**
6906          * The element's default display mode  (defaults to "")
6907          * @type String
6908          */
6909         originalDisplay : "",
6910
6911         visibilityMode : 1,
6912         /**
6913          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6914          * @type String
6915          */
6916         defaultUnit : "px",
6917         /**
6918          * Sets the element's visibility mode. When setVisible() is called it
6919          * will use this to determine whether to set the visibility or the display property.
6920          * @param visMode Element.VISIBILITY or Element.DISPLAY
6921          * @return {Roo.Element} this
6922          */
6923         setVisibilityMode : function(visMode){
6924             this.visibilityMode = visMode;
6925             return this;
6926         },
6927         /**
6928          * Convenience method for setVisibilityMode(Element.DISPLAY)
6929          * @param {String} display (optional) What to set display to when visible
6930          * @return {Roo.Element} this
6931          */
6932         enableDisplayMode : function(display){
6933             this.setVisibilityMode(El.DISPLAY);
6934             if(typeof display != "undefined") this.originalDisplay = display;
6935             return this;
6936         },
6937
6938         /**
6939          * 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)
6940          * @param {String} selector The simple selector to test
6941          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6942                 search as a number or element (defaults to 10 || document.body)
6943          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6944          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6945          */
6946         findParent : function(simpleSelector, maxDepth, returnEl){
6947             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6948             maxDepth = maxDepth || 50;
6949             if(typeof maxDepth != "number"){
6950                 stopEl = Roo.getDom(maxDepth);
6951                 maxDepth = 10;
6952             }
6953             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6954                 if(dq.is(p, simpleSelector)){
6955                     return returnEl ? Roo.get(p) : p;
6956                 }
6957                 depth++;
6958                 p = p.parentNode;
6959             }
6960             return null;
6961         },
6962
6963
6964         /**
6965          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6966          * @param {String} selector The simple selector to test
6967          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6968                 search as a number or element (defaults to 10 || document.body)
6969          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6970          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6971          */
6972         findParentNode : function(simpleSelector, maxDepth, returnEl){
6973             var p = Roo.fly(this.dom.parentNode, '_internal');
6974             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6975         },
6976
6977         /**
6978          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6979          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6980          * @param {String} selector The simple selector to test
6981          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6982                 search as a number or element (defaults to 10 || document.body)
6983          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6984          */
6985         up : function(simpleSelector, maxDepth){
6986             return this.findParentNode(simpleSelector, maxDepth, true);
6987         },
6988
6989
6990
6991         /**
6992          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6993          * @param {String} selector The simple selector to test
6994          * @return {Boolean} True if this element matches the selector, else false
6995          */
6996         is : function(simpleSelector){
6997             return Roo.DomQuery.is(this.dom, simpleSelector);
6998         },
6999
7000         /**
7001          * Perform animation on this element.
7002          * @param {Object} args The YUI animation control args
7003          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7004          * @param {Function} onComplete (optional) Function to call when animation completes
7005          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7006          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7007          * @return {Roo.Element} this
7008          */
7009         animate : function(args, duration, onComplete, easing, animType){
7010             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7011             return this;
7012         },
7013
7014         /*
7015          * @private Internal animation call
7016          */
7017         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7018             animType = animType || 'run';
7019             opt = opt || {};
7020             var anim = Roo.lib.Anim[animType](
7021                 this.dom, args,
7022                 (opt.duration || defaultDur) || .35,
7023                 (opt.easing || defaultEase) || 'easeOut',
7024                 function(){
7025                     Roo.callback(cb, this);
7026                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7027                 },
7028                 this
7029             );
7030             opt.anim = anim;
7031             return anim;
7032         },
7033
7034         // private legacy anim prep
7035         preanim : function(a, i){
7036             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7037         },
7038
7039         /**
7040          * Removes worthless text nodes
7041          * @param {Boolean} forceReclean (optional) By default the element
7042          * keeps track if it has been cleaned already so
7043          * you can call this over and over. However, if you update the element and
7044          * need to force a reclean, you can pass true.
7045          */
7046         clean : function(forceReclean){
7047             if(this.isCleaned && forceReclean !== true){
7048                 return this;
7049             }
7050             var ns = /\S/;
7051             var d = this.dom, n = d.firstChild, ni = -1;
7052             while(n){
7053                 var nx = n.nextSibling;
7054                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7055                     d.removeChild(n);
7056                 }else{
7057                     n.nodeIndex = ++ni;
7058                 }
7059                 n = nx;
7060             }
7061             this.isCleaned = true;
7062             return this;
7063         },
7064
7065         // private
7066         calcOffsetsTo : function(el){
7067             el = Roo.get(el);
7068             var d = el.dom;
7069             var restorePos = false;
7070             if(el.getStyle('position') == 'static'){
7071                 el.position('relative');
7072                 restorePos = true;
7073             }
7074             var x = 0, y =0;
7075             var op = this.dom;
7076             while(op && op != d && op.tagName != 'HTML'){
7077                 x+= op.offsetLeft;
7078                 y+= op.offsetTop;
7079                 op = op.offsetParent;
7080             }
7081             if(restorePos){
7082                 el.position('static');
7083             }
7084             return [x, y];
7085         },
7086
7087         /**
7088          * Scrolls this element into view within the passed container.
7089          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7090          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7091          * @return {Roo.Element} this
7092          */
7093         scrollIntoView : function(container, hscroll){
7094             var c = Roo.getDom(container) || document.body;
7095             var el = this.dom;
7096
7097             var o = this.calcOffsetsTo(c),
7098                 l = o[0],
7099                 t = o[1],
7100                 b = t+el.offsetHeight,
7101                 r = l+el.offsetWidth;
7102
7103             var ch = c.clientHeight;
7104             var ct = parseInt(c.scrollTop, 10);
7105             var cl = parseInt(c.scrollLeft, 10);
7106             var cb = ct + ch;
7107             var cr = cl + c.clientWidth;
7108
7109             if(t < ct){
7110                 c.scrollTop = t;
7111             }else if(b > cb){
7112                 c.scrollTop = b-ch;
7113             }
7114
7115             if(hscroll !== false){
7116                 if(l < cl){
7117                     c.scrollLeft = l;
7118                 }else if(r > cr){
7119                     c.scrollLeft = r-c.clientWidth;
7120                 }
7121             }
7122             return this;
7123         },
7124
7125         // private
7126         scrollChildIntoView : function(child, hscroll){
7127             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7128         },
7129
7130         /**
7131          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7132          * the new height may not be available immediately.
7133          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7134          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7135          * @param {Function} onComplete (optional) Function to call when animation completes
7136          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7137          * @return {Roo.Element} this
7138          */
7139         autoHeight : function(animate, duration, onComplete, easing){
7140             var oldHeight = this.getHeight();
7141             this.clip();
7142             this.setHeight(1); // force clipping
7143             setTimeout(function(){
7144                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7145                 if(!animate){
7146                     this.setHeight(height);
7147                     this.unclip();
7148                     if(typeof onComplete == "function"){
7149                         onComplete();
7150                     }
7151                 }else{
7152                     this.setHeight(oldHeight); // restore original height
7153                     this.setHeight(height, animate, duration, function(){
7154                         this.unclip();
7155                         if(typeof onComplete == "function") onComplete();
7156                     }.createDelegate(this), easing);
7157                 }
7158             }.createDelegate(this), 0);
7159             return this;
7160         },
7161
7162         /**
7163          * Returns true if this element is an ancestor of the passed element
7164          * @param {HTMLElement/String} el The element to check
7165          * @return {Boolean} True if this element is an ancestor of el, else false
7166          */
7167         contains : function(el){
7168             if(!el){return false;}
7169             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7170         },
7171
7172         /**
7173          * Checks whether the element is currently visible using both visibility and display properties.
7174          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7175          * @return {Boolean} True if the element is currently visible, else false
7176          */
7177         isVisible : function(deep) {
7178             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7179             if(deep !== true || !vis){
7180                 return vis;
7181             }
7182             var p = this.dom.parentNode;
7183             while(p && p.tagName.toLowerCase() != "body"){
7184                 if(!Roo.fly(p, '_isVisible').isVisible()){
7185                     return false;
7186                 }
7187                 p = p.parentNode;
7188             }
7189             return true;
7190         },
7191
7192         /**
7193          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7194          * @param {String} selector The CSS selector
7195          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7196          * @return {CompositeElement/CompositeElementLite} The composite element
7197          */
7198         select : function(selector, unique){
7199             return El.select(selector, unique, this.dom);
7200         },
7201
7202         /**
7203          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7204          * @param {String} selector The CSS selector
7205          * @return {Array} An array of the matched nodes
7206          */
7207         query : function(selector, unique){
7208             return Roo.DomQuery.select(selector, this.dom);
7209         },
7210
7211         /**
7212          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7213          * @param {String} selector The CSS selector
7214          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7215          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7216          */
7217         child : function(selector, returnDom){
7218             var n = Roo.DomQuery.selectNode(selector, this.dom);
7219             return returnDom ? n : Roo.get(n);
7220         },
7221
7222         /**
7223          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7224          * @param {String} selector The CSS selector
7225          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7226          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7227          */
7228         down : function(selector, returnDom){
7229             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7230             return returnDom ? n : Roo.get(n);
7231         },
7232
7233         /**
7234          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7235          * @param {String} group The group the DD object is member of
7236          * @param {Object} config The DD config object
7237          * @param {Object} overrides An object containing methods to override/implement on the DD object
7238          * @return {Roo.dd.DD} The DD object
7239          */
7240         initDD : function(group, config, overrides){
7241             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7242             return Roo.apply(dd, overrides);
7243         },
7244
7245         /**
7246          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7247          * @param {String} group The group the DDProxy object is member of
7248          * @param {Object} config The DDProxy config object
7249          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7250          * @return {Roo.dd.DDProxy} The DDProxy object
7251          */
7252         initDDProxy : function(group, config, overrides){
7253             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7254             return Roo.apply(dd, overrides);
7255         },
7256
7257         /**
7258          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7259          * @param {String} group The group the DDTarget object is member of
7260          * @param {Object} config The DDTarget config object
7261          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7262          * @return {Roo.dd.DDTarget} The DDTarget object
7263          */
7264         initDDTarget : function(group, config, overrides){
7265             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7266             return Roo.apply(dd, overrides);
7267         },
7268
7269         /**
7270          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7271          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7272          * @param {Boolean} visible Whether the element is visible
7273          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7274          * @return {Roo.Element} this
7275          */
7276          setVisible : function(visible, animate){
7277             if(!animate || !A){
7278                 if(this.visibilityMode == El.DISPLAY){
7279                     this.setDisplayed(visible);
7280                 }else{
7281                     this.fixDisplay();
7282                     this.dom.style.visibility = visible ? "visible" : "hidden";
7283                 }
7284             }else{
7285                 // closure for composites
7286                 var dom = this.dom;
7287                 var visMode = this.visibilityMode;
7288                 if(visible){
7289                     this.setOpacity(.01);
7290                     this.setVisible(true);
7291                 }
7292                 this.anim({opacity: { to: (visible?1:0) }},
7293                       this.preanim(arguments, 1),
7294                       null, .35, 'easeIn', function(){
7295                          if(!visible){
7296                              if(visMode == El.DISPLAY){
7297                                  dom.style.display = "none";
7298                              }else{
7299                                  dom.style.visibility = "hidden";
7300                              }
7301                              Roo.get(dom).setOpacity(1);
7302                          }
7303                      });
7304             }
7305             return this;
7306         },
7307
7308         /**
7309          * Returns true if display is not "none"
7310          * @return {Boolean}
7311          */
7312         isDisplayed : function() {
7313             return this.getStyle("display") != "none";
7314         },
7315
7316         /**
7317          * Toggles the element's visibility or display, depending on visibility mode.
7318          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7319          * @return {Roo.Element} this
7320          */
7321         toggle : function(animate){
7322             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7323             return this;
7324         },
7325
7326         /**
7327          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7328          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7329          * @return {Roo.Element} this
7330          */
7331         setDisplayed : function(value) {
7332             if(typeof value == "boolean"){
7333                value = value ? this.originalDisplay : "none";
7334             }
7335             this.setStyle("display", value);
7336             return this;
7337         },
7338
7339         /**
7340          * Tries to focus the element. Any exceptions are caught and ignored.
7341          * @return {Roo.Element} this
7342          */
7343         focus : function() {
7344             try{
7345                 this.dom.focus();
7346             }catch(e){}
7347             return this;
7348         },
7349
7350         /**
7351          * Tries to blur the element. Any exceptions are caught and ignored.
7352          * @return {Roo.Element} this
7353          */
7354         blur : function() {
7355             try{
7356                 this.dom.blur();
7357             }catch(e){}
7358             return this;
7359         },
7360
7361         /**
7362          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7363          * @param {String/Array} className The CSS class to add, or an array of classes
7364          * @return {Roo.Element} this
7365          */
7366         addClass : function(className){
7367             if(className instanceof Array){
7368                 for(var i = 0, len = className.length; i < len; i++) {
7369                     this.addClass(className[i]);
7370                 }
7371             }else{
7372                 if(className && !this.hasClass(className)){
7373                     this.dom.className = this.dom.className + " " + className;
7374                 }
7375             }
7376             return this;
7377         },
7378
7379         /**
7380          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7381          * @param {String/Array} className The CSS class to add, or an array of classes
7382          * @return {Roo.Element} this
7383          */
7384         radioClass : function(className){
7385             var siblings = this.dom.parentNode.childNodes;
7386             for(var i = 0; i < siblings.length; i++) {
7387                 var s = siblings[i];
7388                 if(s.nodeType == 1){
7389                     Roo.get(s).removeClass(className);
7390                 }
7391             }
7392             this.addClass(className);
7393             return this;
7394         },
7395
7396         /**
7397          * Removes one or more CSS classes from the element.
7398          * @param {String/Array} className The CSS class to remove, or an array of classes
7399          * @return {Roo.Element} this
7400          */
7401         removeClass : function(className){
7402             if(!className || !this.dom.className){
7403                 return this;
7404             }
7405             if(className instanceof Array){
7406                 for(var i = 0, len = className.length; i < len; i++) {
7407                     this.removeClass(className[i]);
7408                 }
7409             }else{
7410                 if(this.hasClass(className)){
7411                     var re = this.classReCache[className];
7412                     if (!re) {
7413                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7414                        this.classReCache[className] = re;
7415                     }
7416                     this.dom.className =
7417                         this.dom.className.replace(re, " ");
7418                 }
7419             }
7420             return this;
7421         },
7422
7423         // private
7424         classReCache: {},
7425
7426         /**
7427          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7428          * @param {String} className The CSS class to toggle
7429          * @return {Roo.Element} this
7430          */
7431         toggleClass : function(className){
7432             if(this.hasClass(className)){
7433                 this.removeClass(className);
7434             }else{
7435                 this.addClass(className);
7436             }
7437             return this;
7438         },
7439
7440         /**
7441          * Checks if the specified CSS class exists on this element's DOM node.
7442          * @param {String} className The CSS class to check for
7443          * @return {Boolean} True if the class exists, else false
7444          */
7445         hasClass : function(className){
7446             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7447         },
7448
7449         /**
7450          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7451          * @param {String} oldClassName The CSS class to replace
7452          * @param {String} newClassName The replacement CSS class
7453          * @return {Roo.Element} this
7454          */
7455         replaceClass : function(oldClassName, newClassName){
7456             this.removeClass(oldClassName);
7457             this.addClass(newClassName);
7458             return this;
7459         },
7460
7461         /**
7462          * Returns an object with properties matching the styles requested.
7463          * For example, el.getStyles('color', 'font-size', 'width') might return
7464          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7465          * @param {String} style1 A style name
7466          * @param {String} style2 A style name
7467          * @param {String} etc.
7468          * @return {Object} The style object
7469          */
7470         getStyles : function(){
7471             var a = arguments, len = a.length, r = {};
7472             for(var i = 0; i < len; i++){
7473                 r[a[i]] = this.getStyle(a[i]);
7474             }
7475             return r;
7476         },
7477
7478         /**
7479          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7480          * @param {String} property The style property whose value is returned.
7481          * @return {String} The current value of the style property for this element.
7482          */
7483         getStyle : function(){
7484             return view && view.getComputedStyle ?
7485                 function(prop){
7486                     var el = this.dom, v, cs, camel;
7487                     if(prop == 'float'){
7488                         prop = "cssFloat";
7489                     }
7490                     if(el.style && (v = el.style[prop])){
7491                         return v;
7492                     }
7493                     if(cs = view.getComputedStyle(el, "")){
7494                         if(!(camel = propCache[prop])){
7495                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7496                         }
7497                         return cs[camel];
7498                     }
7499                     return null;
7500                 } :
7501                 function(prop){
7502                     var el = this.dom, v, cs, camel;
7503                     if(prop == 'opacity'){
7504                         if(typeof el.style.filter == 'string'){
7505                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7506                             if(m){
7507                                 var fv = parseFloat(m[1]);
7508                                 if(!isNaN(fv)){
7509                                     return fv ? fv / 100 : 0;
7510                                 }
7511                             }
7512                         }
7513                         return 1;
7514                     }else if(prop == 'float'){
7515                         prop = "styleFloat";
7516                     }
7517                     if(!(camel = propCache[prop])){
7518                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7519                     }
7520                     if(v = el.style[camel]){
7521                         return v;
7522                     }
7523                     if(cs = el.currentStyle){
7524                         return cs[camel];
7525                     }
7526                     return null;
7527                 };
7528         }(),
7529
7530         /**
7531          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7532          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7533          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7534          * @return {Roo.Element} this
7535          */
7536         setStyle : function(prop, value){
7537             if(typeof prop == "string"){
7538                 
7539                 if (prop == 'float') {
7540                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7541                     return this;
7542                 }
7543                 
7544                 var camel;
7545                 if(!(camel = propCache[prop])){
7546                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7547                 }
7548                 
7549                 if(camel == 'opacity') {
7550                     this.setOpacity(value);
7551                 }else{
7552                     this.dom.style[camel] = value;
7553                 }
7554             }else{
7555                 for(var style in prop){
7556                     if(typeof prop[style] != "function"){
7557                        this.setStyle(style, prop[style]);
7558                     }
7559                 }
7560             }
7561             return this;
7562         },
7563
7564         /**
7565          * More flexible version of {@link #setStyle} for setting style properties.
7566          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7567          * a function which returns such a specification.
7568          * @return {Roo.Element} this
7569          */
7570         applyStyles : function(style){
7571             Roo.DomHelper.applyStyles(this.dom, style);
7572             return this;
7573         },
7574
7575         /**
7576           * 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).
7577           * @return {Number} The X position of the element
7578           */
7579         getX : function(){
7580             return D.getX(this.dom);
7581         },
7582
7583         /**
7584           * 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).
7585           * @return {Number} The Y position of the element
7586           */
7587         getY : function(){
7588             return D.getY(this.dom);
7589         },
7590
7591         /**
7592           * 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).
7593           * @return {Array} The XY position of the element
7594           */
7595         getXY : function(){
7596             return D.getXY(this.dom);
7597         },
7598
7599         /**
7600          * 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).
7601          * @param {Number} The X position of the element
7602          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7603          * @return {Roo.Element} this
7604          */
7605         setX : function(x, animate){
7606             if(!animate || !A){
7607                 D.setX(this.dom, x);
7608             }else{
7609                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7610             }
7611             return this;
7612         },
7613
7614         /**
7615          * 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).
7616          * @param {Number} The Y position of the element
7617          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7618          * @return {Roo.Element} this
7619          */
7620         setY : function(y, animate){
7621             if(!animate || !A){
7622                 D.setY(this.dom, y);
7623             }else{
7624                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7625             }
7626             return this;
7627         },
7628
7629         /**
7630          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7631          * @param {String} left The left CSS property value
7632          * @return {Roo.Element} this
7633          */
7634         setLeft : function(left){
7635             this.setStyle("left", this.addUnits(left));
7636             return this;
7637         },
7638
7639         /**
7640          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7641          * @param {String} top The top CSS property value
7642          * @return {Roo.Element} this
7643          */
7644         setTop : function(top){
7645             this.setStyle("top", this.addUnits(top));
7646             return this;
7647         },
7648
7649         /**
7650          * Sets the element's CSS right style.
7651          * @param {String} right The right CSS property value
7652          * @return {Roo.Element} this
7653          */
7654         setRight : function(right){
7655             this.setStyle("right", this.addUnits(right));
7656             return this;
7657         },
7658
7659         /**
7660          * Sets the element's CSS bottom style.
7661          * @param {String} bottom The bottom CSS property value
7662          * @return {Roo.Element} this
7663          */
7664         setBottom : function(bottom){
7665             this.setStyle("bottom", this.addUnits(bottom));
7666             return this;
7667         },
7668
7669         /**
7670          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7671          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7672          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7673          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7674          * @return {Roo.Element} this
7675          */
7676         setXY : function(pos, animate){
7677             if(!animate || !A){
7678                 D.setXY(this.dom, pos);
7679             }else{
7680                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7681             }
7682             return this;
7683         },
7684
7685         /**
7686          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7687          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7688          * @param {Number} x X value for new position (coordinates are page-based)
7689          * @param {Number} y Y value for new position (coordinates are page-based)
7690          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7691          * @return {Roo.Element} this
7692          */
7693         setLocation : function(x, y, animate){
7694             this.setXY([x, y], this.preanim(arguments, 2));
7695             return this;
7696         },
7697
7698         /**
7699          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7700          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7701          * @param {Number} x X value for new position (coordinates are page-based)
7702          * @param {Number} y Y value for new position (coordinates are page-based)
7703          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7704          * @return {Roo.Element} this
7705          */
7706         moveTo : function(x, y, animate){
7707             this.setXY([x, y], this.preanim(arguments, 2));
7708             return this;
7709         },
7710
7711         /**
7712          * Returns the region of the given element.
7713          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7714          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7715          */
7716         getRegion : function(){
7717             return D.getRegion(this.dom);
7718         },
7719
7720         /**
7721          * Returns the offset height of the element
7722          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7723          * @return {Number} The element's height
7724          */
7725         getHeight : function(contentHeight){
7726             var h = this.dom.offsetHeight || 0;
7727             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7728         },
7729
7730         /**
7731          * Returns the offset width of the element
7732          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7733          * @return {Number} The element's width
7734          */
7735         getWidth : function(contentWidth){
7736             var w = this.dom.offsetWidth || 0;
7737             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7738         },
7739
7740         /**
7741          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7742          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7743          * if a height has not been set using CSS.
7744          * @return {Number}
7745          */
7746         getComputedHeight : function(){
7747             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7748             if(!h){
7749                 h = parseInt(this.getStyle('height'), 10) || 0;
7750                 if(!this.isBorderBox()){
7751                     h += this.getFrameWidth('tb');
7752                 }
7753             }
7754             return h;
7755         },
7756
7757         /**
7758          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7759          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7760          * if a width has not been set using CSS.
7761          * @return {Number}
7762          */
7763         getComputedWidth : function(){
7764             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7765             if(!w){
7766                 w = parseInt(this.getStyle('width'), 10) || 0;
7767                 if(!this.isBorderBox()){
7768                     w += this.getFrameWidth('lr');
7769                 }
7770             }
7771             return w;
7772         },
7773
7774         /**
7775          * Returns the size of the element.
7776          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7777          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7778          */
7779         getSize : function(contentSize){
7780             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7781         },
7782
7783         /**
7784          * Returns the width and height of the viewport.
7785          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7786          */
7787         getViewSize : function(){
7788             var d = this.dom, doc = document, aw = 0, ah = 0;
7789             if(d == doc || d == doc.body){
7790                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7791             }else{
7792                 return {
7793                     width : d.clientWidth,
7794                     height: d.clientHeight
7795                 };
7796             }
7797         },
7798
7799         /**
7800          * Returns the value of the "value" attribute
7801          * @param {Boolean} asNumber true to parse the value as a number
7802          * @return {String/Number}
7803          */
7804         getValue : function(asNumber){
7805             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7806         },
7807
7808         // private
7809         adjustWidth : function(width){
7810             if(typeof width == "number"){
7811                 if(this.autoBoxAdjust && !this.isBorderBox()){
7812                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7813                 }
7814                 if(width < 0){
7815                     width = 0;
7816                 }
7817             }
7818             return width;
7819         },
7820
7821         // private
7822         adjustHeight : function(height){
7823             if(typeof height == "number"){
7824                if(this.autoBoxAdjust && !this.isBorderBox()){
7825                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7826                }
7827                if(height < 0){
7828                    height = 0;
7829                }
7830             }
7831             return height;
7832         },
7833
7834         /**
7835          * Set the width of the element
7836          * @param {Number} width The new width
7837          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7838          * @return {Roo.Element} this
7839          */
7840         setWidth : function(width, animate){
7841             width = this.adjustWidth(width);
7842             if(!animate || !A){
7843                 this.dom.style.width = this.addUnits(width);
7844             }else{
7845                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7846             }
7847             return this;
7848         },
7849
7850         /**
7851          * Set the height of the element
7852          * @param {Number} height The new height
7853          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7854          * @return {Roo.Element} this
7855          */
7856          setHeight : function(height, animate){
7857             height = this.adjustHeight(height);
7858             if(!animate || !A){
7859                 this.dom.style.height = this.addUnits(height);
7860             }else{
7861                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7862             }
7863             return this;
7864         },
7865
7866         /**
7867          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7868          * @param {Number} width The new width
7869          * @param {Number} height The new height
7870          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7871          * @return {Roo.Element} this
7872          */
7873          setSize : function(width, height, animate){
7874             if(typeof width == "object"){ // in case of object from getSize()
7875                 height = width.height; width = width.width;
7876             }
7877             width = this.adjustWidth(width); height = this.adjustHeight(height);
7878             if(!animate || !A){
7879                 this.dom.style.width = this.addUnits(width);
7880                 this.dom.style.height = this.addUnits(height);
7881             }else{
7882                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7883             }
7884             return this;
7885         },
7886
7887         /**
7888          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7889          * @param {Number} x X value for new position (coordinates are page-based)
7890          * @param {Number} y Y value for new position (coordinates are page-based)
7891          * @param {Number} width The new width
7892          * @param {Number} height The new height
7893          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7894          * @return {Roo.Element} this
7895          */
7896         setBounds : function(x, y, width, height, animate){
7897             if(!animate || !A){
7898                 this.setSize(width, height);
7899                 this.setLocation(x, y);
7900             }else{
7901                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7902                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7903                               this.preanim(arguments, 4), 'motion');
7904             }
7905             return this;
7906         },
7907
7908         /**
7909          * 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.
7910          * @param {Roo.lib.Region} region The region to fill
7911          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7912          * @return {Roo.Element} this
7913          */
7914         setRegion : function(region, animate){
7915             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7916             return this;
7917         },
7918
7919         /**
7920          * Appends an event handler
7921          *
7922          * @param {String}   eventName     The type of event to append
7923          * @param {Function} fn        The method the event invokes
7924          * @param {Object} scope       (optional) The scope (this object) of the fn
7925          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7926          */
7927         addListener : function(eventName, fn, scope, options){
7928             if (this.dom) {
7929                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7930             }
7931         },
7932
7933         /**
7934          * Removes an event handler from this element
7935          * @param {String} eventName the type of event to remove
7936          * @param {Function} fn the method the event invokes
7937          * @return {Roo.Element} this
7938          */
7939         removeListener : function(eventName, fn){
7940             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7941             return this;
7942         },
7943
7944         /**
7945          * Removes all previous added listeners from this element
7946          * @return {Roo.Element} this
7947          */
7948         removeAllListeners : function(){
7949             E.purgeElement(this.dom);
7950             return this;
7951         },
7952
7953         relayEvent : function(eventName, observable){
7954             this.on(eventName, function(e){
7955                 observable.fireEvent(eventName, e);
7956             });
7957         },
7958
7959         /**
7960          * Set the opacity of the element
7961          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7962          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7963          * @return {Roo.Element} this
7964          */
7965          setOpacity : function(opacity, animate){
7966             if(!animate || !A){
7967                 var s = this.dom.style;
7968                 if(Roo.isIE){
7969                     s.zoom = 1;
7970                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7971                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7972                 }else{
7973                     s.opacity = opacity;
7974                 }
7975             }else{
7976                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7977             }
7978             return this;
7979         },
7980
7981         /**
7982          * Gets the left X coordinate
7983          * @param {Boolean} local True to get the local css position instead of page coordinate
7984          * @return {Number}
7985          */
7986         getLeft : function(local){
7987             if(!local){
7988                 return this.getX();
7989             }else{
7990                 return parseInt(this.getStyle("left"), 10) || 0;
7991             }
7992         },
7993
7994         /**
7995          * Gets the right X coordinate of the element (element X position + element width)
7996          * @param {Boolean} local True to get the local css position instead of page coordinate
7997          * @return {Number}
7998          */
7999         getRight : function(local){
8000             if(!local){
8001                 return this.getX() + this.getWidth();
8002             }else{
8003                 return (this.getLeft(true) + this.getWidth()) || 0;
8004             }
8005         },
8006
8007         /**
8008          * Gets the top Y coordinate
8009          * @param {Boolean} local True to get the local css position instead of page coordinate
8010          * @return {Number}
8011          */
8012         getTop : function(local) {
8013             if(!local){
8014                 return this.getY();
8015             }else{
8016                 return parseInt(this.getStyle("top"), 10) || 0;
8017             }
8018         },
8019
8020         /**
8021          * Gets the bottom Y coordinate of the element (element Y position + element height)
8022          * @param {Boolean} local True to get the local css position instead of page coordinate
8023          * @return {Number}
8024          */
8025         getBottom : function(local){
8026             if(!local){
8027                 return this.getY() + this.getHeight();
8028             }else{
8029                 return (this.getTop(true) + this.getHeight()) || 0;
8030             }
8031         },
8032
8033         /**
8034         * Initializes positioning on this element. If a desired position is not passed, it will make the
8035         * the element positioned relative IF it is not already positioned.
8036         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8037         * @param {Number} zIndex (optional) The zIndex to apply
8038         * @param {Number} x (optional) Set the page X position
8039         * @param {Number} y (optional) Set the page Y position
8040         */
8041         position : function(pos, zIndex, x, y){
8042             if(!pos){
8043                if(this.getStyle('position') == 'static'){
8044                    this.setStyle('position', 'relative');
8045                }
8046             }else{
8047                 this.setStyle("position", pos);
8048             }
8049             if(zIndex){
8050                 this.setStyle("z-index", zIndex);
8051             }
8052             if(x !== undefined && y !== undefined){
8053                 this.setXY([x, y]);
8054             }else if(x !== undefined){
8055                 this.setX(x);
8056             }else if(y !== undefined){
8057                 this.setY(y);
8058             }
8059         },
8060
8061         /**
8062         * Clear positioning back to the default when the document was loaded
8063         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8064         * @return {Roo.Element} this
8065          */
8066         clearPositioning : function(value){
8067             value = value ||'';
8068             this.setStyle({
8069                 "left": value,
8070                 "right": value,
8071                 "top": value,
8072                 "bottom": value,
8073                 "z-index": "",
8074                 "position" : "static"
8075             });
8076             return this;
8077         },
8078
8079         /**
8080         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8081         * snapshot before performing an update and then restoring the element.
8082         * @return {Object}
8083         */
8084         getPositioning : function(){
8085             var l = this.getStyle("left");
8086             var t = this.getStyle("top");
8087             return {
8088                 "position" : this.getStyle("position"),
8089                 "left" : l,
8090                 "right" : l ? "" : this.getStyle("right"),
8091                 "top" : t,
8092                 "bottom" : t ? "" : this.getStyle("bottom"),
8093                 "z-index" : this.getStyle("z-index")
8094             };
8095         },
8096
8097         /**
8098          * Gets the width of the border(s) for the specified side(s)
8099          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8100          * passing lr would get the border (l)eft width + the border (r)ight width.
8101          * @return {Number} The width of the sides passed added together
8102          */
8103         getBorderWidth : function(side){
8104             return this.addStyles(side, El.borders);
8105         },
8106
8107         /**
8108          * Gets the width of the padding(s) for the specified side(s)
8109          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8110          * passing lr would get the padding (l)eft + the padding (r)ight.
8111          * @return {Number} The padding of the sides passed added together
8112          */
8113         getPadding : function(side){
8114             return this.addStyles(side, El.paddings);
8115         },
8116
8117         /**
8118         * Set positioning with an object returned by getPositioning().
8119         * @param {Object} posCfg
8120         * @return {Roo.Element} this
8121          */
8122         setPositioning : function(pc){
8123             this.applyStyles(pc);
8124             if(pc.right == "auto"){
8125                 this.dom.style.right = "";
8126             }
8127             if(pc.bottom == "auto"){
8128                 this.dom.style.bottom = "";
8129             }
8130             return this;
8131         },
8132
8133         // private
8134         fixDisplay : function(){
8135             if(this.getStyle("display") == "none"){
8136                 this.setStyle("visibility", "hidden");
8137                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8138                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8139                     this.setStyle("display", "block");
8140                 }
8141             }
8142         },
8143
8144         /**
8145          * Quick set left and top adding default units
8146          * @param {String} left The left CSS property value
8147          * @param {String} top The top CSS property value
8148          * @return {Roo.Element} this
8149          */
8150          setLeftTop : function(left, top){
8151             this.dom.style.left = this.addUnits(left);
8152             this.dom.style.top = this.addUnits(top);
8153             return this;
8154         },
8155
8156         /**
8157          * Move this element relative to its current position.
8158          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8159          * @param {Number} distance How far to move the element in pixels
8160          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8161          * @return {Roo.Element} this
8162          */
8163          move : function(direction, distance, animate){
8164             var xy = this.getXY();
8165             direction = direction.toLowerCase();
8166             switch(direction){
8167                 case "l":
8168                 case "left":
8169                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8170                     break;
8171                case "r":
8172                case "right":
8173                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8174                     break;
8175                case "t":
8176                case "top":
8177                case "up":
8178                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8179                     break;
8180                case "b":
8181                case "bottom":
8182                case "down":
8183                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8184                     break;
8185             }
8186             return this;
8187         },
8188
8189         /**
8190          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8191          * @return {Roo.Element} this
8192          */
8193         clip : function(){
8194             if(!this.isClipped){
8195                this.isClipped = true;
8196                this.originalClip = {
8197                    "o": this.getStyle("overflow"),
8198                    "x": this.getStyle("overflow-x"),
8199                    "y": this.getStyle("overflow-y")
8200                };
8201                this.setStyle("overflow", "hidden");
8202                this.setStyle("overflow-x", "hidden");
8203                this.setStyle("overflow-y", "hidden");
8204             }
8205             return this;
8206         },
8207
8208         /**
8209          *  Return clipping (overflow) to original clipping before clip() was called
8210          * @return {Roo.Element} this
8211          */
8212         unclip : function(){
8213             if(this.isClipped){
8214                 this.isClipped = false;
8215                 var o = this.originalClip;
8216                 if(o.o){this.setStyle("overflow", o.o);}
8217                 if(o.x){this.setStyle("overflow-x", o.x);}
8218                 if(o.y){this.setStyle("overflow-y", o.y);}
8219             }
8220             return this;
8221         },
8222
8223
8224         /**
8225          * Gets the x,y coordinates specified by the anchor position on the element.
8226          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8227          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8228          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8229          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8230          * @return {Array} [x, y] An array containing the element's x and y coordinates
8231          */
8232         getAnchorXY : function(anchor, local, s){
8233             //Passing a different size is useful for pre-calculating anchors,
8234             //especially for anchored animations that change the el size.
8235
8236             var w, h, vp = false;
8237             if(!s){
8238                 var d = this.dom;
8239                 if(d == document.body || d == document){
8240                     vp = true;
8241                     w = D.getViewWidth(); h = D.getViewHeight();
8242                 }else{
8243                     w = this.getWidth(); h = this.getHeight();
8244                 }
8245             }else{
8246                 w = s.width;  h = s.height;
8247             }
8248             var x = 0, y = 0, r = Math.round;
8249             switch((anchor || "tl").toLowerCase()){
8250                 case "c":
8251                     x = r(w*.5);
8252                     y = r(h*.5);
8253                 break;
8254                 case "t":
8255                     x = r(w*.5);
8256                     y = 0;
8257                 break;
8258                 case "l":
8259                     x = 0;
8260                     y = r(h*.5);
8261                 break;
8262                 case "r":
8263                     x = w;
8264                     y = r(h*.5);
8265                 break;
8266                 case "b":
8267                     x = r(w*.5);
8268                     y = h;
8269                 break;
8270                 case "tl":
8271                     x = 0;
8272                     y = 0;
8273                 break;
8274                 case "bl":
8275                     x = 0;
8276                     y = h;
8277                 break;
8278                 case "br":
8279                     x = w;
8280                     y = h;
8281                 break;
8282                 case "tr":
8283                     x = w;
8284                     y = 0;
8285                 break;
8286             }
8287             if(local === true){
8288                 return [x, y];
8289             }
8290             if(vp){
8291                 var sc = this.getScroll();
8292                 return [x + sc.left, y + sc.top];
8293             }
8294             //Add the element's offset xy
8295             var o = this.getXY();
8296             return [x+o[0], y+o[1]];
8297         },
8298
8299         /**
8300          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8301          * supported position values.
8302          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8303          * @param {String} position The position to align to.
8304          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8305          * @return {Array} [x, y]
8306          */
8307         getAlignToXY : function(el, p, o){
8308             el = Roo.get(el);
8309             var d = this.dom;
8310             if(!el.dom){
8311                 throw "Element.alignTo with an element that doesn't exist";
8312             }
8313             var c = false; //constrain to viewport
8314             var p1 = "", p2 = "";
8315             o = o || [0,0];
8316
8317             if(!p){
8318                 p = "tl-bl";
8319             }else if(p == "?"){
8320                 p = "tl-bl?";
8321             }else if(p.indexOf("-") == -1){
8322                 p = "tl-" + p;
8323             }
8324             p = p.toLowerCase();
8325             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8326             if(!m){
8327                throw "Element.alignTo with an invalid alignment " + p;
8328             }
8329             p1 = m[1]; p2 = m[2]; c = !!m[3];
8330
8331             //Subtract the aligned el's internal xy from the target's offset xy
8332             //plus custom offset to get the aligned el's new offset xy
8333             var a1 = this.getAnchorXY(p1, true);
8334             var a2 = el.getAnchorXY(p2, false);
8335             var x = a2[0] - a1[0] + o[0];
8336             var y = a2[1] - a1[1] + o[1];
8337             if(c){
8338                 //constrain the aligned el to viewport if necessary
8339                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8340                 // 5px of margin for ie
8341                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8342
8343                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8344                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8345                 //otherwise swap the aligned el to the opposite border of the target.
8346                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8347                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8348                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8349                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8350
8351                var doc = document;
8352                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8353                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8354
8355                if((x+w) > dw + scrollX){
8356                     x = swapX ? r.left-w : dw+scrollX-w;
8357                 }
8358                if(x < scrollX){
8359                    x = swapX ? r.right : scrollX;
8360                }
8361                if((y+h) > dh + scrollY){
8362                     y = swapY ? r.top-h : dh+scrollY-h;
8363                 }
8364                if (y < scrollY){
8365                    y = swapY ? r.bottom : scrollY;
8366                }
8367             }
8368             return [x,y];
8369         },
8370
8371         // private
8372         getConstrainToXY : function(){
8373             var os = {top:0, left:0, bottom:0, right: 0};
8374
8375             return function(el, local, offsets, proposedXY){
8376                 el = Roo.get(el);
8377                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8378
8379                 var vw, vh, vx = 0, vy = 0;
8380                 if(el.dom == document.body || el.dom == document){
8381                     vw = Roo.lib.Dom.getViewWidth();
8382                     vh = Roo.lib.Dom.getViewHeight();
8383                 }else{
8384                     vw = el.dom.clientWidth;
8385                     vh = el.dom.clientHeight;
8386                     if(!local){
8387                         var vxy = el.getXY();
8388                         vx = vxy[0];
8389                         vy = vxy[1];
8390                     }
8391                 }
8392
8393                 var s = el.getScroll();
8394
8395                 vx += offsets.left + s.left;
8396                 vy += offsets.top + s.top;
8397
8398                 vw -= offsets.right;
8399                 vh -= offsets.bottom;
8400
8401                 var vr = vx+vw;
8402                 var vb = vy+vh;
8403
8404                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8405                 var x = xy[0], y = xy[1];
8406                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8407
8408                 // only move it if it needs it
8409                 var moved = false;
8410
8411                 // first validate right/bottom
8412                 if((x + w) > vr){
8413                     x = vr - w;
8414                     moved = true;
8415                 }
8416                 if((y + h) > vb){
8417                     y = vb - h;
8418                     moved = true;
8419                 }
8420                 // then make sure top/left isn't negative
8421                 if(x < vx){
8422                     x = vx;
8423                     moved = true;
8424                 }
8425                 if(y < vy){
8426                     y = vy;
8427                     moved = true;
8428                 }
8429                 return moved ? [x, y] : false;
8430             };
8431         }(),
8432
8433         // private
8434         adjustForConstraints : function(xy, parent, offsets){
8435             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8436         },
8437
8438         /**
8439          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8440          * document it aligns it to the viewport.
8441          * The position parameter is optional, and can be specified in any one of the following formats:
8442          * <ul>
8443          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8444          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8445          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8446          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8447          *   <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
8448          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8449          * </ul>
8450          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8451          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8452          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8453          * that specified in order to enforce the viewport constraints.
8454          * Following are all of the supported anchor positions:
8455     <pre>
8456     Value  Description
8457     -----  -----------------------------
8458     tl     The top left corner (default)
8459     t      The center of the top edge
8460     tr     The top right corner
8461     l      The center of the left edge
8462     c      In the center of the element
8463     r      The center of the right edge
8464     bl     The bottom left corner
8465     b      The center of the bottom edge
8466     br     The bottom right corner
8467     </pre>
8468     Example Usage:
8469     <pre><code>
8470     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8471     el.alignTo("other-el");
8472
8473     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8474     el.alignTo("other-el", "tr?");
8475
8476     // align the bottom right corner of el with the center left edge of other-el
8477     el.alignTo("other-el", "br-l?");
8478
8479     // align the center of el with the bottom left corner of other-el and
8480     // adjust the x position by -6 pixels (and the y position by 0)
8481     el.alignTo("other-el", "c-bl", [-6, 0]);
8482     </code></pre>
8483          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8484          * @param {String} position The position to align to.
8485          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8486          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8487          * @return {Roo.Element} this
8488          */
8489         alignTo : function(element, position, offsets, animate){
8490             var xy = this.getAlignToXY(element, position, offsets);
8491             this.setXY(xy, this.preanim(arguments, 3));
8492             return this;
8493         },
8494
8495         /**
8496          * Anchors an element to another element and realigns it when the window is resized.
8497          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8498          * @param {String} position The position to align to.
8499          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8500          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8501          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8502          * is a number, it is used as the buffer delay (defaults to 50ms).
8503          * @param {Function} callback The function to call after the animation finishes
8504          * @return {Roo.Element} this
8505          */
8506         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8507             var action = function(){
8508                 this.alignTo(el, alignment, offsets, animate);
8509                 Roo.callback(callback, this);
8510             };
8511             Roo.EventManager.onWindowResize(action, this);
8512             var tm = typeof monitorScroll;
8513             if(tm != 'undefined'){
8514                 Roo.EventManager.on(window, 'scroll', action, this,
8515                     {buffer: tm == 'number' ? monitorScroll : 50});
8516             }
8517             action.call(this); // align immediately
8518             return this;
8519         },
8520         /**
8521          * Clears any opacity settings from this element. Required in some cases for IE.
8522          * @return {Roo.Element} this
8523          */
8524         clearOpacity : function(){
8525             if (window.ActiveXObject) {
8526                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8527                     this.dom.style.filter = "";
8528                 }
8529             } else {
8530                 this.dom.style.opacity = "";
8531                 this.dom.style["-moz-opacity"] = "";
8532                 this.dom.style["-khtml-opacity"] = "";
8533             }
8534             return this;
8535         },
8536
8537         /**
8538          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8539          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8540          * @return {Roo.Element} this
8541          */
8542         hide : function(animate){
8543             this.setVisible(false, this.preanim(arguments, 0));
8544             return this;
8545         },
8546
8547         /**
8548         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8549         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8550          * @return {Roo.Element} this
8551          */
8552         show : function(animate){
8553             this.setVisible(true, this.preanim(arguments, 0));
8554             return this;
8555         },
8556
8557         /**
8558          * @private Test if size has a unit, otherwise appends the default
8559          */
8560         addUnits : function(size){
8561             return Roo.Element.addUnits(size, this.defaultUnit);
8562         },
8563
8564         /**
8565          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8566          * @return {Roo.Element} this
8567          */
8568         beginMeasure : function(){
8569             var el = this.dom;
8570             if(el.offsetWidth || el.offsetHeight){
8571                 return this; // offsets work already
8572             }
8573             var changed = [];
8574             var p = this.dom, b = document.body; // start with this element
8575             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8576                 var pe = Roo.get(p);
8577                 if(pe.getStyle('display') == 'none'){
8578                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8579                     p.style.visibility = "hidden";
8580                     p.style.display = "block";
8581                 }
8582                 p = p.parentNode;
8583             }
8584             this._measureChanged = changed;
8585             return this;
8586
8587         },
8588
8589         /**
8590          * Restores displays to before beginMeasure was called
8591          * @return {Roo.Element} this
8592          */
8593         endMeasure : function(){
8594             var changed = this._measureChanged;
8595             if(changed){
8596                 for(var i = 0, len = changed.length; i < len; i++) {
8597                     var r = changed[i];
8598                     r.el.style.visibility = r.visibility;
8599                     r.el.style.display = "none";
8600                 }
8601                 this._measureChanged = null;
8602             }
8603             return this;
8604         },
8605
8606         /**
8607         * Update the innerHTML of this element, optionally searching for and processing scripts
8608         * @param {String} html The new HTML
8609         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8610         * @param {Function} callback For async script loading you can be noticed when the update completes
8611         * @return {Roo.Element} this
8612          */
8613         update : function(html, loadScripts, callback){
8614             if(typeof html == "undefined"){
8615                 html = "";
8616             }
8617             if(loadScripts !== true){
8618                 this.dom.innerHTML = html;
8619                 if(typeof callback == "function"){
8620                     callback();
8621                 }
8622                 return this;
8623             }
8624             var id = Roo.id();
8625             var dom = this.dom;
8626
8627             html += '<span id="' + id + '"></span>';
8628
8629             E.onAvailable(id, function(){
8630                 var hd = document.getElementsByTagName("head")[0];
8631                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8632                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8633                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8634
8635                 var match;
8636                 while(match = re.exec(html)){
8637                     var attrs = match[1];
8638                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8639                     if(srcMatch && srcMatch[2]){
8640                        var s = document.createElement("script");
8641                        s.src = srcMatch[2];
8642                        var typeMatch = attrs.match(typeRe);
8643                        if(typeMatch && typeMatch[2]){
8644                            s.type = typeMatch[2];
8645                        }
8646                        hd.appendChild(s);
8647                     }else if(match[2] && match[2].length > 0){
8648                         if(window.execScript) {
8649                            window.execScript(match[2]);
8650                         } else {
8651                             /**
8652                              * eval:var:id
8653                              * eval:var:dom
8654                              * eval:var:html
8655                              * 
8656                              */
8657                            window.eval(match[2]);
8658                         }
8659                     }
8660                 }
8661                 var el = document.getElementById(id);
8662                 if(el){el.parentNode.removeChild(el);}
8663                 if(typeof callback == "function"){
8664                     callback();
8665                 }
8666             });
8667             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8668             return this;
8669         },
8670
8671         /**
8672          * Direct access to the UpdateManager update() method (takes the same parameters).
8673          * @param {String/Function} url The url for this request or a function to call to get the url
8674          * @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}
8675          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8676          * @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.
8677          * @return {Roo.Element} this
8678          */
8679         load : function(){
8680             var um = this.getUpdateManager();
8681             um.update.apply(um, arguments);
8682             return this;
8683         },
8684
8685         /**
8686         * Gets this element's UpdateManager
8687         * @return {Roo.UpdateManager} The UpdateManager
8688         */
8689         getUpdateManager : function(){
8690             if(!this.updateManager){
8691                 this.updateManager = new Roo.UpdateManager(this);
8692             }
8693             return this.updateManager;
8694         },
8695
8696         /**
8697          * Disables text selection for this element (normalized across browsers)
8698          * @return {Roo.Element} this
8699          */
8700         unselectable : function(){
8701             this.dom.unselectable = "on";
8702             this.swallowEvent("selectstart", true);
8703             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8704             this.addClass("x-unselectable");
8705             return this;
8706         },
8707
8708         /**
8709         * Calculates the x, y to center this element on the screen
8710         * @return {Array} The x, y values [x, y]
8711         */
8712         getCenterXY : function(){
8713             return this.getAlignToXY(document, 'c-c');
8714         },
8715
8716         /**
8717         * Centers the Element in either the viewport, or another Element.
8718         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8719         */
8720         center : function(centerIn){
8721             this.alignTo(centerIn || document, 'c-c');
8722             return this;
8723         },
8724
8725         /**
8726          * Tests various css rules/browsers to determine if this element uses a border box
8727          * @return {Boolean}
8728          */
8729         isBorderBox : function(){
8730             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8731         },
8732
8733         /**
8734          * Return a box {x, y, width, height} that can be used to set another elements
8735          * size/location to match this element.
8736          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8737          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8738          * @return {Object} box An object in the format {x, y, width, height}
8739          */
8740         getBox : function(contentBox, local){
8741             var xy;
8742             if(!local){
8743                 xy = this.getXY();
8744             }else{
8745                 var left = parseInt(this.getStyle("left"), 10) || 0;
8746                 var top = parseInt(this.getStyle("top"), 10) || 0;
8747                 xy = [left, top];
8748             }
8749             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8750             if(!contentBox){
8751                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8752             }else{
8753                 var l = this.getBorderWidth("l")+this.getPadding("l");
8754                 var r = this.getBorderWidth("r")+this.getPadding("r");
8755                 var t = this.getBorderWidth("t")+this.getPadding("t");
8756                 var b = this.getBorderWidth("b")+this.getPadding("b");
8757                 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)};
8758             }
8759             bx.right = bx.x + bx.width;
8760             bx.bottom = bx.y + bx.height;
8761             return bx;
8762         },
8763
8764         /**
8765          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8766          for more information about the sides.
8767          * @param {String} sides
8768          * @return {Number}
8769          */
8770         getFrameWidth : function(sides, onlyContentBox){
8771             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8772         },
8773
8774         /**
8775          * 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.
8776          * @param {Object} box The box to fill {x, y, width, height}
8777          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8778          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8779          * @return {Roo.Element} this
8780          */
8781         setBox : function(box, adjust, animate){
8782             var w = box.width, h = box.height;
8783             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8784                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8785                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8786             }
8787             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8788             return this;
8789         },
8790
8791         /**
8792          * Forces the browser to repaint this element
8793          * @return {Roo.Element} this
8794          */
8795          repaint : function(){
8796             var dom = this.dom;
8797             this.addClass("x-repaint");
8798             setTimeout(function(){
8799                 Roo.get(dom).removeClass("x-repaint");
8800             }, 1);
8801             return this;
8802         },
8803
8804         /**
8805          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8806          * then it returns the calculated width of the sides (see getPadding)
8807          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8808          * @return {Object/Number}
8809          */
8810         getMargins : function(side){
8811             if(!side){
8812                 return {
8813                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8814                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8815                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8816                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8817                 };
8818             }else{
8819                 return this.addStyles(side, El.margins);
8820              }
8821         },
8822
8823         // private
8824         addStyles : function(sides, styles){
8825             var val = 0, v, w;
8826             for(var i = 0, len = sides.length; i < len; i++){
8827                 v = this.getStyle(styles[sides.charAt(i)]);
8828                 if(v){
8829                      w = parseInt(v, 10);
8830                      if(w){ val += w; }
8831                 }
8832             }
8833             return val;
8834         },
8835
8836         /**
8837          * Creates a proxy element of this element
8838          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8839          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8840          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8841          * @return {Roo.Element} The new proxy element
8842          */
8843         createProxy : function(config, renderTo, matchBox){
8844             if(renderTo){
8845                 renderTo = Roo.getDom(renderTo);
8846             }else{
8847                 renderTo = document.body;
8848             }
8849             config = typeof config == "object" ?
8850                 config : {tag : "div", cls: config};
8851             var proxy = Roo.DomHelper.append(renderTo, config, true);
8852             if(matchBox){
8853                proxy.setBox(this.getBox());
8854             }
8855             return proxy;
8856         },
8857
8858         /**
8859          * Puts a mask over this element to disable user interaction. Requires core.css.
8860          * This method can only be applied to elements which accept child nodes.
8861          * @param {String} msg (optional) A message to display in the mask
8862          * @param {String} msgCls (optional) A css class to apply to the msg element
8863          * @return {Element} The mask  element
8864          */
8865         mask : function(msg, msgCls)
8866         {
8867             if(this.getStyle("position") == "static"){
8868                 this.setStyle("position", "relative");
8869             }
8870             if(!this._mask){
8871                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8872             }
8873             this.addClass("x-masked");
8874             this._mask.setDisplayed(true);
8875             
8876             // we wander
8877             var z = 0;
8878             var dom = this.dom
8879             while (dom && dom.style) {
8880                 if (!isNaN(parseInt(dom.style.zIndex))) {
8881                     z = Math.max(z, parseInt(dom.style.zIndex));
8882                 }
8883                 dom = dom.parentNode;
8884             }
8885             // if we are masking the body - then it hides everything..
8886             if (this.dom == document.body) {
8887                 z = 1000000;
8888                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8889                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8890             }
8891            
8892             if(typeof msg == 'string'){
8893                 if(!this._maskMsg){
8894                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8895                 }
8896                 var mm = this._maskMsg;
8897                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8898                 mm.dom.firstChild.innerHTML = msg;
8899                 mm.setDisplayed(true);
8900                 mm.center(this);
8901                 mm.setStyle('z-index', z + 102);
8902             }
8903             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8904                 this._mask.setHeight(this.getHeight());
8905             }
8906             this._mask.setStyle('z-index', z + 100);
8907             
8908             return this._mask;
8909         },
8910
8911         /**
8912          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8913          * it is cached for reuse.
8914          */
8915         unmask : function(removeEl){
8916             if(this._mask){
8917                 if(removeEl === true){
8918                     this._mask.remove();
8919                     delete this._mask;
8920                     if(this._maskMsg){
8921                         this._maskMsg.remove();
8922                         delete this._maskMsg;
8923                     }
8924                 }else{
8925                     this._mask.setDisplayed(false);
8926                     if(this._maskMsg){
8927                         this._maskMsg.setDisplayed(false);
8928                     }
8929                 }
8930             }
8931             this.removeClass("x-masked");
8932         },
8933
8934         /**
8935          * Returns true if this element is masked
8936          * @return {Boolean}
8937          */
8938         isMasked : function(){
8939             return this._mask && this._mask.isVisible();
8940         },
8941
8942         /**
8943          * Creates an iframe shim for this element to keep selects and other windowed objects from
8944          * showing through.
8945          * @return {Roo.Element} The new shim element
8946          */
8947         createShim : function(){
8948             var el = document.createElement('iframe');
8949             el.frameBorder = 'no';
8950             el.className = 'roo-shim';
8951             if(Roo.isIE && Roo.isSecure){
8952                 el.src = Roo.SSL_SECURE_URL;
8953             }
8954             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8955             shim.autoBoxAdjust = false;
8956             return shim;
8957         },
8958
8959         /**
8960          * Removes this element from the DOM and deletes it from the cache
8961          */
8962         remove : function(){
8963             if(this.dom.parentNode){
8964                 this.dom.parentNode.removeChild(this.dom);
8965             }
8966             delete El.cache[this.dom.id];
8967         },
8968
8969         /**
8970          * Sets up event handlers to add and remove a css class when the mouse is over this element
8971          * @param {String} className
8972          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8973          * mouseout events for children elements
8974          * @return {Roo.Element} this
8975          */
8976         addClassOnOver : function(className, preventFlicker){
8977             this.on("mouseover", function(){
8978                 Roo.fly(this, '_internal').addClass(className);
8979             }, this.dom);
8980             var removeFn = function(e){
8981                 if(preventFlicker !== true || !e.within(this, true)){
8982                     Roo.fly(this, '_internal').removeClass(className);
8983                 }
8984             };
8985             this.on("mouseout", removeFn, this.dom);
8986             return this;
8987         },
8988
8989         /**
8990          * Sets up event handlers to add and remove a css class when this element has the focus
8991          * @param {String} className
8992          * @return {Roo.Element} this
8993          */
8994         addClassOnFocus : function(className){
8995             this.on("focus", function(){
8996                 Roo.fly(this, '_internal').addClass(className);
8997             }, this.dom);
8998             this.on("blur", function(){
8999                 Roo.fly(this, '_internal').removeClass(className);
9000             }, this.dom);
9001             return this;
9002         },
9003         /**
9004          * 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)
9005          * @param {String} className
9006          * @return {Roo.Element} this
9007          */
9008         addClassOnClick : function(className){
9009             var dom = this.dom;
9010             this.on("mousedown", function(){
9011                 Roo.fly(dom, '_internal').addClass(className);
9012                 var d = Roo.get(document);
9013                 var fn = function(){
9014                     Roo.fly(dom, '_internal').removeClass(className);
9015                     d.removeListener("mouseup", fn);
9016                 };
9017                 d.on("mouseup", fn);
9018             });
9019             return this;
9020         },
9021
9022         /**
9023          * Stops the specified event from bubbling and optionally prevents the default action
9024          * @param {String} eventName
9025          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9026          * @return {Roo.Element} this
9027          */
9028         swallowEvent : function(eventName, preventDefault){
9029             var fn = function(e){
9030                 e.stopPropagation();
9031                 if(preventDefault){
9032                     e.preventDefault();
9033                 }
9034             };
9035             if(eventName instanceof Array){
9036                 for(var i = 0, len = eventName.length; i < len; i++){
9037                      this.on(eventName[i], fn);
9038                 }
9039                 return this;
9040             }
9041             this.on(eventName, fn);
9042             return this;
9043         },
9044
9045         /**
9046          * @private
9047          */
9048       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9049
9050         /**
9051          * Sizes this element to its parent element's dimensions performing
9052          * neccessary box adjustments.
9053          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9054          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9055          * @return {Roo.Element} this
9056          */
9057         fitToParent : function(monitorResize, targetParent) {
9058           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9059           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9060           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9061             return;
9062           }
9063           var p = Roo.get(targetParent || this.dom.parentNode);
9064           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9065           if (monitorResize === true) {
9066             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9067             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9068           }
9069           return this;
9070         },
9071
9072         /**
9073          * Gets the next sibling, skipping text nodes
9074          * @return {HTMLElement} The next sibling or null
9075          */
9076         getNextSibling : function(){
9077             var n = this.dom.nextSibling;
9078             while(n && n.nodeType != 1){
9079                 n = n.nextSibling;
9080             }
9081             return n;
9082         },
9083
9084         /**
9085          * Gets the previous sibling, skipping text nodes
9086          * @return {HTMLElement} The previous sibling or null
9087          */
9088         getPrevSibling : function(){
9089             var n = this.dom.previousSibling;
9090             while(n && n.nodeType != 1){
9091                 n = n.previousSibling;
9092             }
9093             return n;
9094         },
9095
9096
9097         /**
9098          * Appends the passed element(s) to this element
9099          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9100          * @return {Roo.Element} this
9101          */
9102         appendChild: function(el){
9103             el = Roo.get(el);
9104             el.appendTo(this);
9105             return this;
9106         },
9107
9108         /**
9109          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9110          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9111          * automatically generated with the specified attributes.
9112          * @param {HTMLElement} insertBefore (optional) a child element of this element
9113          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9114          * @return {Roo.Element} The new child element
9115          */
9116         createChild: function(config, insertBefore, returnDom){
9117             config = config || {tag:'div'};
9118             if(insertBefore){
9119                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9120             }
9121             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9122         },
9123
9124         /**
9125          * Appends this element to the passed element
9126          * @param {String/HTMLElement/Element} el The new parent element
9127          * @return {Roo.Element} this
9128          */
9129         appendTo: function(el){
9130             el = Roo.getDom(el);
9131             el.appendChild(this.dom);
9132             return this;
9133         },
9134
9135         /**
9136          * Inserts this element before the passed element in the DOM
9137          * @param {String/HTMLElement/Element} el The element to insert before
9138          * @return {Roo.Element} this
9139          */
9140         insertBefore: function(el){
9141             el = Roo.getDom(el);
9142             el.parentNode.insertBefore(this.dom, el);
9143             return this;
9144         },
9145
9146         /**
9147          * Inserts this element after the passed element in the DOM
9148          * @param {String/HTMLElement/Element} el The element to insert after
9149          * @return {Roo.Element} this
9150          */
9151         insertAfter: function(el){
9152             el = Roo.getDom(el);
9153             el.parentNode.insertBefore(this.dom, el.nextSibling);
9154             return this;
9155         },
9156
9157         /**
9158          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9159          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9160          * @return {Roo.Element} The new child
9161          */
9162         insertFirst: function(el, returnDom){
9163             el = el || {};
9164             if(typeof el == 'object' && !el.nodeType){ // dh config
9165                 return this.createChild(el, this.dom.firstChild, returnDom);
9166             }else{
9167                 el = Roo.getDom(el);
9168                 this.dom.insertBefore(el, this.dom.firstChild);
9169                 return !returnDom ? Roo.get(el) : el;
9170             }
9171         },
9172
9173         /**
9174          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9175          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9176          * @param {String} where (optional) 'before' or 'after' defaults to before
9177          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9178          * @return {Roo.Element} the inserted Element
9179          */
9180         insertSibling: function(el, where, returnDom){
9181             where = where ? where.toLowerCase() : 'before';
9182             el = el || {};
9183             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9184
9185             if(typeof el == 'object' && !el.nodeType){ // dh config
9186                 if(where == 'after' && !this.dom.nextSibling){
9187                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9188                 }else{
9189                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9190                 }
9191
9192             }else{
9193                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9194                             where == 'before' ? this.dom : this.dom.nextSibling);
9195                 if(!returnDom){
9196                     rt = Roo.get(rt);
9197                 }
9198             }
9199             return rt;
9200         },
9201
9202         /**
9203          * Creates and wraps this element with another element
9204          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9205          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9206          * @return {HTMLElement/Element} The newly created wrapper element
9207          */
9208         wrap: function(config, returnDom){
9209             if(!config){
9210                 config = {tag: "div"};
9211             }
9212             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9213             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9214             return newEl;
9215         },
9216
9217         /**
9218          * Replaces the passed element with this element
9219          * @param {String/HTMLElement/Element} el The element to replace
9220          * @return {Roo.Element} this
9221          */
9222         replace: function(el){
9223             el = Roo.get(el);
9224             this.insertBefore(el);
9225             el.remove();
9226             return this;
9227         },
9228
9229         /**
9230          * Inserts an html fragment into this element
9231          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9232          * @param {String} html The HTML fragment
9233          * @param {Boolean} returnEl True to return an Roo.Element
9234          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9235          */
9236         insertHtml : function(where, html, returnEl){
9237             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9238             return returnEl ? Roo.get(el) : el;
9239         },
9240
9241         /**
9242          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9243          * @param {Object} o The object with the attributes
9244          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9245          * @return {Roo.Element} this
9246          */
9247         set : function(o, useSet){
9248             var el = this.dom;
9249             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9250             for(var attr in o){
9251                 if(attr == "style" || typeof o[attr] == "function") continue;
9252                 if(attr=="cls"){
9253                     el.className = o["cls"];
9254                 }else{
9255                     if(useSet) el.setAttribute(attr, o[attr]);
9256                     else el[attr] = o[attr];
9257                 }
9258             }
9259             if(o.style){
9260                 Roo.DomHelper.applyStyles(el, o.style);
9261             }
9262             return this;
9263         },
9264
9265         /**
9266          * Convenience method for constructing a KeyMap
9267          * @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:
9268          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9269          * @param {Function} fn The function to call
9270          * @param {Object} scope (optional) The scope of the function
9271          * @return {Roo.KeyMap} The KeyMap created
9272          */
9273         addKeyListener : function(key, fn, scope){
9274             var config;
9275             if(typeof key != "object" || key instanceof Array){
9276                 config = {
9277                     key: key,
9278                     fn: fn,
9279                     scope: scope
9280                 };
9281             }else{
9282                 config = {
9283                     key : key.key,
9284                     shift : key.shift,
9285                     ctrl : key.ctrl,
9286                     alt : key.alt,
9287                     fn: fn,
9288                     scope: scope
9289                 };
9290             }
9291             return new Roo.KeyMap(this, config);
9292         },
9293
9294         /**
9295          * Creates a KeyMap for this element
9296          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9297          * @return {Roo.KeyMap} The KeyMap created
9298          */
9299         addKeyMap : function(config){
9300             return new Roo.KeyMap(this, config);
9301         },
9302
9303         /**
9304          * Returns true if this element is scrollable.
9305          * @return {Boolean}
9306          */
9307          isScrollable : function(){
9308             var dom = this.dom;
9309             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9310         },
9311
9312         /**
9313          * 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().
9314          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9315          * @param {Number} value The new scroll value
9316          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9317          * @return {Element} this
9318          */
9319
9320         scrollTo : function(side, value, animate){
9321             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9322             if(!animate || !A){
9323                 this.dom[prop] = value;
9324             }else{
9325                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9326                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9327             }
9328             return this;
9329         },
9330
9331         /**
9332          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9333          * within this element's scrollable range.
9334          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9335          * @param {Number} distance How far to scroll the element in pixels
9336          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9337          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9338          * was scrolled as far as it could go.
9339          */
9340          scroll : function(direction, distance, animate){
9341              if(!this.isScrollable()){
9342                  return;
9343              }
9344              var el = this.dom;
9345              var l = el.scrollLeft, t = el.scrollTop;
9346              var w = el.scrollWidth, h = el.scrollHeight;
9347              var cw = el.clientWidth, ch = el.clientHeight;
9348              direction = direction.toLowerCase();
9349              var scrolled = false;
9350              var a = this.preanim(arguments, 2);
9351              switch(direction){
9352                  case "l":
9353                  case "left":
9354                      if(w - l > cw){
9355                          var v = Math.min(l + distance, w-cw);
9356                          this.scrollTo("left", v, a);
9357                          scrolled = true;
9358                      }
9359                      break;
9360                 case "r":
9361                 case "right":
9362                      if(l > 0){
9363                          var v = Math.max(l - distance, 0);
9364                          this.scrollTo("left", v, a);
9365                          scrolled = true;
9366                      }
9367                      break;
9368                 case "t":
9369                 case "top":
9370                 case "up":
9371                      if(t > 0){
9372                          var v = Math.max(t - distance, 0);
9373                          this.scrollTo("top", v, a);
9374                          scrolled = true;
9375                      }
9376                      break;
9377                 case "b":
9378                 case "bottom":
9379                 case "down":
9380                      if(h - t > ch){
9381                          var v = Math.min(t + distance, h-ch);
9382                          this.scrollTo("top", v, a);
9383                          scrolled = true;
9384                      }
9385                      break;
9386              }
9387              return scrolled;
9388         },
9389
9390         /**
9391          * Translates the passed page coordinates into left/top css values for this element
9392          * @param {Number/Array} x The page x or an array containing [x, y]
9393          * @param {Number} y The page y
9394          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9395          */
9396         translatePoints : function(x, y){
9397             if(typeof x == 'object' || x instanceof Array){
9398                 y = x[1]; x = x[0];
9399             }
9400             var p = this.getStyle('position');
9401             var o = this.getXY();
9402
9403             var l = parseInt(this.getStyle('left'), 10);
9404             var t = parseInt(this.getStyle('top'), 10);
9405
9406             if(isNaN(l)){
9407                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9408             }
9409             if(isNaN(t)){
9410                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9411             }
9412
9413             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9414         },
9415
9416         /**
9417          * Returns the current scroll position of the element.
9418          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9419          */
9420         getScroll : function(){
9421             var d = this.dom, doc = document;
9422             if(d == doc || d == doc.body){
9423                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9424                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9425                 return {left: l, top: t};
9426             }else{
9427                 return {left: d.scrollLeft, top: d.scrollTop};
9428             }
9429         },
9430
9431         /**
9432          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9433          * are convert to standard 6 digit hex color.
9434          * @param {String} attr The css attribute
9435          * @param {String} defaultValue The default value to use when a valid color isn't found
9436          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9437          * YUI color anims.
9438          */
9439         getColor : function(attr, defaultValue, prefix){
9440             var v = this.getStyle(attr);
9441             if(!v || v == "transparent" || v == "inherit") {
9442                 return defaultValue;
9443             }
9444             var color = typeof prefix == "undefined" ? "#" : prefix;
9445             if(v.substr(0, 4) == "rgb("){
9446                 var rvs = v.slice(4, v.length -1).split(",");
9447                 for(var i = 0; i < 3; i++){
9448                     var h = parseInt(rvs[i]).toString(16);
9449                     if(h < 16){
9450                         h = "0" + h;
9451                     }
9452                     color += h;
9453                 }
9454             } else {
9455                 if(v.substr(0, 1) == "#"){
9456                     if(v.length == 4) {
9457                         for(var i = 1; i < 4; i++){
9458                             var c = v.charAt(i);
9459                             color +=  c + c;
9460                         }
9461                     }else if(v.length == 7){
9462                         color += v.substr(1);
9463                     }
9464                 }
9465             }
9466             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9467         },
9468
9469         /**
9470          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9471          * gradient background, rounded corners and a 4-way shadow.
9472          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9473          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9474          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9475          * @return {Roo.Element} this
9476          */
9477         boxWrap : function(cls){
9478             cls = cls || 'x-box';
9479             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9480             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9481             return el;
9482         },
9483
9484         /**
9485          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9486          * @param {String} namespace The namespace in which to look for the attribute
9487          * @param {String} name The attribute name
9488          * @return {String} The attribute value
9489          */
9490         getAttributeNS : Roo.isIE ? function(ns, name){
9491             var d = this.dom;
9492             var type = typeof d[ns+":"+name];
9493             if(type != 'undefined' && type != 'unknown'){
9494                 return d[ns+":"+name];
9495             }
9496             return d[name];
9497         } : function(ns, name){
9498             var d = this.dom;
9499             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9500         }
9501     };
9502
9503     var ep = El.prototype;
9504
9505     /**
9506      * Appends an event handler (Shorthand for addListener)
9507      * @param {String}   eventName     The type of event to append
9508      * @param {Function} fn        The method the event invokes
9509      * @param {Object} scope       (optional) The scope (this object) of the fn
9510      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9511      * @method
9512      */
9513     ep.on = ep.addListener;
9514         // backwards compat
9515     ep.mon = ep.addListener;
9516
9517     /**
9518      * Removes an event handler from this element (shorthand for removeListener)
9519      * @param {String} eventName the type of event to remove
9520      * @param {Function} fn the method the event invokes
9521      * @return {Roo.Element} this
9522      * @method
9523      */
9524     ep.un = ep.removeListener;
9525
9526     /**
9527      * true to automatically adjust width and height settings for box-model issues (default to true)
9528      */
9529     ep.autoBoxAdjust = true;
9530
9531     // private
9532     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9533
9534     // private
9535     El.addUnits = function(v, defaultUnit){
9536         if(v === "" || v == "auto"){
9537             return v;
9538         }
9539         if(v === undefined){
9540             return '';
9541         }
9542         if(typeof v == "number" || !El.unitPattern.test(v)){
9543             return v + (defaultUnit || 'px');
9544         }
9545         return v;
9546     };
9547
9548     // special markup used throughout Roo when box wrapping elements
9549     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>';
9550     /**
9551      * Visibility mode constant - Use visibility to hide element
9552      * @static
9553      * @type Number
9554      */
9555     El.VISIBILITY = 1;
9556     /**
9557      * Visibility mode constant - Use display to hide element
9558      * @static
9559      * @type Number
9560      */
9561     El.DISPLAY = 2;
9562
9563     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9564     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9565     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9566
9567
9568
9569     /**
9570      * @private
9571      */
9572     El.cache = {};
9573
9574     var docEl;
9575
9576     /**
9577      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9578      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9579      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9580      * @return {Element} The Element object
9581      * @static
9582      */
9583     El.get = function(el){
9584         var ex, elm, id;
9585         if(!el){ return null; }
9586         if(typeof el == "string"){ // element id
9587             if(!(elm = document.getElementById(el))){
9588                 return null;
9589             }
9590             if(ex = El.cache[el]){
9591                 ex.dom = elm;
9592             }else{
9593                 ex = El.cache[el] = new El(elm);
9594             }
9595             return ex;
9596         }else if(el.tagName){ // dom element
9597             if(!(id = el.id)){
9598                 id = Roo.id(el);
9599             }
9600             if(ex = El.cache[id]){
9601                 ex.dom = el;
9602             }else{
9603                 ex = El.cache[id] = new El(el);
9604             }
9605             return ex;
9606         }else if(el instanceof El){
9607             if(el != docEl){
9608                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9609                                                               // catch case where it hasn't been appended
9610                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9611             }
9612             return el;
9613         }else if(el.isComposite){
9614             return el;
9615         }else if(el instanceof Array){
9616             return El.select(el);
9617         }else if(el == document){
9618             // create a bogus element object representing the document object
9619             if(!docEl){
9620                 var f = function(){};
9621                 f.prototype = El.prototype;
9622                 docEl = new f();
9623                 docEl.dom = document;
9624             }
9625             return docEl;
9626         }
9627         return null;
9628     };
9629
9630     // private
9631     El.uncache = function(el){
9632         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9633             if(a[i]){
9634                 delete El.cache[a[i].id || a[i]];
9635             }
9636         }
9637     };
9638
9639     // private
9640     // Garbage collection - uncache elements/purge listeners on orphaned elements
9641     // so we don't hold a reference and cause the browser to retain them
9642     El.garbageCollect = function(){
9643         if(!Roo.enableGarbageCollector){
9644             clearInterval(El.collectorThread);
9645             return;
9646         }
9647         for(var eid in El.cache){
9648             var el = El.cache[eid], d = el.dom;
9649             // -------------------------------------------------------
9650             // Determining what is garbage:
9651             // -------------------------------------------------------
9652             // !d
9653             // dom node is null, definitely garbage
9654             // -------------------------------------------------------
9655             // !d.parentNode
9656             // no parentNode == direct orphan, definitely garbage
9657             // -------------------------------------------------------
9658             // !d.offsetParent && !document.getElementById(eid)
9659             // display none elements have no offsetParent so we will
9660             // also try to look it up by it's id. However, check
9661             // offsetParent first so we don't do unneeded lookups.
9662             // This enables collection of elements that are not orphans
9663             // directly, but somewhere up the line they have an orphan
9664             // parent.
9665             // -------------------------------------------------------
9666             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9667                 delete El.cache[eid];
9668                 if(d && Roo.enableListenerCollection){
9669                     E.purgeElement(d);
9670                 }
9671             }
9672         }
9673     }
9674     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9675
9676
9677     // dom is optional
9678     El.Flyweight = function(dom){
9679         this.dom = dom;
9680     };
9681     El.Flyweight.prototype = El.prototype;
9682
9683     El._flyweights = {};
9684     /**
9685      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9686      * the dom node can be overwritten by other code.
9687      * @param {String/HTMLElement} el The dom node or id
9688      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9689      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9690      * @static
9691      * @return {Element} The shared Element object
9692      */
9693     El.fly = function(el, named){
9694         named = named || '_global';
9695         el = Roo.getDom(el);
9696         if(!el){
9697             return null;
9698         }
9699         if(!El._flyweights[named]){
9700             El._flyweights[named] = new El.Flyweight();
9701         }
9702         El._flyweights[named].dom = el;
9703         return El._flyweights[named];
9704     };
9705
9706     /**
9707      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9708      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9709      * Shorthand of {@link Roo.Element#get}
9710      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9711      * @return {Element} The Element object
9712      * @member Roo
9713      * @method get
9714      */
9715     Roo.get = El.get;
9716     /**
9717      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9718      * the dom node can be overwritten by other code.
9719      * Shorthand of {@link Roo.Element#fly}
9720      * @param {String/HTMLElement} el The dom node or id
9721      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9722      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9723      * @static
9724      * @return {Element} The shared Element object
9725      * @member Roo
9726      * @method fly
9727      */
9728     Roo.fly = El.fly;
9729
9730     // speedy lookup for elements never to box adjust
9731     var noBoxAdjust = Roo.isStrict ? {
9732         select:1
9733     } : {
9734         input:1, select:1, textarea:1
9735     };
9736     if(Roo.isIE || Roo.isGecko){
9737         noBoxAdjust['button'] = 1;
9738     }
9739
9740
9741     Roo.EventManager.on(window, 'unload', function(){
9742         delete El.cache;
9743         delete El._flyweights;
9744     });
9745 })();
9746
9747
9748
9749
9750 if(Roo.DomQuery){
9751     Roo.Element.selectorFunction = Roo.DomQuery.select;
9752 }
9753
9754 Roo.Element.select = function(selector, unique, root){
9755     var els;
9756     if(typeof selector == "string"){
9757         els = Roo.Element.selectorFunction(selector, root);
9758     }else if(selector.length !== undefined){
9759         els = selector;
9760     }else{
9761         throw "Invalid selector";
9762     }
9763     if(unique === true){
9764         return new Roo.CompositeElement(els);
9765     }else{
9766         return new Roo.CompositeElementLite(els);
9767     }
9768 };
9769 /**
9770  * Selects elements based on the passed CSS selector to enable working on them as 1.
9771  * @param {String/Array} selector The CSS selector or an array of elements
9772  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9773  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9774  * @return {CompositeElementLite/CompositeElement}
9775  * @member Roo
9776  * @method select
9777  */
9778 Roo.select = Roo.Element.select;
9779
9780
9781
9782
9783
9784
9785
9786
9787
9788
9789
9790
9791
9792
9793 /*
9794  * Based on:
9795  * Ext JS Library 1.1.1
9796  * Copyright(c) 2006-2007, Ext JS, LLC.
9797  *
9798  * Originally Released Under LGPL - original licence link has changed is not relivant.
9799  *
9800  * Fork - LGPL
9801  * <script type="text/javascript">
9802  */
9803
9804
9805
9806 //Notifies Element that fx methods are available
9807 Roo.enableFx = true;
9808
9809 /**
9810  * @class Roo.Fx
9811  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9812  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9813  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9814  * Element effects to work.</p><br/>
9815  *
9816  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9817  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9818  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9819  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9820  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9821  * expected results and should be done with care.</p><br/>
9822  *
9823  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9824  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9825 <pre>
9826 Value  Description
9827 -----  -----------------------------
9828 tl     The top left corner
9829 t      The center of the top edge
9830 tr     The top right corner
9831 l      The center of the left edge
9832 r      The center of the right edge
9833 bl     The bottom left corner
9834 b      The center of the bottom edge
9835 br     The bottom right corner
9836 </pre>
9837  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9838  * below are common options that can be passed to any Fx method.</b>
9839  * @cfg {Function} callback A function called when the effect is finished
9840  * @cfg {Object} scope The scope of the effect function
9841  * @cfg {String} easing A valid Easing value for the effect
9842  * @cfg {String} afterCls A css class to apply after the effect
9843  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9844  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9845  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9846  * effects that end with the element being visually hidden, ignored otherwise)
9847  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9848  * a function which returns such a specification that will be applied to the Element after the effect finishes
9849  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9850  * @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
9851  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9852  */
9853 Roo.Fx = {
9854         /**
9855          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9856          * origin for the slide effect.  This function automatically handles wrapping the element with
9857          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9858          * Usage:
9859          *<pre><code>
9860 // default: slide the element in from the top
9861 el.slideIn();
9862
9863 // custom: slide the element in from the right with a 2-second duration
9864 el.slideIn('r', { duration: 2 });
9865
9866 // common config options shown with default values
9867 el.slideIn('t', {
9868     easing: 'easeOut',
9869     duration: .5
9870 });
9871 </code></pre>
9872          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9873          * @param {Object} options (optional) Object literal with any of the Fx config options
9874          * @return {Roo.Element} The Element
9875          */
9876     slideIn : function(anchor, o){
9877         var el = this.getFxEl();
9878         o = o || {};
9879
9880         el.queueFx(o, function(){
9881
9882             anchor = anchor || "t";
9883
9884             // fix display to visibility
9885             this.fixDisplay();
9886
9887             // restore values after effect
9888             var r = this.getFxRestore();
9889             var b = this.getBox();
9890             // fixed size for slide
9891             this.setSize(b);
9892
9893             // wrap if needed
9894             var wrap = this.fxWrap(r.pos, o, "hidden");
9895
9896             var st = this.dom.style;
9897             st.visibility = "visible";
9898             st.position = "absolute";
9899
9900             // clear out temp styles after slide and unwrap
9901             var after = function(){
9902                 el.fxUnwrap(wrap, r.pos, o);
9903                 st.width = r.width;
9904                 st.height = r.height;
9905                 el.afterFx(o);
9906             };
9907             // time to calc the positions
9908             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9909
9910             switch(anchor.toLowerCase()){
9911                 case "t":
9912                     wrap.setSize(b.width, 0);
9913                     st.left = st.bottom = "0";
9914                     a = {height: bh};
9915                 break;
9916                 case "l":
9917                     wrap.setSize(0, b.height);
9918                     st.right = st.top = "0";
9919                     a = {width: bw};
9920                 break;
9921                 case "r":
9922                     wrap.setSize(0, b.height);
9923                     wrap.setX(b.right);
9924                     st.left = st.top = "0";
9925                     a = {width: bw, points: pt};
9926                 break;
9927                 case "b":
9928                     wrap.setSize(b.width, 0);
9929                     wrap.setY(b.bottom);
9930                     st.left = st.top = "0";
9931                     a = {height: bh, points: pt};
9932                 break;
9933                 case "tl":
9934                     wrap.setSize(0, 0);
9935                     st.right = st.bottom = "0";
9936                     a = {width: bw, height: bh};
9937                 break;
9938                 case "bl":
9939                     wrap.setSize(0, 0);
9940                     wrap.setY(b.y+b.height);
9941                     st.right = st.top = "0";
9942                     a = {width: bw, height: bh, points: pt};
9943                 break;
9944                 case "br":
9945                     wrap.setSize(0, 0);
9946                     wrap.setXY([b.right, b.bottom]);
9947                     st.left = st.top = "0";
9948                     a = {width: bw, height: bh, points: pt};
9949                 break;
9950                 case "tr":
9951                     wrap.setSize(0, 0);
9952                     wrap.setX(b.x+b.width);
9953                     st.left = st.bottom = "0";
9954                     a = {width: bw, height: bh, points: pt};
9955                 break;
9956             }
9957             this.dom.style.visibility = "visible";
9958             wrap.show();
9959
9960             arguments.callee.anim = wrap.fxanim(a,
9961                 o,
9962                 'motion',
9963                 .5,
9964                 'easeOut', after);
9965         });
9966         return this;
9967     },
9968     
9969         /**
9970          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9971          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9972          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9973          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9974          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9975          * Usage:
9976          *<pre><code>
9977 // default: slide the element out to the top
9978 el.slideOut();
9979
9980 // custom: slide the element out to the right with a 2-second duration
9981 el.slideOut('r', { duration: 2 });
9982
9983 // common config options shown with default values
9984 el.slideOut('t', {
9985     easing: 'easeOut',
9986     duration: .5,
9987     remove: false,
9988     useDisplay: false
9989 });
9990 </code></pre>
9991          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9992          * @param {Object} options (optional) Object literal with any of the Fx config options
9993          * @return {Roo.Element} The Element
9994          */
9995     slideOut : function(anchor, o){
9996         var el = this.getFxEl();
9997         o = o || {};
9998
9999         el.queueFx(o, function(){
10000
10001             anchor = anchor || "t";
10002
10003             // restore values after effect
10004             var r = this.getFxRestore();
10005             
10006             var b = this.getBox();
10007             // fixed size for slide
10008             this.setSize(b);
10009
10010             // wrap if needed
10011             var wrap = this.fxWrap(r.pos, o, "visible");
10012
10013             var st = this.dom.style;
10014             st.visibility = "visible";
10015             st.position = "absolute";
10016
10017             wrap.setSize(b);
10018
10019             var after = function(){
10020                 if(o.useDisplay){
10021                     el.setDisplayed(false);
10022                 }else{
10023                     el.hide();
10024                 }
10025
10026                 el.fxUnwrap(wrap, r.pos, o);
10027
10028                 st.width = r.width;
10029                 st.height = r.height;
10030
10031                 el.afterFx(o);
10032             };
10033
10034             var a, zero = {to: 0};
10035             switch(anchor.toLowerCase()){
10036                 case "t":
10037                     st.left = st.bottom = "0";
10038                     a = {height: zero};
10039                 break;
10040                 case "l":
10041                     st.right = st.top = "0";
10042                     a = {width: zero};
10043                 break;
10044                 case "r":
10045                     st.left = st.top = "0";
10046                     a = {width: zero, points: {to:[b.right, b.y]}};
10047                 break;
10048                 case "b":
10049                     st.left = st.top = "0";
10050                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10051                 break;
10052                 case "tl":
10053                     st.right = st.bottom = "0";
10054                     a = {width: zero, height: zero};
10055                 break;
10056                 case "bl":
10057                     st.right = st.top = "0";
10058                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10059                 break;
10060                 case "br":
10061                     st.left = st.top = "0";
10062                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10063                 break;
10064                 case "tr":
10065                     st.left = st.bottom = "0";
10066                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10067                 break;
10068             }
10069
10070             arguments.callee.anim = wrap.fxanim(a,
10071                 o,
10072                 'motion',
10073                 .5,
10074                 "easeOut", after);
10075         });
10076         return this;
10077     },
10078
10079         /**
10080          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10081          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10082          * The element must be removed from the DOM using the 'remove' config option if desired.
10083          * Usage:
10084          *<pre><code>
10085 // default
10086 el.puff();
10087
10088 // common config options shown with default values
10089 el.puff({
10090     easing: 'easeOut',
10091     duration: .5,
10092     remove: false,
10093     useDisplay: false
10094 });
10095 </code></pre>
10096          * @param {Object} options (optional) Object literal with any of the Fx config options
10097          * @return {Roo.Element} The Element
10098          */
10099     puff : function(o){
10100         var el = this.getFxEl();
10101         o = o || {};
10102
10103         el.queueFx(o, function(){
10104             this.clearOpacity();
10105             this.show();
10106
10107             // restore values after effect
10108             var r = this.getFxRestore();
10109             var st = this.dom.style;
10110
10111             var after = function(){
10112                 if(o.useDisplay){
10113                     el.setDisplayed(false);
10114                 }else{
10115                     el.hide();
10116                 }
10117
10118                 el.clearOpacity();
10119
10120                 el.setPositioning(r.pos);
10121                 st.width = r.width;
10122                 st.height = r.height;
10123                 st.fontSize = '';
10124                 el.afterFx(o);
10125             };
10126
10127             var width = this.getWidth();
10128             var height = this.getHeight();
10129
10130             arguments.callee.anim = this.fxanim({
10131                     width : {to: this.adjustWidth(width * 2)},
10132                     height : {to: this.adjustHeight(height * 2)},
10133                     points : {by: [-(width * .5), -(height * .5)]},
10134                     opacity : {to: 0},
10135                     fontSize: {to:200, unit: "%"}
10136                 },
10137                 o,
10138                 'motion',
10139                 .5,
10140                 "easeOut", after);
10141         });
10142         return this;
10143     },
10144
10145         /**
10146          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10147          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10148          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10149          * Usage:
10150          *<pre><code>
10151 // default
10152 el.switchOff();
10153
10154 // all config options shown with default values
10155 el.switchOff({
10156     easing: 'easeIn',
10157     duration: .3,
10158     remove: false,
10159     useDisplay: false
10160 });
10161 </code></pre>
10162          * @param {Object} options (optional) Object literal with any of the Fx config options
10163          * @return {Roo.Element} The Element
10164          */
10165     switchOff : function(o){
10166         var el = this.getFxEl();
10167         o = o || {};
10168
10169         el.queueFx(o, function(){
10170             this.clearOpacity();
10171             this.clip();
10172
10173             // restore values after effect
10174             var r = this.getFxRestore();
10175             var st = this.dom.style;
10176
10177             var after = function(){
10178                 if(o.useDisplay){
10179                     el.setDisplayed(false);
10180                 }else{
10181                     el.hide();
10182                 }
10183
10184                 el.clearOpacity();
10185                 el.setPositioning(r.pos);
10186                 st.width = r.width;
10187                 st.height = r.height;
10188
10189                 el.afterFx(o);
10190             };
10191
10192             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10193                 this.clearOpacity();
10194                 (function(){
10195                     this.fxanim({
10196                         height:{to:1},
10197                         points:{by:[0, this.getHeight() * .5]}
10198                     }, o, 'motion', 0.3, 'easeIn', after);
10199                 }).defer(100, this);
10200             });
10201         });
10202         return this;
10203     },
10204
10205     /**
10206      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10207      * changed using the "attr" config option) and then fading back to the original color. If no original
10208      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10209      * Usage:
10210 <pre><code>
10211 // default: highlight background to yellow
10212 el.highlight();
10213
10214 // custom: highlight foreground text to blue for 2 seconds
10215 el.highlight("0000ff", { attr: 'color', duration: 2 });
10216
10217 // common config options shown with default values
10218 el.highlight("ffff9c", {
10219     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10220     endColor: (current color) or "ffffff",
10221     easing: 'easeIn',
10222     duration: 1
10223 });
10224 </code></pre>
10225      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10226      * @param {Object} options (optional) Object literal with any of the Fx config options
10227      * @return {Roo.Element} The Element
10228      */ 
10229     highlight : function(color, o){
10230         var el = this.getFxEl();
10231         o = o || {};
10232
10233         el.queueFx(o, function(){
10234             color = color || "ffff9c";
10235             attr = o.attr || "backgroundColor";
10236
10237             this.clearOpacity();
10238             this.show();
10239
10240             var origColor = this.getColor(attr);
10241             var restoreColor = this.dom.style[attr];
10242             endColor = (o.endColor || origColor) || "ffffff";
10243
10244             var after = function(){
10245                 el.dom.style[attr] = restoreColor;
10246                 el.afterFx(o);
10247             };
10248
10249             var a = {};
10250             a[attr] = {from: color, to: endColor};
10251             arguments.callee.anim = this.fxanim(a,
10252                 o,
10253                 'color',
10254                 1,
10255                 'easeIn', after);
10256         });
10257         return this;
10258     },
10259
10260    /**
10261     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10262     * Usage:
10263 <pre><code>
10264 // default: a single light blue ripple
10265 el.frame();
10266
10267 // custom: 3 red ripples lasting 3 seconds total
10268 el.frame("ff0000", 3, { duration: 3 });
10269
10270 // common config options shown with default values
10271 el.frame("C3DAF9", 1, {
10272     duration: 1 //duration of entire animation (not each individual ripple)
10273     // Note: Easing is not configurable and will be ignored if included
10274 });
10275 </code></pre>
10276     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10277     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10278     * @param {Object} options (optional) Object literal with any of the Fx config options
10279     * @return {Roo.Element} The Element
10280     */
10281     frame : function(color, count, o){
10282         var el = this.getFxEl();
10283         o = o || {};
10284
10285         el.queueFx(o, function(){
10286             color = color || "#C3DAF9";
10287             if(color.length == 6){
10288                 color = "#" + color;
10289             }
10290             count = count || 1;
10291             duration = o.duration || 1;
10292             this.show();
10293
10294             var b = this.getBox();
10295             var animFn = function(){
10296                 var proxy = this.createProxy({
10297
10298                      style:{
10299                         visbility:"hidden",
10300                         position:"absolute",
10301                         "z-index":"35000", // yee haw
10302                         border:"0px solid " + color
10303                      }
10304                   });
10305                 var scale = Roo.isBorderBox ? 2 : 1;
10306                 proxy.animate({
10307                     top:{from:b.y, to:b.y - 20},
10308                     left:{from:b.x, to:b.x - 20},
10309                     borderWidth:{from:0, to:10},
10310                     opacity:{from:1, to:0},
10311                     height:{from:b.height, to:(b.height + (20*scale))},
10312                     width:{from:b.width, to:(b.width + (20*scale))}
10313                 }, duration, function(){
10314                     proxy.remove();
10315                 });
10316                 if(--count > 0){
10317                      animFn.defer((duration/2)*1000, this);
10318                 }else{
10319                     el.afterFx(o);
10320                 }
10321             };
10322             animFn.call(this);
10323         });
10324         return this;
10325     },
10326
10327    /**
10328     * Creates a pause before any subsequent queued effects begin.  If there are
10329     * no effects queued after the pause it will have no effect.
10330     * Usage:
10331 <pre><code>
10332 el.pause(1);
10333 </code></pre>
10334     * @param {Number} seconds The length of time to pause (in seconds)
10335     * @return {Roo.Element} The Element
10336     */
10337     pause : function(seconds){
10338         var el = this.getFxEl();
10339         var o = {};
10340
10341         el.queueFx(o, function(){
10342             setTimeout(function(){
10343                 el.afterFx(o);
10344             }, seconds * 1000);
10345         });
10346         return this;
10347     },
10348
10349    /**
10350     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10351     * using the "endOpacity" config option.
10352     * Usage:
10353 <pre><code>
10354 // default: fade in from opacity 0 to 100%
10355 el.fadeIn();
10356
10357 // custom: fade in from opacity 0 to 75% over 2 seconds
10358 el.fadeIn({ endOpacity: .75, duration: 2});
10359
10360 // common config options shown with default values
10361 el.fadeIn({
10362     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10363     easing: 'easeOut',
10364     duration: .5
10365 });
10366 </code></pre>
10367     * @param {Object} options (optional) Object literal with any of the Fx config options
10368     * @return {Roo.Element} The Element
10369     */
10370     fadeIn : function(o){
10371         var el = this.getFxEl();
10372         o = o || {};
10373         el.queueFx(o, function(){
10374             this.setOpacity(0);
10375             this.fixDisplay();
10376             this.dom.style.visibility = 'visible';
10377             var to = o.endOpacity || 1;
10378             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10379                 o, null, .5, "easeOut", function(){
10380                 if(to == 1){
10381                     this.clearOpacity();
10382                 }
10383                 el.afterFx(o);
10384             });
10385         });
10386         return this;
10387     },
10388
10389    /**
10390     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10391     * using the "endOpacity" config option.
10392     * Usage:
10393 <pre><code>
10394 // default: fade out from the element's current opacity to 0
10395 el.fadeOut();
10396
10397 // custom: fade out from the element's current opacity to 25% over 2 seconds
10398 el.fadeOut({ endOpacity: .25, duration: 2});
10399
10400 // common config options shown with default values
10401 el.fadeOut({
10402     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10403     easing: 'easeOut',
10404     duration: .5
10405     remove: false,
10406     useDisplay: false
10407 });
10408 </code></pre>
10409     * @param {Object} options (optional) Object literal with any of the Fx config options
10410     * @return {Roo.Element} The Element
10411     */
10412     fadeOut : function(o){
10413         var el = this.getFxEl();
10414         o = o || {};
10415         el.queueFx(o, function(){
10416             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10417                 o, null, .5, "easeOut", function(){
10418                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10419                      this.dom.style.display = "none";
10420                 }else{
10421                      this.dom.style.visibility = "hidden";
10422                 }
10423                 this.clearOpacity();
10424                 el.afterFx(o);
10425             });
10426         });
10427         return this;
10428     },
10429
10430    /**
10431     * Animates the transition of an element's dimensions from a starting height/width
10432     * to an ending height/width.
10433     * Usage:
10434 <pre><code>
10435 // change height and width to 100x100 pixels
10436 el.scale(100, 100);
10437
10438 // common config options shown with default values.  The height and width will default to
10439 // the element's existing values if passed as null.
10440 el.scale(
10441     [element's width],
10442     [element's height], {
10443     easing: 'easeOut',
10444     duration: .35
10445 });
10446 </code></pre>
10447     * @param {Number} width  The new width (pass undefined to keep the original width)
10448     * @param {Number} height  The new height (pass undefined to keep the original height)
10449     * @param {Object} options (optional) Object literal with any of the Fx config options
10450     * @return {Roo.Element} The Element
10451     */
10452     scale : function(w, h, o){
10453         this.shift(Roo.apply({}, o, {
10454             width: w,
10455             height: h
10456         }));
10457         return this;
10458     },
10459
10460    /**
10461     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10462     * Any of these properties not specified in the config object will not be changed.  This effect 
10463     * requires that at least one new dimension, position or opacity setting must be passed in on
10464     * the config object in order for the function to have any effect.
10465     * Usage:
10466 <pre><code>
10467 // slide the element horizontally to x position 200 while changing the height and opacity
10468 el.shift({ x: 200, height: 50, opacity: .8 });
10469
10470 // common config options shown with default values.
10471 el.shift({
10472     width: [element's width],
10473     height: [element's height],
10474     x: [element's x position],
10475     y: [element's y position],
10476     opacity: [element's opacity],
10477     easing: 'easeOut',
10478     duration: .35
10479 });
10480 </code></pre>
10481     * @param {Object} options  Object literal with any of the Fx config options
10482     * @return {Roo.Element} The Element
10483     */
10484     shift : function(o){
10485         var el = this.getFxEl();
10486         o = o || {};
10487         el.queueFx(o, function(){
10488             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10489             if(w !== undefined){
10490                 a.width = {to: this.adjustWidth(w)};
10491             }
10492             if(h !== undefined){
10493                 a.height = {to: this.adjustHeight(h)};
10494             }
10495             if(x !== undefined || y !== undefined){
10496                 a.points = {to: [
10497                     x !== undefined ? x : this.getX(),
10498                     y !== undefined ? y : this.getY()
10499                 ]};
10500             }
10501             if(op !== undefined){
10502                 a.opacity = {to: op};
10503             }
10504             if(o.xy !== undefined){
10505                 a.points = {to: o.xy};
10506             }
10507             arguments.callee.anim = this.fxanim(a,
10508                 o, 'motion', .35, "easeOut", function(){
10509                 el.afterFx(o);
10510             });
10511         });
10512         return this;
10513     },
10514
10515         /**
10516          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10517          * ending point of the effect.
10518          * Usage:
10519          *<pre><code>
10520 // default: slide the element downward while fading out
10521 el.ghost();
10522
10523 // custom: slide the element out to the right with a 2-second duration
10524 el.ghost('r', { duration: 2 });
10525
10526 // common config options shown with default values
10527 el.ghost('b', {
10528     easing: 'easeOut',
10529     duration: .5
10530     remove: false,
10531     useDisplay: false
10532 });
10533 </code></pre>
10534          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10535          * @param {Object} options (optional) Object literal with any of the Fx config options
10536          * @return {Roo.Element} The Element
10537          */
10538     ghost : function(anchor, o){
10539         var el = this.getFxEl();
10540         o = o || {};
10541
10542         el.queueFx(o, function(){
10543             anchor = anchor || "b";
10544
10545             // restore values after effect
10546             var r = this.getFxRestore();
10547             var w = this.getWidth(),
10548                 h = this.getHeight();
10549
10550             var st = this.dom.style;
10551
10552             var after = function(){
10553                 if(o.useDisplay){
10554                     el.setDisplayed(false);
10555                 }else{
10556                     el.hide();
10557                 }
10558
10559                 el.clearOpacity();
10560                 el.setPositioning(r.pos);
10561                 st.width = r.width;
10562                 st.height = r.height;
10563
10564                 el.afterFx(o);
10565             };
10566
10567             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10568             switch(anchor.toLowerCase()){
10569                 case "t":
10570                     pt.by = [0, -h];
10571                 break;
10572                 case "l":
10573                     pt.by = [-w, 0];
10574                 break;
10575                 case "r":
10576                     pt.by = [w, 0];
10577                 break;
10578                 case "b":
10579                     pt.by = [0, h];
10580                 break;
10581                 case "tl":
10582                     pt.by = [-w, -h];
10583                 break;
10584                 case "bl":
10585                     pt.by = [-w, h];
10586                 break;
10587                 case "br":
10588                     pt.by = [w, h];
10589                 break;
10590                 case "tr":
10591                     pt.by = [w, -h];
10592                 break;
10593             }
10594
10595             arguments.callee.anim = this.fxanim(a,
10596                 o,
10597                 'motion',
10598                 .5,
10599                 "easeOut", after);
10600         });
10601         return this;
10602     },
10603
10604         /**
10605          * Ensures that all effects queued after syncFx is called on the element are
10606          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10607          * @return {Roo.Element} The Element
10608          */
10609     syncFx : function(){
10610         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10611             block : false,
10612             concurrent : true,
10613             stopFx : false
10614         });
10615         return this;
10616     },
10617
10618         /**
10619          * Ensures that all effects queued after sequenceFx is called on the element are
10620          * run in sequence.  This is the opposite of {@link #syncFx}.
10621          * @return {Roo.Element} The Element
10622          */
10623     sequenceFx : function(){
10624         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10625             block : false,
10626             concurrent : false,
10627             stopFx : false
10628         });
10629         return this;
10630     },
10631
10632         /* @private */
10633     nextFx : function(){
10634         var ef = this.fxQueue[0];
10635         if(ef){
10636             ef.call(this);
10637         }
10638     },
10639
10640         /**
10641          * Returns true if the element has any effects actively running or queued, else returns false.
10642          * @return {Boolean} True if element has active effects, else false
10643          */
10644     hasActiveFx : function(){
10645         return this.fxQueue && this.fxQueue[0];
10646     },
10647
10648         /**
10649          * Stops any running effects and clears the element's internal effects queue if it contains
10650          * any additional effects that haven't started yet.
10651          * @return {Roo.Element} The Element
10652          */
10653     stopFx : function(){
10654         if(this.hasActiveFx()){
10655             var cur = this.fxQueue[0];
10656             if(cur && cur.anim && cur.anim.isAnimated()){
10657                 this.fxQueue = [cur]; // clear out others
10658                 cur.anim.stop(true);
10659             }
10660         }
10661         return this;
10662     },
10663
10664         /* @private */
10665     beforeFx : function(o){
10666         if(this.hasActiveFx() && !o.concurrent){
10667            if(o.stopFx){
10668                this.stopFx();
10669                return true;
10670            }
10671            return false;
10672         }
10673         return true;
10674     },
10675
10676         /**
10677          * Returns true if the element is currently blocking so that no other effect can be queued
10678          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10679          * used to ensure that an effect initiated by a user action runs to completion prior to the
10680          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10681          * @return {Boolean} True if blocking, else false
10682          */
10683     hasFxBlock : function(){
10684         var q = this.fxQueue;
10685         return q && q[0] && q[0].block;
10686     },
10687
10688         /* @private */
10689     queueFx : function(o, fn){
10690         if(!this.fxQueue){
10691             this.fxQueue = [];
10692         }
10693         if(!this.hasFxBlock()){
10694             Roo.applyIf(o, this.fxDefaults);
10695             if(!o.concurrent){
10696                 var run = this.beforeFx(o);
10697                 fn.block = o.block;
10698                 this.fxQueue.push(fn);
10699                 if(run){
10700                     this.nextFx();
10701                 }
10702             }else{
10703                 fn.call(this);
10704             }
10705         }
10706         return this;
10707     },
10708
10709         /* @private */
10710     fxWrap : function(pos, o, vis){
10711         var wrap;
10712         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10713             var wrapXY;
10714             if(o.fixPosition){
10715                 wrapXY = this.getXY();
10716             }
10717             var div = document.createElement("div");
10718             div.style.visibility = vis;
10719             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10720             wrap.setPositioning(pos);
10721             if(wrap.getStyle("position") == "static"){
10722                 wrap.position("relative");
10723             }
10724             this.clearPositioning('auto');
10725             wrap.clip();
10726             wrap.dom.appendChild(this.dom);
10727             if(wrapXY){
10728                 wrap.setXY(wrapXY);
10729             }
10730         }
10731         return wrap;
10732     },
10733
10734         /* @private */
10735     fxUnwrap : function(wrap, pos, o){
10736         this.clearPositioning();
10737         this.setPositioning(pos);
10738         if(!o.wrap){
10739             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10740             wrap.remove();
10741         }
10742     },
10743
10744         /* @private */
10745     getFxRestore : function(){
10746         var st = this.dom.style;
10747         return {pos: this.getPositioning(), width: st.width, height : st.height};
10748     },
10749
10750         /* @private */
10751     afterFx : function(o){
10752         if(o.afterStyle){
10753             this.applyStyles(o.afterStyle);
10754         }
10755         if(o.afterCls){
10756             this.addClass(o.afterCls);
10757         }
10758         if(o.remove === true){
10759             this.remove();
10760         }
10761         Roo.callback(o.callback, o.scope, [this]);
10762         if(!o.concurrent){
10763             this.fxQueue.shift();
10764             this.nextFx();
10765         }
10766     },
10767
10768         /* @private */
10769     getFxEl : function(){ // support for composite element fx
10770         return Roo.get(this.dom);
10771     },
10772
10773         /* @private */
10774     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10775         animType = animType || 'run';
10776         opt = opt || {};
10777         var anim = Roo.lib.Anim[animType](
10778             this.dom, args,
10779             (opt.duration || defaultDur) || .35,
10780             (opt.easing || defaultEase) || 'easeOut',
10781             function(){
10782                 Roo.callback(cb, this);
10783             },
10784             this
10785         );
10786         opt.anim = anim;
10787         return anim;
10788     }
10789 };
10790
10791 // backwords compat
10792 Roo.Fx.resize = Roo.Fx.scale;
10793
10794 //When included, Roo.Fx is automatically applied to Element so that all basic
10795 //effects are available directly via the Element API
10796 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10797  * Based on:
10798  * Ext JS Library 1.1.1
10799  * Copyright(c) 2006-2007, Ext JS, LLC.
10800  *
10801  * Originally Released Under LGPL - original licence link has changed is not relivant.
10802  *
10803  * Fork - LGPL
10804  * <script type="text/javascript">
10805  */
10806
10807
10808 /**
10809  * @class Roo.CompositeElement
10810  * Standard composite class. Creates a Roo.Element for every element in the collection.
10811  * <br><br>
10812  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10813  * actions will be performed on all the elements in this collection.</b>
10814  * <br><br>
10815  * All methods return <i>this</i> and can be chained.
10816  <pre><code>
10817  var els = Roo.select("#some-el div.some-class", true);
10818  // or select directly from an existing element
10819  var el = Roo.get('some-el');
10820  el.select('div.some-class', true);
10821
10822  els.setWidth(100); // all elements become 100 width
10823  els.hide(true); // all elements fade out and hide
10824  // or
10825  els.setWidth(100).hide(true);
10826  </code></pre>
10827  */
10828 Roo.CompositeElement = function(els){
10829     this.elements = [];
10830     this.addElements(els);
10831 };
10832 Roo.CompositeElement.prototype = {
10833     isComposite: true,
10834     addElements : function(els){
10835         if(!els) return this;
10836         if(typeof els == "string"){
10837             els = Roo.Element.selectorFunction(els);
10838         }
10839         var yels = this.elements;
10840         var index = yels.length-1;
10841         for(var i = 0, len = els.length; i < len; i++) {
10842                 yels[++index] = Roo.get(els[i]);
10843         }
10844         return this;
10845     },
10846
10847     /**
10848     * Clears this composite and adds the elements returned by the passed selector.
10849     * @param {String/Array} els A string CSS selector, an array of elements or an element
10850     * @return {CompositeElement} this
10851     */
10852     fill : function(els){
10853         this.elements = [];
10854         this.add(els);
10855         return this;
10856     },
10857
10858     /**
10859     * Filters this composite to only elements that match the passed selector.
10860     * @param {String} selector A string CSS selector
10861     * @return {CompositeElement} this
10862     */
10863     filter : function(selector){
10864         var els = [];
10865         this.each(function(el){
10866             if(el.is(selector)){
10867                 els[els.length] = el.dom;
10868             }
10869         });
10870         this.fill(els);
10871         return this;
10872     },
10873
10874     invoke : function(fn, args){
10875         var els = this.elements;
10876         for(var i = 0, len = els.length; i < len; i++) {
10877                 Roo.Element.prototype[fn].apply(els[i], args);
10878         }
10879         return this;
10880     },
10881     /**
10882     * Adds elements to this composite.
10883     * @param {String/Array} els A string CSS selector, an array of elements or an element
10884     * @return {CompositeElement} this
10885     */
10886     add : function(els){
10887         if(typeof els == "string"){
10888             this.addElements(Roo.Element.selectorFunction(els));
10889         }else if(els.length !== undefined){
10890             this.addElements(els);
10891         }else{
10892             this.addElements([els]);
10893         }
10894         return this;
10895     },
10896     /**
10897     * Calls the passed function passing (el, this, index) for each element in this composite.
10898     * @param {Function} fn The function to call
10899     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10900     * @return {CompositeElement} this
10901     */
10902     each : function(fn, scope){
10903         var els = this.elements;
10904         for(var i = 0, len = els.length; i < len; i++){
10905             if(fn.call(scope || els[i], els[i], this, i) === false) {
10906                 break;
10907             }
10908         }
10909         return this;
10910     },
10911
10912     /**
10913      * Returns the Element object at the specified index
10914      * @param {Number} index
10915      * @return {Roo.Element}
10916      */
10917     item : function(index){
10918         return this.elements[index] || null;
10919     },
10920
10921     /**
10922      * Returns the first Element
10923      * @return {Roo.Element}
10924      */
10925     first : function(){
10926         return this.item(0);
10927     },
10928
10929     /**
10930      * Returns the last Element
10931      * @return {Roo.Element}
10932      */
10933     last : function(){
10934         return this.item(this.elements.length-1);
10935     },
10936
10937     /**
10938      * Returns the number of elements in this composite
10939      * @return Number
10940      */
10941     getCount : function(){
10942         return this.elements.length;
10943     },
10944
10945     /**
10946      * Returns true if this composite contains the passed element
10947      * @return Boolean
10948      */
10949     contains : function(el){
10950         return this.indexOf(el) !== -1;
10951     },
10952
10953     /**
10954      * Returns true if this composite contains the passed element
10955      * @return Boolean
10956      */
10957     indexOf : function(el){
10958         return this.elements.indexOf(Roo.get(el));
10959     },
10960
10961
10962     /**
10963     * Removes the specified element(s).
10964     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10965     * or an array of any of those.
10966     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10967     * @return {CompositeElement} this
10968     */
10969     removeElement : function(el, removeDom){
10970         if(el instanceof Array){
10971             for(var i = 0, len = el.length; i < len; i++){
10972                 this.removeElement(el[i]);
10973             }
10974             return this;
10975         }
10976         var index = typeof el == 'number' ? el : this.indexOf(el);
10977         if(index !== -1){
10978             if(removeDom){
10979                 var d = this.elements[index];
10980                 if(d.dom){
10981                     d.remove();
10982                 }else{
10983                     d.parentNode.removeChild(d);
10984                 }
10985             }
10986             this.elements.splice(index, 1);
10987         }
10988         return this;
10989     },
10990
10991     /**
10992     * Replaces the specified element with the passed element.
10993     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10994     * to replace.
10995     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10996     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10997     * @return {CompositeElement} this
10998     */
10999     replaceElement : function(el, replacement, domReplace){
11000         var index = typeof el == 'number' ? el : this.indexOf(el);
11001         if(index !== -1){
11002             if(domReplace){
11003                 this.elements[index].replaceWith(replacement);
11004             }else{
11005                 this.elements.splice(index, 1, Roo.get(replacement))
11006             }
11007         }
11008         return this;
11009     },
11010
11011     /**
11012      * Removes all elements.
11013      */
11014     clear : function(){
11015         this.elements = [];
11016     }
11017 };
11018 (function(){
11019     Roo.CompositeElement.createCall = function(proto, fnName){
11020         if(!proto[fnName]){
11021             proto[fnName] = function(){
11022                 return this.invoke(fnName, arguments);
11023             };
11024         }
11025     };
11026     for(var fnName in Roo.Element.prototype){
11027         if(typeof Roo.Element.prototype[fnName] == "function"){
11028             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11029         }
11030     };
11031 })();
11032 /*
11033  * Based on:
11034  * Ext JS Library 1.1.1
11035  * Copyright(c) 2006-2007, Ext JS, LLC.
11036  *
11037  * Originally Released Under LGPL - original licence link has changed is not relivant.
11038  *
11039  * Fork - LGPL
11040  * <script type="text/javascript">
11041  */
11042
11043 /**
11044  * @class Roo.CompositeElementLite
11045  * @extends Roo.CompositeElement
11046  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11047  <pre><code>
11048  var els = Roo.select("#some-el div.some-class");
11049  // or select directly from an existing element
11050  var el = Roo.get('some-el');
11051  el.select('div.some-class');
11052
11053  els.setWidth(100); // all elements become 100 width
11054  els.hide(true); // all elements fade out and hide
11055  // or
11056  els.setWidth(100).hide(true);
11057  </code></pre><br><br>
11058  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11059  * actions will be performed on all the elements in this collection.</b>
11060  */
11061 Roo.CompositeElementLite = function(els){
11062     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11063     this.el = new Roo.Element.Flyweight();
11064 };
11065 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11066     addElements : function(els){
11067         if(els){
11068             if(els instanceof Array){
11069                 this.elements = this.elements.concat(els);
11070             }else{
11071                 var yels = this.elements;
11072                 var index = yels.length-1;
11073                 for(var i = 0, len = els.length; i < len; i++) {
11074                     yels[++index] = els[i];
11075                 }
11076             }
11077         }
11078         return this;
11079     },
11080     invoke : function(fn, args){
11081         var els = this.elements;
11082         var el = this.el;
11083         for(var i = 0, len = els.length; i < len; i++) {
11084             el.dom = els[i];
11085                 Roo.Element.prototype[fn].apply(el, args);
11086         }
11087         return this;
11088     },
11089     /**
11090      * Returns a flyweight Element of the dom element object at the specified index
11091      * @param {Number} index
11092      * @return {Roo.Element}
11093      */
11094     item : function(index){
11095         if(!this.elements[index]){
11096             return null;
11097         }
11098         this.el.dom = this.elements[index];
11099         return this.el;
11100     },
11101
11102     // fixes scope with flyweight
11103     addListener : function(eventName, handler, scope, opt){
11104         var els = this.elements;
11105         for(var i = 0, len = els.length; i < len; i++) {
11106             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11107         }
11108         return this;
11109     },
11110
11111     /**
11112     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11113     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11114     * a reference to the dom node, use el.dom.</b>
11115     * @param {Function} fn The function to call
11116     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11117     * @return {CompositeElement} this
11118     */
11119     each : function(fn, scope){
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                 if(fn.call(scope || el, el, this, i) === false){
11125                 break;
11126             }
11127         }
11128         return this;
11129     },
11130
11131     indexOf : function(el){
11132         return this.elements.indexOf(Roo.getDom(el));
11133     },
11134
11135     replaceElement : function(el, replacement, domReplace){
11136         var index = typeof el == 'number' ? el : this.indexOf(el);
11137         if(index !== -1){
11138             replacement = Roo.getDom(replacement);
11139             if(domReplace){
11140                 var d = this.elements[index];
11141                 d.parentNode.insertBefore(replacement, d);
11142                 d.parentNode.removeChild(d);
11143             }
11144             this.elements.splice(index, 1, replacement);
11145         }
11146         return this;
11147     }
11148 });
11149 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11150
11151 /*
11152  * Based on:
11153  * Ext JS Library 1.1.1
11154  * Copyright(c) 2006-2007, Ext JS, LLC.
11155  *
11156  * Originally Released Under LGPL - original licence link has changed is not relivant.
11157  *
11158  * Fork - LGPL
11159  * <script type="text/javascript">
11160  */
11161
11162  
11163
11164 /**
11165  * @class Roo.data.Connection
11166  * @extends Roo.util.Observable
11167  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11168  * either to a configured URL, or to a URL specified at request time.<br><br>
11169  * <p>
11170  * Requests made by this class are asynchronous, and will return immediately. No data from
11171  * the server will be available to the statement immediately following the {@link #request} call.
11172  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11173  * <p>
11174  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11175  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11176  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11177  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11178  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11179  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11180  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11181  * standard DOM methods.
11182  * @constructor
11183  * @param {Object} config a configuration object.
11184  */
11185 Roo.data.Connection = function(config){
11186     Roo.apply(this, config);
11187     this.addEvents({
11188         /**
11189          * @event beforerequest
11190          * Fires before a network request is made to retrieve a data object.
11191          * @param {Connection} conn This Connection object.
11192          * @param {Object} options The options config object passed to the {@link #request} method.
11193          */
11194         "beforerequest" : true,
11195         /**
11196          * @event requestcomplete
11197          * Fires if the request was successfully completed.
11198          * @param {Connection} conn This Connection object.
11199          * @param {Object} response The XHR object containing the response data.
11200          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11201          * @param {Object} options The options config object passed to the {@link #request} method.
11202          */
11203         "requestcomplete" : true,
11204         /**
11205          * @event requestexception
11206          * Fires if an error HTTP status was returned from the server.
11207          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11208          * @param {Connection} conn This Connection object.
11209          * @param {Object} response The XHR object containing the response data.
11210          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11211          * @param {Object} options The options config object passed to the {@link #request} method.
11212          */
11213         "requestexception" : true
11214     });
11215     Roo.data.Connection.superclass.constructor.call(this);
11216 };
11217
11218 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11219     /**
11220      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11221      */
11222     /**
11223      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11224      * extra parameters to each request made by this object. (defaults to undefined)
11225      */
11226     /**
11227      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11228      *  to each request made by this object. (defaults to undefined)
11229      */
11230     /**
11231      * @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)
11232      */
11233     /**
11234      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11235      */
11236     timeout : 30000,
11237     /**
11238      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11239      * @type Boolean
11240      */
11241     autoAbort:false,
11242
11243     /**
11244      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11245      * @type Boolean
11246      */
11247     disableCaching: true,
11248
11249     /**
11250      * Sends an HTTP request to a remote server.
11251      * @param {Object} options An object which may contain the following properties:<ul>
11252      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11253      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11254      * request, a url encoded string or a function to call to get either.</li>
11255      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11256      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11257      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11258      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11259      * <li>options {Object} The parameter to the request call.</li>
11260      * <li>success {Boolean} True if the request succeeded.</li>
11261      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11262      * </ul></li>
11263      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11264      * The callback is passed the following parameters:<ul>
11265      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11266      * <li>options {Object} The parameter to the request call.</li>
11267      * </ul></li>
11268      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11269      * The callback is passed the following parameters:<ul>
11270      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11271      * <li>options {Object} The parameter to the request call.</li>
11272      * </ul></li>
11273      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11274      * for the callback function. Defaults to the browser window.</li>
11275      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11276      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11277      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11278      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11279      * params for the post data. Any params will be appended to the URL.</li>
11280      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11281      * </ul>
11282      * @return {Number} transactionId
11283      */
11284     request : function(o){
11285         if(this.fireEvent("beforerequest", this, o) !== false){
11286             var p = o.params;
11287
11288             if(typeof p == "function"){
11289                 p = p.call(o.scope||window, o);
11290             }
11291             if(typeof p == "object"){
11292                 p = Roo.urlEncode(o.params);
11293             }
11294             if(this.extraParams){
11295                 var extras = Roo.urlEncode(this.extraParams);
11296                 p = p ? (p + '&' + extras) : extras;
11297             }
11298
11299             var url = o.url || this.url;
11300             if(typeof url == 'function'){
11301                 url = url.call(o.scope||window, o);
11302             }
11303
11304             if(o.form){
11305                 var form = Roo.getDom(o.form);
11306                 url = url || form.action;
11307
11308                 var enctype = form.getAttribute("enctype");
11309                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11310                     return this.doFormUpload(o, p, url);
11311                 }
11312                 var f = Roo.lib.Ajax.serializeForm(form);
11313                 p = p ? (p + '&' + f) : f;
11314             }
11315
11316             var hs = o.headers;
11317             if(this.defaultHeaders){
11318                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11319                 if(!o.headers){
11320                     o.headers = hs;
11321                 }
11322             }
11323
11324             var cb = {
11325                 success: this.handleResponse,
11326                 failure: this.handleFailure,
11327                 scope: this,
11328                 argument: {options: o},
11329                 timeout : this.timeout
11330             };
11331
11332             var method = o.method||this.method||(p ? "POST" : "GET");
11333
11334             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11335                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11336             }
11337
11338             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11339                 if(o.autoAbort){
11340                     this.abort();
11341                 }
11342             }else if(this.autoAbort !== false){
11343                 this.abort();
11344             }
11345
11346             if((method == 'GET' && p) || o.xmlData){
11347                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11348                 p = '';
11349             }
11350             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11351             return this.transId;
11352         }else{
11353             Roo.callback(o.callback, o.scope, [o, null, null]);
11354             return null;
11355         }
11356     },
11357
11358     /**
11359      * Determine whether this object has a request outstanding.
11360      * @param {Number} transactionId (Optional) defaults to the last transaction
11361      * @return {Boolean} True if there is an outstanding request.
11362      */
11363     isLoading : function(transId){
11364         if(transId){
11365             return Roo.lib.Ajax.isCallInProgress(transId);
11366         }else{
11367             return this.transId ? true : false;
11368         }
11369     },
11370
11371     /**
11372      * Aborts any outstanding request.
11373      * @param {Number} transactionId (Optional) defaults to the last transaction
11374      */
11375     abort : function(transId){
11376         if(transId || this.isLoading()){
11377             Roo.lib.Ajax.abort(transId || this.transId);
11378         }
11379     },
11380
11381     // private
11382     handleResponse : function(response){
11383         this.transId = false;
11384         var options = response.argument.options;
11385         response.argument = options ? options.argument : null;
11386         this.fireEvent("requestcomplete", this, response, options);
11387         Roo.callback(options.success, options.scope, [response, options]);
11388         Roo.callback(options.callback, options.scope, [options, true, response]);
11389     },
11390
11391     // private
11392     handleFailure : function(response, e){
11393         this.transId = false;
11394         var options = response.argument.options;
11395         response.argument = options ? options.argument : null;
11396         this.fireEvent("requestexception", this, response, options, e);
11397         Roo.callback(options.failure, options.scope, [response, options]);
11398         Roo.callback(options.callback, options.scope, [options, false, response]);
11399     },
11400
11401     // private
11402     doFormUpload : function(o, ps, url){
11403         var id = Roo.id();
11404         var frame = document.createElement('iframe');
11405         frame.id = id;
11406         frame.name = id;
11407         frame.className = 'x-hidden';
11408         if(Roo.isIE){
11409             frame.src = Roo.SSL_SECURE_URL;
11410         }
11411         document.body.appendChild(frame);
11412
11413         if(Roo.isIE){
11414            document.frames[id].name = id;
11415         }
11416
11417         var form = Roo.getDom(o.form);
11418         form.target = id;
11419         form.method = 'POST';
11420         form.enctype = form.encoding = 'multipart/form-data';
11421         if(url){
11422             form.action = url;
11423         }
11424
11425         var hiddens, hd;
11426         if(ps){ // add dynamic params
11427             hiddens = [];
11428             ps = Roo.urlDecode(ps, false);
11429             for(var k in ps){
11430                 if(ps.hasOwnProperty(k)){
11431                     hd = document.createElement('input');
11432                     hd.type = 'hidden';
11433                     hd.name = k;
11434                     hd.value = ps[k];
11435                     form.appendChild(hd);
11436                     hiddens.push(hd);
11437                 }
11438             }
11439         }
11440
11441         function cb(){
11442             var r = {  // bogus response object
11443                 responseText : '',
11444                 responseXML : null
11445             };
11446
11447             r.argument = o ? o.argument : null;
11448
11449             try { //
11450                 var doc;
11451                 if(Roo.isIE){
11452                     doc = frame.contentWindow.document;
11453                 }else {
11454                     doc = (frame.contentDocument || window.frames[id].document);
11455                 }
11456                 if(doc && doc.body){
11457                     r.responseText = doc.body.innerHTML;
11458                 }
11459                 if(doc && doc.XMLDocument){
11460                     r.responseXML = doc.XMLDocument;
11461                 }else {
11462                     r.responseXML = doc;
11463                 }
11464             }
11465             catch(e) {
11466                 // ignore
11467             }
11468
11469             Roo.EventManager.removeListener(frame, 'load', cb, this);
11470
11471             this.fireEvent("requestcomplete", this, r, o);
11472             Roo.callback(o.success, o.scope, [r, o]);
11473             Roo.callback(o.callback, o.scope, [o, true, r]);
11474
11475             setTimeout(function(){document.body.removeChild(frame);}, 100);
11476         }
11477
11478         Roo.EventManager.on(frame, 'load', cb, this);
11479         form.submit();
11480
11481         if(hiddens){ // remove dynamic params
11482             for(var i = 0, len = hiddens.length; i < len; i++){
11483                 form.removeChild(hiddens[i]);
11484             }
11485         }
11486     }
11487 });
11488
11489 /**
11490  * @class Roo.Ajax
11491  * @extends Roo.data.Connection
11492  * Global Ajax request class.
11493  *
11494  * @singleton
11495  */
11496 Roo.Ajax = new Roo.data.Connection({
11497     // fix up the docs
11498    /**
11499      * @cfg {String} url @hide
11500      */
11501     /**
11502      * @cfg {Object} extraParams @hide
11503      */
11504     /**
11505      * @cfg {Object} defaultHeaders @hide
11506      */
11507     /**
11508      * @cfg {String} method (Optional) @hide
11509      */
11510     /**
11511      * @cfg {Number} timeout (Optional) @hide
11512      */
11513     /**
11514      * @cfg {Boolean} autoAbort (Optional) @hide
11515      */
11516
11517     /**
11518      * @cfg {Boolean} disableCaching (Optional) @hide
11519      */
11520
11521     /**
11522      * @property  disableCaching
11523      * True to add a unique cache-buster param to GET requests. (defaults to true)
11524      * @type Boolean
11525      */
11526     /**
11527      * @property  url
11528      * The default URL to be used for requests to the server. (defaults to undefined)
11529      * @type String
11530      */
11531     /**
11532      * @property  extraParams
11533      * An object containing properties which are used as
11534      * extra parameters to each request made by this object. (defaults to undefined)
11535      * @type Object
11536      */
11537     /**
11538      * @property  defaultHeaders
11539      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11540      * @type Object
11541      */
11542     /**
11543      * @property  method
11544      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11545      * @type String
11546      */
11547     /**
11548      * @property  timeout
11549      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11550      * @type Number
11551      */
11552
11553     /**
11554      * @property  autoAbort
11555      * Whether a new request should abort any pending requests. (defaults to false)
11556      * @type Boolean
11557      */
11558     autoAbort : false,
11559
11560     /**
11561      * Serialize the passed form into a url encoded string
11562      * @param {String/HTMLElement} form
11563      * @return {String}
11564      */
11565     serializeForm : function(form){
11566         return Roo.lib.Ajax.serializeForm(form);
11567     }
11568 });/*
11569  * Based on:
11570  * Ext JS Library 1.1.1
11571  * Copyright(c) 2006-2007, Ext JS, LLC.
11572  *
11573  * Originally Released Under LGPL - original licence link has changed is not relivant.
11574  *
11575  * Fork - LGPL
11576  * <script type="text/javascript">
11577  */
11578  
11579 /**
11580  * Global Ajax request class.
11581  * 
11582  * @class Roo.Ajax
11583  * @extends Roo.data.Connection
11584  * @static
11585  * 
11586  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11587  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11588  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11589  * @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)
11590  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11591  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11592  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11593  */
11594 Roo.Ajax = new Roo.data.Connection({
11595     // fix up the docs
11596     /**
11597      * @scope Roo.Ajax
11598      * @type {Boolear} 
11599      */
11600     autoAbort : false,
11601
11602     /**
11603      * Serialize the passed form into a url encoded string
11604      * @scope Roo.Ajax
11605      * @param {String/HTMLElement} form
11606      * @return {String}
11607      */
11608     serializeForm : function(form){
11609         return Roo.lib.Ajax.serializeForm(form);
11610     }
11611 });/*
11612  * Based on:
11613  * Ext JS Library 1.1.1
11614  * Copyright(c) 2006-2007, Ext JS, LLC.
11615  *
11616  * Originally Released Under LGPL - original licence link has changed is not relivant.
11617  *
11618  * Fork - LGPL
11619  * <script type="text/javascript">
11620  */
11621
11622  
11623 /**
11624  * @class Roo.UpdateManager
11625  * @extends Roo.util.Observable
11626  * Provides AJAX-style update for Element object.<br><br>
11627  * Usage:<br>
11628  * <pre><code>
11629  * // Get it from a Roo.Element object
11630  * var el = Roo.get("foo");
11631  * var mgr = el.getUpdateManager();
11632  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11633  * ...
11634  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11635  * <br>
11636  * // or directly (returns the same UpdateManager instance)
11637  * var mgr = new Roo.UpdateManager("myElementId");
11638  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11639  * mgr.on("update", myFcnNeedsToKnow);
11640  * <br>
11641    // short handed call directly from the element object
11642    Roo.get("foo").load({
11643         url: "bar.php",
11644         scripts:true,
11645         params: "for=bar",
11646         text: "Loading Foo..."
11647    });
11648  * </code></pre>
11649  * @constructor
11650  * Create new UpdateManager directly.
11651  * @param {String/HTMLElement/Roo.Element} el The element to update
11652  * @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).
11653  */
11654 Roo.UpdateManager = function(el, forceNew){
11655     el = Roo.get(el);
11656     if(!forceNew && el.updateManager){
11657         return el.updateManager;
11658     }
11659     /**
11660      * The Element object
11661      * @type Roo.Element
11662      */
11663     this.el = el;
11664     /**
11665      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11666      * @type String
11667      */
11668     this.defaultUrl = null;
11669
11670     this.addEvents({
11671         /**
11672          * @event beforeupdate
11673          * Fired before an update is made, return false from your handler and the update is cancelled.
11674          * @param {Roo.Element} el
11675          * @param {String/Object/Function} url
11676          * @param {String/Object} params
11677          */
11678         "beforeupdate": true,
11679         /**
11680          * @event update
11681          * Fired after successful update is made.
11682          * @param {Roo.Element} el
11683          * @param {Object} oResponseObject The response Object
11684          */
11685         "update": true,
11686         /**
11687          * @event failure
11688          * Fired on update failure.
11689          * @param {Roo.Element} el
11690          * @param {Object} oResponseObject The response Object
11691          */
11692         "failure": true
11693     });
11694     var d = Roo.UpdateManager.defaults;
11695     /**
11696      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11697      * @type String
11698      */
11699     this.sslBlankUrl = d.sslBlankUrl;
11700     /**
11701      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11702      * @type Boolean
11703      */
11704     this.disableCaching = d.disableCaching;
11705     /**
11706      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11707      * @type String
11708      */
11709     this.indicatorText = d.indicatorText;
11710     /**
11711      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11712      * @type String
11713      */
11714     this.showLoadIndicator = d.showLoadIndicator;
11715     /**
11716      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11717      * @type Number
11718      */
11719     this.timeout = d.timeout;
11720
11721     /**
11722      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11723      * @type Boolean
11724      */
11725     this.loadScripts = d.loadScripts;
11726
11727     /**
11728      * Transaction object of current executing transaction
11729      */
11730     this.transaction = null;
11731
11732     /**
11733      * @private
11734      */
11735     this.autoRefreshProcId = null;
11736     /**
11737      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11738      * @type Function
11739      */
11740     this.refreshDelegate = this.refresh.createDelegate(this);
11741     /**
11742      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11743      * @type Function
11744      */
11745     this.updateDelegate = this.update.createDelegate(this);
11746     /**
11747      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11748      * @type Function
11749      */
11750     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11751     /**
11752      * @private
11753      */
11754     this.successDelegate = this.processSuccess.createDelegate(this);
11755     /**
11756      * @private
11757      */
11758     this.failureDelegate = this.processFailure.createDelegate(this);
11759
11760     if(!this.renderer){
11761      /**
11762       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11763       */
11764     this.renderer = new Roo.UpdateManager.BasicRenderer();
11765     }
11766     
11767     Roo.UpdateManager.superclass.constructor.call(this);
11768 };
11769
11770 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11771     /**
11772      * Get the Element this UpdateManager is bound to
11773      * @return {Roo.Element} The element
11774      */
11775     getEl : function(){
11776         return this.el;
11777     },
11778     /**
11779      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11780      * @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:
11781 <pre><code>
11782 um.update({<br/>
11783     url: "your-url.php",<br/>
11784     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11785     callback: yourFunction,<br/>
11786     scope: yourObject, //(optional scope)  <br/>
11787     discardUrl: false, <br/>
11788     nocache: false,<br/>
11789     text: "Loading...",<br/>
11790     timeout: 30,<br/>
11791     scripts: false<br/>
11792 });
11793 </code></pre>
11794      * The only required property is url. The optional properties nocache, text and scripts
11795      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11796      * @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}
11797      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11798      * @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.
11799      */
11800     update : function(url, params, callback, discardUrl){
11801         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11802             var method = this.method, cfg;
11803             if(typeof url == "object"){ // must be config object
11804                 cfg = url;
11805                 url = cfg.url;
11806                 params = params || cfg.params;
11807                 callback = callback || cfg.callback;
11808                 discardUrl = discardUrl || cfg.discardUrl;
11809                 if(callback && cfg.scope){
11810                     callback = callback.createDelegate(cfg.scope);
11811                 }
11812                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11813                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11814                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11815                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11816                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11817             }
11818             this.showLoading();
11819             if(!discardUrl){
11820                 this.defaultUrl = url;
11821             }
11822             if(typeof url == "function"){
11823                 url = url.call(this);
11824             }
11825
11826             method = method || (params ? "POST" : "GET");
11827             if(method == "GET"){
11828                 url = this.prepareUrl(url);
11829             }
11830
11831             var o = Roo.apply(cfg ||{}, {
11832                 url : url,
11833                 params: params,
11834                 success: this.successDelegate,
11835                 failure: this.failureDelegate,
11836                 callback: undefined,
11837                 timeout: (this.timeout*1000),
11838                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11839             });
11840
11841             this.transaction = Roo.Ajax.request(o);
11842         }
11843     },
11844
11845     /**
11846      * 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.
11847      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11848      * @param {String/HTMLElement} form The form Id or form element
11849      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11850      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11851      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11852      */
11853     formUpdate : function(form, url, reset, callback){
11854         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11855             if(typeof url == "function"){
11856                 url = url.call(this);
11857             }
11858             form = Roo.getDom(form);
11859             this.transaction = Roo.Ajax.request({
11860                 form: form,
11861                 url:url,
11862                 success: this.successDelegate,
11863                 failure: this.failureDelegate,
11864                 timeout: (this.timeout*1000),
11865                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11866             });
11867             this.showLoading.defer(1, this);
11868         }
11869     },
11870
11871     /**
11872      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11873      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11874      */
11875     refresh : function(callback){
11876         if(this.defaultUrl == null){
11877             return;
11878         }
11879         this.update(this.defaultUrl, null, callback, true);
11880     },
11881
11882     /**
11883      * Set this element to auto refresh.
11884      * @param {Number} interval How often to update (in seconds).
11885      * @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)
11886      * @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}
11887      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11888      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11889      */
11890     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11891         if(refreshNow){
11892             this.update(url || this.defaultUrl, params, callback, true);
11893         }
11894         if(this.autoRefreshProcId){
11895             clearInterval(this.autoRefreshProcId);
11896         }
11897         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11898     },
11899
11900     /**
11901      * Stop auto refresh on this element.
11902      */
11903      stopAutoRefresh : function(){
11904         if(this.autoRefreshProcId){
11905             clearInterval(this.autoRefreshProcId);
11906             delete this.autoRefreshProcId;
11907         }
11908     },
11909
11910     isAutoRefreshing : function(){
11911        return this.autoRefreshProcId ? true : false;
11912     },
11913     /**
11914      * Called to update the element to "Loading" state. Override to perform custom action.
11915      */
11916     showLoading : function(){
11917         if(this.showLoadIndicator){
11918             this.el.update(this.indicatorText);
11919         }
11920     },
11921
11922     /**
11923      * Adds unique parameter to query string if disableCaching = true
11924      * @private
11925      */
11926     prepareUrl : function(url){
11927         if(this.disableCaching){
11928             var append = "_dc=" + (new Date().getTime());
11929             if(url.indexOf("?") !== -1){
11930                 url += "&" + append;
11931             }else{
11932                 url += "?" + append;
11933             }
11934         }
11935         return url;
11936     },
11937
11938     /**
11939      * @private
11940      */
11941     processSuccess : function(response){
11942         this.transaction = null;
11943         if(response.argument.form && response.argument.reset){
11944             try{ // put in try/catch since some older FF releases had problems with this
11945                 response.argument.form.reset();
11946             }catch(e){}
11947         }
11948         if(this.loadScripts){
11949             this.renderer.render(this.el, response, this,
11950                 this.updateComplete.createDelegate(this, [response]));
11951         }else{
11952             this.renderer.render(this.el, response, this);
11953             this.updateComplete(response);
11954         }
11955     },
11956
11957     updateComplete : function(response){
11958         this.fireEvent("update", this.el, response);
11959         if(typeof response.argument.callback == "function"){
11960             response.argument.callback(this.el, true, response);
11961         }
11962     },
11963
11964     /**
11965      * @private
11966      */
11967     processFailure : function(response){
11968         this.transaction = null;
11969         this.fireEvent("failure", this.el, response);
11970         if(typeof response.argument.callback == "function"){
11971             response.argument.callback(this.el, false, response);
11972         }
11973     },
11974
11975     /**
11976      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11977      * @param {Object} renderer The object implementing the render() method
11978      */
11979     setRenderer : function(renderer){
11980         this.renderer = renderer;
11981     },
11982
11983     getRenderer : function(){
11984        return this.renderer;
11985     },
11986
11987     /**
11988      * Set the defaultUrl used for updates
11989      * @param {String/Function} defaultUrl The url or a function to call to get the url
11990      */
11991     setDefaultUrl : function(defaultUrl){
11992         this.defaultUrl = defaultUrl;
11993     },
11994
11995     /**
11996      * Aborts the executing transaction
11997      */
11998     abort : function(){
11999         if(this.transaction){
12000             Roo.Ajax.abort(this.transaction);
12001         }
12002     },
12003
12004     /**
12005      * Returns true if an update is in progress
12006      * @return {Boolean}
12007      */
12008     isUpdating : function(){
12009         if(this.transaction){
12010             return Roo.Ajax.isLoading(this.transaction);
12011         }
12012         return false;
12013     }
12014 });
12015
12016 /**
12017  * @class Roo.UpdateManager.defaults
12018  * @static (not really - but it helps the doc tool)
12019  * The defaults collection enables customizing the default properties of UpdateManager
12020  */
12021    Roo.UpdateManager.defaults = {
12022        /**
12023          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12024          * @type Number
12025          */
12026          timeout : 30,
12027
12028          /**
12029          * True to process scripts by default (Defaults to false).
12030          * @type Boolean
12031          */
12032         loadScripts : false,
12033
12034         /**
12035         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12036         * @type String
12037         */
12038         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12039         /**
12040          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12041          * @type Boolean
12042          */
12043         disableCaching : false,
12044         /**
12045          * Whether to show indicatorText when loading (Defaults to true).
12046          * @type Boolean
12047          */
12048         showLoadIndicator : true,
12049         /**
12050          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12051          * @type String
12052          */
12053         indicatorText : '<div class="loading-indicator">Loading...</div>'
12054    };
12055
12056 /**
12057  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12058  *Usage:
12059  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12060  * @param {String/HTMLElement/Roo.Element} el The element to update
12061  * @param {String} url The url
12062  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12063  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12064  * @static
12065  * @deprecated
12066  * @member Roo.UpdateManager
12067  */
12068 Roo.UpdateManager.updateElement = function(el, url, params, options){
12069     var um = Roo.get(el, true).getUpdateManager();
12070     Roo.apply(um, options);
12071     um.update(url, params, options ? options.callback : null);
12072 };
12073 // alias for backwards compat
12074 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12075 /**
12076  * @class Roo.UpdateManager.BasicRenderer
12077  * Default Content renderer. Updates the elements innerHTML with the responseText.
12078  */
12079 Roo.UpdateManager.BasicRenderer = function(){};
12080
12081 Roo.UpdateManager.BasicRenderer.prototype = {
12082     /**
12083      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12084      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12085      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12086      * @param {Roo.Element} el The element being rendered
12087      * @param {Object} response The YUI Connect response object
12088      * @param {UpdateManager} updateManager The calling update manager
12089      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12090      */
12091      render : function(el, response, updateManager, callback){
12092         el.update(response.responseText, updateManager.loadScripts, callback);
12093     }
12094 };
12095 /*
12096  * Based on:
12097  * Ext JS Library 1.1.1
12098  * Copyright(c) 2006-2007, Ext JS, LLC.
12099  *
12100  * Originally Released Under LGPL - original licence link has changed is not relivant.
12101  *
12102  * Fork - LGPL
12103  * <script type="text/javascript">
12104  */
12105
12106 /**
12107  * @class Roo.util.DelayedTask
12108  * Provides a convenient method of performing setTimeout where a new
12109  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12110  * You can use this class to buffer
12111  * the keypress events for a certain number of milliseconds, and perform only if they stop
12112  * for that amount of time.
12113  * @constructor The parameters to this constructor serve as defaults and are not required.
12114  * @param {Function} fn (optional) The default function to timeout
12115  * @param {Object} scope (optional) The default scope of that timeout
12116  * @param {Array} args (optional) The default Array of arguments
12117  */
12118 Roo.util.DelayedTask = function(fn, scope, args){
12119     var id = null, d, t;
12120
12121     var call = function(){
12122         var now = new Date().getTime();
12123         if(now - t >= d){
12124             clearInterval(id);
12125             id = null;
12126             fn.apply(scope, args || []);
12127         }
12128     };
12129     /**
12130      * Cancels any pending timeout and queues a new one
12131      * @param {Number} delay The milliseconds to delay
12132      * @param {Function} newFn (optional) Overrides function passed to constructor
12133      * @param {Object} newScope (optional) Overrides scope passed to constructor
12134      * @param {Array} newArgs (optional) Overrides args passed to constructor
12135      */
12136     this.delay = function(delay, newFn, newScope, newArgs){
12137         if(id && delay != d){
12138             this.cancel();
12139         }
12140         d = delay;
12141         t = new Date().getTime();
12142         fn = newFn || fn;
12143         scope = newScope || scope;
12144         args = newArgs || args;
12145         if(!id){
12146             id = setInterval(call, d);
12147         }
12148     };
12149
12150     /**
12151      * Cancel the last queued timeout
12152      */
12153     this.cancel = function(){
12154         if(id){
12155             clearInterval(id);
12156             id = null;
12157         }
12158     };
12159 };/*
12160  * Based on:
12161  * Ext JS Library 1.1.1
12162  * Copyright(c) 2006-2007, Ext JS, LLC.
12163  *
12164  * Originally Released Under LGPL - original licence link has changed is not relivant.
12165  *
12166  * Fork - LGPL
12167  * <script type="text/javascript">
12168  */
12169  
12170  
12171 Roo.util.TaskRunner = function(interval){
12172     interval = interval || 10;
12173     var tasks = [], removeQueue = [];
12174     var id = 0;
12175     var running = false;
12176
12177     var stopThread = function(){
12178         running = false;
12179         clearInterval(id);
12180         id = 0;
12181     };
12182
12183     var startThread = function(){
12184         if(!running){
12185             running = true;
12186             id = setInterval(runTasks, interval);
12187         }
12188     };
12189
12190     var removeTask = function(task){
12191         removeQueue.push(task);
12192         if(task.onStop){
12193             task.onStop();
12194         }
12195     };
12196
12197     var runTasks = function(){
12198         if(removeQueue.length > 0){
12199             for(var i = 0, len = removeQueue.length; i < len; i++){
12200                 tasks.remove(removeQueue[i]);
12201             }
12202             removeQueue = [];
12203             if(tasks.length < 1){
12204                 stopThread();
12205                 return;
12206             }
12207         }
12208         var now = new Date().getTime();
12209         for(var i = 0, len = tasks.length; i < len; ++i){
12210             var t = tasks[i];
12211             var itime = now - t.taskRunTime;
12212             if(t.interval <= itime){
12213                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12214                 t.taskRunTime = now;
12215                 if(rt === false || t.taskRunCount === t.repeat){
12216                     removeTask(t);
12217                     return;
12218                 }
12219             }
12220             if(t.duration && t.duration <= (now - t.taskStartTime)){
12221                 removeTask(t);
12222             }
12223         }
12224     };
12225
12226     /**
12227      * Queues a new task.
12228      * @param {Object} task
12229      */
12230     this.start = function(task){
12231         tasks.push(task);
12232         task.taskStartTime = new Date().getTime();
12233         task.taskRunTime = 0;
12234         task.taskRunCount = 0;
12235         startThread();
12236         return task;
12237     };
12238
12239     this.stop = function(task){
12240         removeTask(task);
12241         return task;
12242     };
12243
12244     this.stopAll = function(){
12245         stopThread();
12246         for(var i = 0, len = tasks.length; i < len; i++){
12247             if(tasks[i].onStop){
12248                 tasks[i].onStop();
12249             }
12250         }
12251         tasks = [];
12252         removeQueue = [];
12253     };
12254 };
12255
12256 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12257  * Based on:
12258  * Ext JS Library 1.1.1
12259  * Copyright(c) 2006-2007, Ext JS, LLC.
12260  *
12261  * Originally Released Under LGPL - original licence link has changed is not relivant.
12262  *
12263  * Fork - LGPL
12264  * <script type="text/javascript">
12265  */
12266
12267  
12268 /**
12269  * @class Roo.util.MixedCollection
12270  * @extends Roo.util.Observable
12271  * A Collection class that maintains both numeric indexes and keys and exposes events.
12272  * @constructor
12273  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12274  * collection (defaults to false)
12275  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12276  * and return the key value for that item.  This is used when available to look up the key on items that
12277  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12278  * equivalent to providing an implementation for the {@link #getKey} method.
12279  */
12280 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12281     this.items = [];
12282     this.map = {};
12283     this.keys = [];
12284     this.length = 0;
12285     this.addEvents({
12286         /**
12287          * @event clear
12288          * Fires when the collection is cleared.
12289          */
12290         "clear" : true,
12291         /**
12292          * @event add
12293          * Fires when an item is added to the collection.
12294          * @param {Number} index The index at which the item was added.
12295          * @param {Object} o The item added.
12296          * @param {String} key The key associated with the added item.
12297          */
12298         "add" : true,
12299         /**
12300          * @event replace
12301          * Fires when an item is replaced in the collection.
12302          * @param {String} key he key associated with the new added.
12303          * @param {Object} old The item being replaced.
12304          * @param {Object} new The new item.
12305          */
12306         "replace" : true,
12307         /**
12308          * @event remove
12309          * Fires when an item is removed from the collection.
12310          * @param {Object} o The item being removed.
12311          * @param {String} key (optional) The key associated with the removed item.
12312          */
12313         "remove" : true,
12314         "sort" : true
12315     });
12316     this.allowFunctions = allowFunctions === true;
12317     if(keyFn){
12318         this.getKey = keyFn;
12319     }
12320     Roo.util.MixedCollection.superclass.constructor.call(this);
12321 };
12322
12323 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12324     allowFunctions : false,
12325     
12326 /**
12327  * Adds an item to the collection.
12328  * @param {String} key The key to associate with the item
12329  * @param {Object} o The item to add.
12330  * @return {Object} The item added.
12331  */
12332     add : function(key, o){
12333         if(arguments.length == 1){
12334             o = arguments[0];
12335             key = this.getKey(o);
12336         }
12337         if(typeof key == "undefined" || key === null){
12338             this.length++;
12339             this.items.push(o);
12340             this.keys.push(null);
12341         }else{
12342             var old = this.map[key];
12343             if(old){
12344                 return this.replace(key, o);
12345             }
12346             this.length++;
12347             this.items.push(o);
12348             this.map[key] = o;
12349             this.keys.push(key);
12350         }
12351         this.fireEvent("add", this.length-1, o, key);
12352         return o;
12353     },
12354        
12355 /**
12356   * MixedCollection has a generic way to fetch keys if you implement getKey.
12357 <pre><code>
12358 // normal way
12359 var mc = new Roo.util.MixedCollection();
12360 mc.add(someEl.dom.id, someEl);
12361 mc.add(otherEl.dom.id, otherEl);
12362 //and so on
12363
12364 // using getKey
12365 var mc = new Roo.util.MixedCollection();
12366 mc.getKey = function(el){
12367    return el.dom.id;
12368 };
12369 mc.add(someEl);
12370 mc.add(otherEl);
12371
12372 // or via the constructor
12373 var mc = new Roo.util.MixedCollection(false, function(el){
12374    return el.dom.id;
12375 });
12376 mc.add(someEl);
12377 mc.add(otherEl);
12378 </code></pre>
12379  * @param o {Object} The item for which to find the key.
12380  * @return {Object} The key for the passed item.
12381  */
12382     getKey : function(o){
12383          return o.id; 
12384     },
12385    
12386 /**
12387  * Replaces an item in the collection.
12388  * @param {String} key The key associated with the item to replace, or the item to replace.
12389  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12390  * @return {Object}  The new item.
12391  */
12392     replace : function(key, o){
12393         if(arguments.length == 1){
12394             o = arguments[0];
12395             key = this.getKey(o);
12396         }
12397         var old = this.item(key);
12398         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12399              return this.add(key, o);
12400         }
12401         var index = this.indexOfKey(key);
12402         this.items[index] = o;
12403         this.map[key] = o;
12404         this.fireEvent("replace", key, old, o);
12405         return o;
12406     },
12407    
12408 /**
12409  * Adds all elements of an Array or an Object to the collection.
12410  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12411  * an Array of values, each of which are added to the collection.
12412  */
12413     addAll : function(objs){
12414         if(arguments.length > 1 || objs instanceof Array){
12415             var args = arguments.length > 1 ? arguments : objs;
12416             for(var i = 0, len = args.length; i < len; i++){
12417                 this.add(args[i]);
12418             }
12419         }else{
12420             for(var key in objs){
12421                 if(this.allowFunctions || typeof objs[key] != "function"){
12422                     this.add(key, objs[key]);
12423                 }
12424             }
12425         }
12426     },
12427    
12428 /**
12429  * Executes the specified function once for every item in the collection, passing each
12430  * item as the first and only parameter. returning false from the function will stop the iteration.
12431  * @param {Function} fn The function to execute for each item.
12432  * @param {Object} scope (optional) The scope in which to execute the function.
12433  */
12434     each : function(fn, scope){
12435         var items = [].concat(this.items); // each safe for removal
12436         for(var i = 0, len = items.length; i < len; i++){
12437             if(fn.call(scope || items[i], items[i], i, len) === false){
12438                 break;
12439             }
12440         }
12441     },
12442    
12443 /**
12444  * Executes the specified function once for every key in the collection, passing each
12445  * key, and its associated item as the first two parameters.
12446  * @param {Function} fn The function to execute for each item.
12447  * @param {Object} scope (optional) The scope in which to execute the function.
12448  */
12449     eachKey : function(fn, scope){
12450         for(var i = 0, len = this.keys.length; i < len; i++){
12451             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12452         }
12453     },
12454    
12455 /**
12456  * Returns the first item in the collection which elicits a true return value from the
12457  * passed selection function.
12458  * @param {Function} fn The selection function to execute for each item.
12459  * @param {Object} scope (optional) The scope in which to execute the function.
12460  * @return {Object} The first item in the collection which returned true from the selection function.
12461  */
12462     find : function(fn, scope){
12463         for(var i = 0, len = this.items.length; i < len; i++){
12464             if(fn.call(scope || window, this.items[i], this.keys[i])){
12465                 return this.items[i];
12466             }
12467         }
12468         return null;
12469     },
12470    
12471 /**
12472  * Inserts an item at the specified index in the collection.
12473  * @param {Number} index The index to insert the item at.
12474  * @param {String} key The key to associate with the new item, or the item itself.
12475  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12476  * @return {Object} The item inserted.
12477  */
12478     insert : function(index, key, o){
12479         if(arguments.length == 2){
12480             o = arguments[1];
12481             key = this.getKey(o);
12482         }
12483         if(index >= this.length){
12484             return this.add(key, o);
12485         }
12486         this.length++;
12487         this.items.splice(index, 0, o);
12488         if(typeof key != "undefined" && key != null){
12489             this.map[key] = o;
12490         }
12491         this.keys.splice(index, 0, key);
12492         this.fireEvent("add", index, o, key);
12493         return o;
12494     },
12495    
12496 /**
12497  * Removed an item from the collection.
12498  * @param {Object} o The item to remove.
12499  * @return {Object} The item removed.
12500  */
12501     remove : function(o){
12502         return this.removeAt(this.indexOf(o));
12503     },
12504    
12505 /**
12506  * Remove an item from a specified index in the collection.
12507  * @param {Number} index The index within the collection of the item to remove.
12508  */
12509     removeAt : function(index){
12510         if(index < this.length && index >= 0){
12511             this.length--;
12512             var o = this.items[index];
12513             this.items.splice(index, 1);
12514             var key = this.keys[index];
12515             if(typeof key != "undefined"){
12516                 delete this.map[key];
12517             }
12518             this.keys.splice(index, 1);
12519             this.fireEvent("remove", o, key);
12520         }
12521     },
12522    
12523 /**
12524  * Removed an item associated with the passed key fom the collection.
12525  * @param {String} key The key of the item to remove.
12526  */
12527     removeKey : function(key){
12528         return this.removeAt(this.indexOfKey(key));
12529     },
12530    
12531 /**
12532  * Returns the number of items in the collection.
12533  * @return {Number} the number of items in the collection.
12534  */
12535     getCount : function(){
12536         return this.length; 
12537     },
12538    
12539 /**
12540  * Returns index within the collection of the passed Object.
12541  * @param {Object} o The item to find the index of.
12542  * @return {Number} index of the item.
12543  */
12544     indexOf : function(o){
12545         if(!this.items.indexOf){
12546             for(var i = 0, len = this.items.length; i < len; i++){
12547                 if(this.items[i] == o) return i;
12548             }
12549             return -1;
12550         }else{
12551             return this.items.indexOf(o);
12552         }
12553     },
12554    
12555 /**
12556  * Returns index within the collection of the passed key.
12557  * @param {String} key The key to find the index of.
12558  * @return {Number} index of the key.
12559  */
12560     indexOfKey : function(key){
12561         if(!this.keys.indexOf){
12562             for(var i = 0, len = this.keys.length; i < len; i++){
12563                 if(this.keys[i] == key) return i;
12564             }
12565             return -1;
12566         }else{
12567             return this.keys.indexOf(key);
12568         }
12569     },
12570    
12571 /**
12572  * Returns the item associated with the passed key OR index. Key has priority over index.
12573  * @param {String/Number} key The key or index of the item.
12574  * @return {Object} The item associated with the passed key.
12575  */
12576     item : function(key){
12577         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12578         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12579     },
12580     
12581 /**
12582  * Returns the item at the specified index.
12583  * @param {Number} index The index of the item.
12584  * @return {Object}
12585  */
12586     itemAt : function(index){
12587         return this.items[index];
12588     },
12589     
12590 /**
12591  * Returns the item associated with the passed key.
12592  * @param {String/Number} key The key of the item.
12593  * @return {Object} The item associated with the passed key.
12594  */
12595     key : function(key){
12596         return this.map[key];
12597     },
12598    
12599 /**
12600  * Returns true if the collection contains the passed Object as an item.
12601  * @param {Object} o  The Object to look for in the collection.
12602  * @return {Boolean} True if the collection contains the Object as an item.
12603  */
12604     contains : function(o){
12605         return this.indexOf(o) != -1;
12606     },
12607    
12608 /**
12609  * Returns true if the collection contains the passed Object as a key.
12610  * @param {String} key The key to look for in the collection.
12611  * @return {Boolean} True if the collection contains the Object as a key.
12612  */
12613     containsKey : function(key){
12614         return typeof this.map[key] != "undefined";
12615     },
12616    
12617 /**
12618  * Removes all items from the collection.
12619  */
12620     clear : function(){
12621         this.length = 0;
12622         this.items = [];
12623         this.keys = [];
12624         this.map = {};
12625         this.fireEvent("clear");
12626     },
12627    
12628 /**
12629  * Returns the first item in the collection.
12630  * @return {Object} the first item in the collection..
12631  */
12632     first : function(){
12633         return this.items[0]; 
12634     },
12635    
12636 /**
12637  * Returns the last item in the collection.
12638  * @return {Object} the last item in the collection..
12639  */
12640     last : function(){
12641         return this.items[this.length-1];   
12642     },
12643     
12644     _sort : function(property, dir, fn){
12645         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12646         fn = fn || function(a, b){
12647             return a-b;
12648         };
12649         var c = [], k = this.keys, items = this.items;
12650         for(var i = 0, len = items.length; i < len; i++){
12651             c[c.length] = {key: k[i], value: items[i], index: i};
12652         }
12653         c.sort(function(a, b){
12654             var v = fn(a[property], b[property]) * dsc;
12655             if(v == 0){
12656                 v = (a.index < b.index ? -1 : 1);
12657             }
12658             return v;
12659         });
12660         for(var i = 0, len = c.length; i < len; i++){
12661             items[i] = c[i].value;
12662             k[i] = c[i].key;
12663         }
12664         this.fireEvent("sort", this);
12665     },
12666     
12667     /**
12668      * Sorts this collection with the passed comparison function
12669      * @param {String} direction (optional) "ASC" or "DESC"
12670      * @param {Function} fn (optional) comparison function
12671      */
12672     sort : function(dir, fn){
12673         this._sort("value", dir, fn);
12674     },
12675     
12676     /**
12677      * Sorts this collection by keys
12678      * @param {String} direction (optional) "ASC" or "DESC"
12679      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12680      */
12681     keySort : function(dir, fn){
12682         this._sort("key", dir, fn || function(a, b){
12683             return String(a).toUpperCase()-String(b).toUpperCase();
12684         });
12685     },
12686     
12687     /**
12688      * Returns a range of items in this collection
12689      * @param {Number} startIndex (optional) defaults to 0
12690      * @param {Number} endIndex (optional) default to the last item
12691      * @return {Array} An array of items
12692      */
12693     getRange : function(start, end){
12694         var items = this.items;
12695         if(items.length < 1){
12696             return [];
12697         }
12698         start = start || 0;
12699         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12700         var r = [];
12701         if(start <= end){
12702             for(var i = start; i <= end; i++) {
12703                     r[r.length] = items[i];
12704             }
12705         }else{
12706             for(var i = start; i >= end; i--) {
12707                     r[r.length] = items[i];
12708             }
12709         }
12710         return r;
12711     },
12712         
12713     /**
12714      * Filter the <i>objects</i> in this collection by a specific property. 
12715      * Returns a new collection that has been filtered.
12716      * @param {String} property A property on your objects
12717      * @param {String/RegExp} value Either string that the property values 
12718      * should start with or a RegExp to test against the property
12719      * @return {MixedCollection} The new filtered collection
12720      */
12721     filter : function(property, value){
12722         if(!value.exec){ // not a regex
12723             value = String(value);
12724             if(value.length == 0){
12725                 return this.clone();
12726             }
12727             value = new RegExp("^" + Roo.escapeRe(value), "i");
12728         }
12729         return this.filterBy(function(o){
12730             return o && value.test(o[property]);
12731         });
12732         },
12733     
12734     /**
12735      * Filter by a function. * Returns a new collection that has been filtered.
12736      * The passed function will be called with each 
12737      * object in the collection. If the function returns true, the value is included 
12738      * otherwise it is filtered.
12739      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12740      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12741      * @return {MixedCollection} The new filtered collection
12742      */
12743     filterBy : function(fn, scope){
12744         var r = new Roo.util.MixedCollection();
12745         r.getKey = this.getKey;
12746         var k = this.keys, it = this.items;
12747         for(var i = 0, len = it.length; i < len; i++){
12748             if(fn.call(scope||this, it[i], k[i])){
12749                                 r.add(k[i], it[i]);
12750                         }
12751         }
12752         return r;
12753     },
12754     
12755     /**
12756      * Creates a duplicate of this collection
12757      * @return {MixedCollection}
12758      */
12759     clone : function(){
12760         var r = new Roo.util.MixedCollection();
12761         var k = this.keys, it = this.items;
12762         for(var i = 0, len = it.length; i < len; i++){
12763             r.add(k[i], it[i]);
12764         }
12765         r.getKey = this.getKey;
12766         return r;
12767     }
12768 });
12769 /**
12770  * Returns the item associated with the passed key or index.
12771  * @method
12772  * @param {String/Number} key The key or index of the item.
12773  * @return {Object} The item associated with the passed key.
12774  */
12775 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12776  * Based on:
12777  * Ext JS Library 1.1.1
12778  * Copyright(c) 2006-2007, Ext JS, LLC.
12779  *
12780  * Originally Released Under LGPL - original licence link has changed is not relivant.
12781  *
12782  * Fork - LGPL
12783  * <script type="text/javascript">
12784  */
12785 /**
12786  * @class Roo.util.JSON
12787  * Modified version of Douglas Crockford"s json.js that doesn"t
12788  * mess with the Object prototype 
12789  * http://www.json.org/js.html
12790  * @singleton
12791  */
12792 Roo.util.JSON = new (function(){
12793     var useHasOwn = {}.hasOwnProperty ? true : false;
12794     
12795     // crashes Safari in some instances
12796     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12797     
12798     var pad = function(n) {
12799         return n < 10 ? "0" + n : n;
12800     };
12801     
12802     var m = {
12803         "\b": '\\b',
12804         "\t": '\\t',
12805         "\n": '\\n',
12806         "\f": '\\f',
12807         "\r": '\\r',
12808         '"' : '\\"',
12809         "\\": '\\\\'
12810     };
12811
12812     var encodeString = function(s){
12813         if (/["\\\x00-\x1f]/.test(s)) {
12814             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12815                 var c = m[b];
12816                 if(c){
12817                     return c;
12818                 }
12819                 c = b.charCodeAt();
12820                 return "\\u00" +
12821                     Math.floor(c / 16).toString(16) +
12822                     (c % 16).toString(16);
12823             }) + '"';
12824         }
12825         return '"' + s + '"';
12826     };
12827     
12828     var encodeArray = function(o){
12829         var a = ["["], b, i, l = o.length, v;
12830             for (i = 0; i < l; i += 1) {
12831                 v = o[i];
12832                 switch (typeof v) {
12833                     case "undefined":
12834                     case "function":
12835                     case "unknown":
12836                         break;
12837                     default:
12838                         if (b) {
12839                             a.push(',');
12840                         }
12841                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12842                         b = true;
12843                 }
12844             }
12845             a.push("]");
12846             return a.join("");
12847     };
12848     
12849     var encodeDate = function(o){
12850         return '"' + o.getFullYear() + "-" +
12851                 pad(o.getMonth() + 1) + "-" +
12852                 pad(o.getDate()) + "T" +
12853                 pad(o.getHours()) + ":" +
12854                 pad(o.getMinutes()) + ":" +
12855                 pad(o.getSeconds()) + '"';
12856     };
12857     
12858     /**
12859      * Encodes an Object, Array or other value
12860      * @param {Mixed} o The variable to encode
12861      * @return {String} The JSON string
12862      */
12863     this.encode = function(o)
12864     {
12865         // should this be extended to fully wrap stringify..
12866         
12867         if(typeof o == "undefined" || o === null){
12868             return "null";
12869         }else if(o instanceof Array){
12870             return encodeArray(o);
12871         }else if(o instanceof Date){
12872             return encodeDate(o);
12873         }else if(typeof o == "string"){
12874             return encodeString(o);
12875         }else if(typeof o == "number"){
12876             return isFinite(o) ? String(o) : "null";
12877         }else if(typeof o == "boolean"){
12878             return String(o);
12879         }else {
12880             var a = ["{"], b, i, v;
12881             for (i in o) {
12882                 if(!useHasOwn || o.hasOwnProperty(i)) {
12883                     v = o[i];
12884                     switch (typeof v) {
12885                     case "undefined":
12886                     case "function":
12887                     case "unknown":
12888                         break;
12889                     default:
12890                         if(b){
12891                             a.push(',');
12892                         }
12893                         a.push(this.encode(i), ":",
12894                                 v === null ? "null" : this.encode(v));
12895                         b = true;
12896                     }
12897                 }
12898             }
12899             a.push("}");
12900             return a.join("");
12901         }
12902     };
12903     
12904     /**
12905      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12906      * @param {String} json The JSON string
12907      * @return {Object} The resulting object
12908      */
12909     this.decode = function(json){
12910         
12911         return  /** eval:var:json */ eval("(" + json + ')');
12912     };
12913 })();
12914 /** 
12915  * Shorthand for {@link Roo.util.JSON#encode}
12916  * @member Roo encode 
12917  * @method */
12918 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12919 /** 
12920  * Shorthand for {@link Roo.util.JSON#decode}
12921  * @member Roo decode 
12922  * @method */
12923 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12924 /*
12925  * Based on:
12926  * Ext JS Library 1.1.1
12927  * Copyright(c) 2006-2007, Ext JS, LLC.
12928  *
12929  * Originally Released Under LGPL - original licence link has changed is not relivant.
12930  *
12931  * Fork - LGPL
12932  * <script type="text/javascript">
12933  */
12934  
12935 /**
12936  * @class Roo.util.Format
12937  * Reusable data formatting functions
12938  * @singleton
12939  */
12940 Roo.util.Format = function(){
12941     var trimRe = /^\s+|\s+$/g;
12942     return {
12943         /**
12944          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12945          * @param {String} value The string to truncate
12946          * @param {Number} length The maximum length to allow before truncating
12947          * @return {String} The converted text
12948          */
12949         ellipsis : function(value, len){
12950             if(value && value.length > len){
12951                 return value.substr(0, len-3)+"...";
12952             }
12953             return value;
12954         },
12955
12956         /**
12957          * Checks a reference and converts it to empty string if it is undefined
12958          * @param {Mixed} value Reference to check
12959          * @return {Mixed} Empty string if converted, otherwise the original value
12960          */
12961         undef : function(value){
12962             return typeof value != "undefined" ? value : "";
12963         },
12964
12965         /**
12966          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12967          * @param {String} value The string to encode
12968          * @return {String} The encoded text
12969          */
12970         htmlEncode : function(value){
12971             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12972         },
12973
12974         /**
12975          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12976          * @param {String} value The string to decode
12977          * @return {String} The decoded text
12978          */
12979         htmlDecode : function(value){
12980             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12981         },
12982
12983         /**
12984          * Trims any whitespace from either side of a string
12985          * @param {String} value The text to trim
12986          * @return {String} The trimmed text
12987          */
12988         trim : function(value){
12989             return String(value).replace(trimRe, "");
12990         },
12991
12992         /**
12993          * Returns a substring from within an original string
12994          * @param {String} value The original text
12995          * @param {Number} start The start index of the substring
12996          * @param {Number} length The length of the substring
12997          * @return {String} The substring
12998          */
12999         substr : function(value, start, length){
13000             return String(value).substr(start, length);
13001         },
13002
13003         /**
13004          * Converts a string to all lower case letters
13005          * @param {String} value The text to convert
13006          * @return {String} The converted text
13007          */
13008         lowercase : function(value){
13009             return String(value).toLowerCase();
13010         },
13011
13012         /**
13013          * Converts a string to all upper case letters
13014          * @param {String} value The text to convert
13015          * @return {String} The converted text
13016          */
13017         uppercase : function(value){
13018             return String(value).toUpperCase();
13019         },
13020
13021         /**
13022          * Converts the first character only of a string to upper case
13023          * @param {String} value The text to convert
13024          * @return {String} The converted text
13025          */
13026         capitalize : function(value){
13027             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13028         },
13029
13030         // private
13031         call : function(value, fn){
13032             if(arguments.length > 2){
13033                 var args = Array.prototype.slice.call(arguments, 2);
13034                 args.unshift(value);
13035                  
13036                 return /** eval:var:value */  eval(fn).apply(window, args);
13037             }else{
13038                 /** eval:var:value */
13039                 return /** eval:var:value */ eval(fn).call(window, value);
13040             }
13041         },
13042
13043        
13044         /**
13045          * safer version of Math.toFixed..??/
13046          * @param {Number/String} value The numeric value to format
13047          * @param {Number/String} value Decimal places 
13048          * @return {String} The formatted currency string
13049          */
13050         toFixed : function(v, n)
13051         {
13052             // why not use to fixed - precision is buggered???
13053             if (!n) {
13054                 return Math.round(v-0);
13055             }
13056             var fact = Math.pow(10,n+1);
13057             v = (Math.round((v-0)*fact))/fact;
13058             var z = (''+fact).substring(2);
13059             if (v == Math.floor(v)) {
13060                 return Math.floor(v) + '.' + z;
13061             }
13062             
13063             // now just padd decimals..
13064             var ps = String(v).split('.');
13065             var fd = (ps[1] + z);
13066             var r = fd.substring(0,n); 
13067             var rm = fd.substring(n); 
13068             if (rm < 5) {
13069                 return ps[0] + '.' + r;
13070             }
13071             r*=1; // turn it into a number;
13072             r++;
13073             if (String(r).length != n) {
13074                 ps[0]*=1;
13075                 ps[0]++;
13076                 r = String(r).substring(1); // chop the end off.
13077             }
13078             
13079             return ps[0] + '.' + r;
13080              
13081         },
13082         
13083         /**
13084          * Format a number as US currency
13085          * @param {Number/String} value The numeric value to format
13086          * @return {String} The formatted currency string
13087          */
13088         usMoney : function(v){
13089             v = (Math.round((v-0)*100))/100;
13090             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13091             v = String(v);
13092             var ps = v.split('.');
13093             var whole = ps[0];
13094             var sub = ps[1] ? '.'+ ps[1] : '.00';
13095             var r = /(\d+)(\d{3})/;
13096             while (r.test(whole)) {
13097                 whole = whole.replace(r, '$1' + ',' + '$2');
13098             }
13099             return "$" + whole + sub ;
13100         },
13101         
13102         /**
13103          * Parse a value into a formatted date using the specified format pattern.
13104          * @param {Mixed} value The value to format
13105          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13106          * @return {String} The formatted date string
13107          */
13108         date : function(v, format){
13109             if(!v){
13110                 return "";
13111             }
13112             if(!(v instanceof Date)){
13113                 v = new Date(Date.parse(v));
13114             }
13115             return v.dateFormat(format || "m/d/Y");
13116         },
13117
13118         /**
13119          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13120          * @param {String} format Any valid date format string
13121          * @return {Function} The date formatting function
13122          */
13123         dateRenderer : function(format){
13124             return function(v){
13125                 return Roo.util.Format.date(v, format);  
13126             };
13127         },
13128
13129         // private
13130         stripTagsRE : /<\/?[^>]+>/gi,
13131         
13132         /**
13133          * Strips all HTML tags
13134          * @param {Mixed} value The text from which to strip tags
13135          * @return {String} The stripped text
13136          */
13137         stripTags : function(v){
13138             return !v ? v : String(v).replace(this.stripTagsRE, "");
13139         }
13140     };
13141 }();/*
13142  * Based on:
13143  * Ext JS Library 1.1.1
13144  * Copyright(c) 2006-2007, Ext JS, LLC.
13145  *
13146  * Originally Released Under LGPL - original licence link has changed is not relivant.
13147  *
13148  * Fork - LGPL
13149  * <script type="text/javascript">
13150  */
13151
13152
13153  
13154
13155 /**
13156  * @class Roo.MasterTemplate
13157  * @extends Roo.Template
13158  * Provides a template that can have child templates. The syntax is:
13159 <pre><code>
13160 var t = new Roo.MasterTemplate(
13161         '&lt;select name="{name}"&gt;',
13162                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13163         '&lt;/select&gt;'
13164 );
13165 t.add('options', {value: 'foo', text: 'bar'});
13166 // or you can add multiple child elements in one shot
13167 t.addAll('options', [
13168     {value: 'foo', text: 'bar'},
13169     {value: 'foo2', text: 'bar2'},
13170     {value: 'foo3', text: 'bar3'}
13171 ]);
13172 // then append, applying the master template values
13173 t.append('my-form', {name: 'my-select'});
13174 </code></pre>
13175 * A name attribute for the child template is not required if you have only one child
13176 * template or you want to refer to them by index.
13177  */
13178 Roo.MasterTemplate = function(){
13179     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13180     this.originalHtml = this.html;
13181     var st = {};
13182     var m, re = this.subTemplateRe;
13183     re.lastIndex = 0;
13184     var subIndex = 0;
13185     while(m = re.exec(this.html)){
13186         var name = m[1], content = m[2];
13187         st[subIndex] = {
13188             name: name,
13189             index: subIndex,
13190             buffer: [],
13191             tpl : new Roo.Template(content)
13192         };
13193         if(name){
13194             st[name] = st[subIndex];
13195         }
13196         st[subIndex].tpl.compile();
13197         st[subIndex].tpl.call = this.call.createDelegate(this);
13198         subIndex++;
13199     }
13200     this.subCount = subIndex;
13201     this.subs = st;
13202 };
13203 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13204     /**
13205     * The regular expression used to match sub templates
13206     * @type RegExp
13207     * @property
13208     */
13209     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13210
13211     /**
13212      * Applies the passed values to a child template.
13213      * @param {String/Number} name (optional) The name or index of the child template
13214      * @param {Array/Object} values The values to be applied to the template
13215      * @return {MasterTemplate} this
13216      */
13217      add : function(name, values){
13218         if(arguments.length == 1){
13219             values = arguments[0];
13220             name = 0;
13221         }
13222         var s = this.subs[name];
13223         s.buffer[s.buffer.length] = s.tpl.apply(values);
13224         return this;
13225     },
13226
13227     /**
13228      * Applies all the passed values to a child template.
13229      * @param {String/Number} name (optional) The name or index of the child template
13230      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13231      * @param {Boolean} reset (optional) True to reset the template first
13232      * @return {MasterTemplate} this
13233      */
13234     fill : function(name, values, reset){
13235         var a = arguments;
13236         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13237             values = a[0];
13238             name = 0;
13239             reset = a[1];
13240         }
13241         if(reset){
13242             this.reset();
13243         }
13244         for(var i = 0, len = values.length; i < len; i++){
13245             this.add(name, values[i]);
13246         }
13247         return this;
13248     },
13249
13250     /**
13251      * Resets the template for reuse
13252      * @return {MasterTemplate} this
13253      */
13254      reset : function(){
13255         var s = this.subs;
13256         for(var i = 0; i < this.subCount; i++){
13257             s[i].buffer = [];
13258         }
13259         return this;
13260     },
13261
13262     applyTemplate : function(values){
13263         var s = this.subs;
13264         var replaceIndex = -1;
13265         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13266             return s[++replaceIndex].buffer.join("");
13267         });
13268         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13269     },
13270
13271     apply : function(){
13272         return this.applyTemplate.apply(this, arguments);
13273     },
13274
13275     compile : function(){return this;}
13276 });
13277
13278 /**
13279  * Alias for fill().
13280  * @method
13281  */
13282 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13283  /**
13284  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13285  * var tpl = Roo.MasterTemplate.from('element-id');
13286  * @param {String/HTMLElement} el
13287  * @param {Object} config
13288  * @static
13289  */
13290 Roo.MasterTemplate.from = function(el, config){
13291     el = Roo.getDom(el);
13292     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13293 };/*
13294  * Based on:
13295  * Ext JS Library 1.1.1
13296  * Copyright(c) 2006-2007, Ext JS, LLC.
13297  *
13298  * Originally Released Under LGPL - original licence link has changed is not relivant.
13299  *
13300  * Fork - LGPL
13301  * <script type="text/javascript">
13302  */
13303
13304  
13305 /**
13306  * @class Roo.util.CSS
13307  * Utility class for manipulating CSS rules
13308  * @singleton
13309  */
13310 Roo.util.CSS = function(){
13311         var rules = null;
13312         var doc = document;
13313
13314     var camelRe = /(-[a-z])/gi;
13315     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13316
13317    return {
13318    /**
13319     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13320     * tag and appended to the HEAD of the document.
13321     * @param {String|Object} cssText The text containing the css rules
13322     * @param {String} id An id to add to the stylesheet for later removal
13323     * @return {StyleSheet}
13324     */
13325     createStyleSheet : function(cssText, id){
13326         var ss;
13327         var head = doc.getElementsByTagName("head")[0];
13328         var nrules = doc.createElement("style");
13329         nrules.setAttribute("type", "text/css");
13330         if(id){
13331             nrules.setAttribute("id", id);
13332         }
13333         if (typeof(cssText) != 'string') {
13334             // support object maps..
13335             // not sure if this a good idea.. 
13336             // perhaps it should be merged with the general css handling
13337             // and handle js style props.
13338             var cssTextNew = [];
13339             for(var n in cssText) {
13340                 var citems = [];
13341                 for(var k in cssText[n]) {
13342                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13343                 }
13344                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13345                 
13346             }
13347             cssText = cssTextNew.join("\n");
13348             
13349         }
13350        
13351        
13352        if(Roo.isIE){
13353            head.appendChild(nrules);
13354            ss = nrules.styleSheet;
13355            ss.cssText = cssText;
13356        }else{
13357            try{
13358                 nrules.appendChild(doc.createTextNode(cssText));
13359            }catch(e){
13360                nrules.cssText = cssText; 
13361            }
13362            head.appendChild(nrules);
13363            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13364        }
13365        this.cacheStyleSheet(ss);
13366        return ss;
13367    },
13368
13369    /**
13370     * Removes a style or link tag by id
13371     * @param {String} id The id of the tag
13372     */
13373    removeStyleSheet : function(id){
13374        var existing = doc.getElementById(id);
13375        if(existing){
13376            existing.parentNode.removeChild(existing);
13377        }
13378    },
13379
13380    /**
13381     * Dynamically swaps an existing stylesheet reference for a new one
13382     * @param {String} id The id of an existing link tag to remove
13383     * @param {String} url The href of the new stylesheet to include
13384     */
13385    swapStyleSheet : function(id, url){
13386        this.removeStyleSheet(id);
13387        var ss = doc.createElement("link");
13388        ss.setAttribute("rel", "stylesheet");
13389        ss.setAttribute("type", "text/css");
13390        ss.setAttribute("id", id);
13391        ss.setAttribute("href", url);
13392        doc.getElementsByTagName("head")[0].appendChild(ss);
13393    },
13394    
13395    /**
13396     * Refresh the rule cache if you have dynamically added stylesheets
13397     * @return {Object} An object (hash) of rules indexed by selector
13398     */
13399    refreshCache : function(){
13400        return this.getRules(true);
13401    },
13402
13403    // private
13404    cacheStyleSheet : function(stylesheet){
13405        if(!rules){
13406            rules = {};
13407        }
13408        try{// try catch for cross domain access issue
13409            var ssRules = stylesheet.cssRules || stylesheet.rules;
13410            for(var j = ssRules.length-1; j >= 0; --j){
13411                rules[ssRules[j].selectorText] = ssRules[j];
13412            }
13413        }catch(e){}
13414    },
13415    
13416    /**
13417     * Gets all css rules for the document
13418     * @param {Boolean} refreshCache true to refresh the internal cache
13419     * @return {Object} An object (hash) of rules indexed by selector
13420     */
13421    getRules : function(refreshCache){
13422                 if(rules == null || refreshCache){
13423                         rules = {};
13424                         var ds = doc.styleSheets;
13425                         for(var i =0, len = ds.length; i < len; i++){
13426                             try{
13427                         this.cacheStyleSheet(ds[i]);
13428                     }catch(e){} 
13429                 }
13430                 }
13431                 return rules;
13432         },
13433         
13434         /**
13435     * Gets an an individual CSS rule by selector(s)
13436     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13437     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13438     * @return {CSSRule} The CSS rule or null if one is not found
13439     */
13440    getRule : function(selector, refreshCache){
13441                 var rs = this.getRules(refreshCache);
13442                 if(!(selector instanceof Array)){
13443                     return rs[selector];
13444                 }
13445                 for(var i = 0; i < selector.length; i++){
13446                         if(rs[selector[i]]){
13447                                 return rs[selector[i]];
13448                         }
13449                 }
13450                 return null;
13451         },
13452         
13453         
13454         /**
13455     * Updates a rule property
13456     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13457     * @param {String} property The css property
13458     * @param {String} value The new value for the property
13459     * @return {Boolean} true If a rule was found and updated
13460     */
13461    updateRule : function(selector, property, value){
13462                 if(!(selector instanceof Array)){
13463                         var rule = this.getRule(selector);
13464                         if(rule){
13465                                 rule.style[property.replace(camelRe, camelFn)] = value;
13466                                 return true;
13467                         }
13468                 }else{
13469                         for(var i = 0; i < selector.length; i++){
13470                                 if(this.updateRule(selector[i], property, value)){
13471                                         return true;
13472                                 }
13473                         }
13474                 }
13475                 return false;
13476         }
13477    };   
13478 }();/*
13479  * Based on:
13480  * Ext JS Library 1.1.1
13481  * Copyright(c) 2006-2007, Ext JS, LLC.
13482  *
13483  * Originally Released Under LGPL - original licence link has changed is not relivant.
13484  *
13485  * Fork - LGPL
13486  * <script type="text/javascript">
13487  */
13488
13489  
13490
13491 /**
13492  * @class Roo.util.ClickRepeater
13493  * @extends Roo.util.Observable
13494  * 
13495  * A wrapper class which can be applied to any element. Fires a "click" event while the
13496  * mouse is pressed. The interval between firings may be specified in the config but
13497  * defaults to 10 milliseconds.
13498  * 
13499  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13500  * 
13501  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13502  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13503  * Similar to an autorepeat key delay.
13504  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13505  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13506  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13507  *           "interval" and "delay" are ignored. "immediate" is honored.
13508  * @cfg {Boolean} preventDefault True to prevent the default click event
13509  * @cfg {Boolean} stopDefault True to stop the default click event
13510  * 
13511  * @history
13512  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13513  *     2007-02-02 jvs Renamed to ClickRepeater
13514  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13515  *
13516  *  @constructor
13517  * @param {String/HTMLElement/Element} el The element to listen on
13518  * @param {Object} config
13519  **/
13520 Roo.util.ClickRepeater = function(el, config)
13521 {
13522     this.el = Roo.get(el);
13523     this.el.unselectable();
13524
13525     Roo.apply(this, config);
13526
13527     this.addEvents({
13528     /**
13529      * @event mousedown
13530      * Fires when the mouse button is depressed.
13531      * @param {Roo.util.ClickRepeater} this
13532      */
13533         "mousedown" : true,
13534     /**
13535      * @event click
13536      * Fires on a specified interval during the time the element is pressed.
13537      * @param {Roo.util.ClickRepeater} this
13538      */
13539         "click" : true,
13540     /**
13541      * @event mouseup
13542      * Fires when the mouse key is released.
13543      * @param {Roo.util.ClickRepeater} this
13544      */
13545         "mouseup" : true
13546     });
13547
13548     this.el.on("mousedown", this.handleMouseDown, this);
13549     if(this.preventDefault || this.stopDefault){
13550         this.el.on("click", function(e){
13551             if(this.preventDefault){
13552                 e.preventDefault();
13553             }
13554             if(this.stopDefault){
13555                 e.stopEvent();
13556             }
13557         }, this);
13558     }
13559
13560     // allow inline handler
13561     if(this.handler){
13562         this.on("click", this.handler,  this.scope || this);
13563     }
13564
13565     Roo.util.ClickRepeater.superclass.constructor.call(this);
13566 };
13567
13568 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13569     interval : 20,
13570     delay: 250,
13571     preventDefault : true,
13572     stopDefault : false,
13573     timer : 0,
13574
13575     // private
13576     handleMouseDown : function(){
13577         clearTimeout(this.timer);
13578         this.el.blur();
13579         if(this.pressClass){
13580             this.el.addClass(this.pressClass);
13581         }
13582         this.mousedownTime = new Date();
13583
13584         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13585         this.el.on("mouseout", this.handleMouseOut, this);
13586
13587         this.fireEvent("mousedown", this);
13588         this.fireEvent("click", this);
13589         
13590         this.timer = this.click.defer(this.delay || this.interval, this);
13591     },
13592
13593     // private
13594     click : function(){
13595         this.fireEvent("click", this);
13596         this.timer = this.click.defer(this.getInterval(), this);
13597     },
13598
13599     // private
13600     getInterval: function(){
13601         if(!this.accelerate){
13602             return this.interval;
13603         }
13604         var pressTime = this.mousedownTime.getElapsed();
13605         if(pressTime < 500){
13606             return 400;
13607         }else if(pressTime < 1700){
13608             return 320;
13609         }else if(pressTime < 2600){
13610             return 250;
13611         }else if(pressTime < 3500){
13612             return 180;
13613         }else if(pressTime < 4400){
13614             return 140;
13615         }else if(pressTime < 5300){
13616             return 80;
13617         }else if(pressTime < 6200){
13618             return 50;
13619         }else{
13620             return 10;
13621         }
13622     },
13623
13624     // private
13625     handleMouseOut : function(){
13626         clearTimeout(this.timer);
13627         if(this.pressClass){
13628             this.el.removeClass(this.pressClass);
13629         }
13630         this.el.on("mouseover", this.handleMouseReturn, this);
13631     },
13632
13633     // private
13634     handleMouseReturn : function(){
13635         this.el.un("mouseover", this.handleMouseReturn);
13636         if(this.pressClass){
13637             this.el.addClass(this.pressClass);
13638         }
13639         this.click();
13640     },
13641
13642     // private
13643     handleMouseUp : function(){
13644         clearTimeout(this.timer);
13645         this.el.un("mouseover", this.handleMouseReturn);
13646         this.el.un("mouseout", this.handleMouseOut);
13647         Roo.get(document).un("mouseup", this.handleMouseUp);
13648         this.el.removeClass(this.pressClass);
13649         this.fireEvent("mouseup", this);
13650     }
13651 });/*
13652  * Based on:
13653  * Ext JS Library 1.1.1
13654  * Copyright(c) 2006-2007, Ext JS, LLC.
13655  *
13656  * Originally Released Under LGPL - original licence link has changed is not relivant.
13657  *
13658  * Fork - LGPL
13659  * <script type="text/javascript">
13660  */
13661
13662  
13663 /**
13664  * @class Roo.KeyNav
13665  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13666  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13667  * way to implement custom navigation schemes for any UI component.</p>
13668  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13669  * pageUp, pageDown, del, home, end.  Usage:</p>
13670  <pre><code>
13671 var nav = new Roo.KeyNav("my-element", {
13672     "left" : function(e){
13673         this.moveLeft(e.ctrlKey);
13674     },
13675     "right" : function(e){
13676         this.moveRight(e.ctrlKey);
13677     },
13678     "enter" : function(e){
13679         this.save();
13680     },
13681     scope : this
13682 });
13683 </code></pre>
13684  * @constructor
13685  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13686  * @param {Object} config The config
13687  */
13688 Roo.KeyNav = function(el, config){
13689     this.el = Roo.get(el);
13690     Roo.apply(this, config);
13691     if(!this.disabled){
13692         this.disabled = true;
13693         this.enable();
13694     }
13695 };
13696
13697 Roo.KeyNav.prototype = {
13698     /**
13699      * @cfg {Boolean} disabled
13700      * True to disable this KeyNav instance (defaults to false)
13701      */
13702     disabled : false,
13703     /**
13704      * @cfg {String} defaultEventAction
13705      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13706      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13707      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13708      */
13709     defaultEventAction: "stopEvent",
13710     /**
13711      * @cfg {Boolean} forceKeyDown
13712      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13713      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13714      * handle keydown instead of keypress.
13715      */
13716     forceKeyDown : false,
13717
13718     // private
13719     prepareEvent : function(e){
13720         var k = e.getKey();
13721         var h = this.keyToHandler[k];
13722         //if(h && this[h]){
13723         //    e.stopPropagation();
13724         //}
13725         if(Roo.isSafari && h && k >= 37 && k <= 40){
13726             e.stopEvent();
13727         }
13728     },
13729
13730     // private
13731     relay : function(e){
13732         var k = e.getKey();
13733         var h = this.keyToHandler[k];
13734         if(h && this[h]){
13735             if(this.doRelay(e, this[h], h) !== true){
13736                 e[this.defaultEventAction]();
13737             }
13738         }
13739     },
13740
13741     // private
13742     doRelay : function(e, h, hname){
13743         return h.call(this.scope || this, e);
13744     },
13745
13746     // possible handlers
13747     enter : false,
13748     left : false,
13749     right : false,
13750     up : false,
13751     down : false,
13752     tab : false,
13753     esc : false,
13754     pageUp : false,
13755     pageDown : false,
13756     del : false,
13757     home : false,
13758     end : false,
13759
13760     // quick lookup hash
13761     keyToHandler : {
13762         37 : "left",
13763         39 : "right",
13764         38 : "up",
13765         40 : "down",
13766         33 : "pageUp",
13767         34 : "pageDown",
13768         46 : "del",
13769         36 : "home",
13770         35 : "end",
13771         13 : "enter",
13772         27 : "esc",
13773         9  : "tab"
13774     },
13775
13776         /**
13777          * Enable this KeyNav
13778          */
13779         enable: function(){
13780                 if(this.disabled){
13781             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13782             // the EventObject will normalize Safari automatically
13783             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13784                 this.el.on("keydown", this.relay,  this);
13785             }else{
13786                 this.el.on("keydown", this.prepareEvent,  this);
13787                 this.el.on("keypress", this.relay,  this);
13788             }
13789                     this.disabled = false;
13790                 }
13791         },
13792
13793         /**
13794          * Disable this KeyNav
13795          */
13796         disable: function(){
13797                 if(!this.disabled){
13798                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13799                 this.el.un("keydown", this.relay);
13800             }else{
13801                 this.el.un("keydown", this.prepareEvent);
13802                 this.el.un("keypress", this.relay);
13803             }
13804                     this.disabled = true;
13805                 }
13806         }
13807 };/*
13808  * Based on:
13809  * Ext JS Library 1.1.1
13810  * Copyright(c) 2006-2007, Ext JS, LLC.
13811  *
13812  * Originally Released Under LGPL - original licence link has changed is not relivant.
13813  *
13814  * Fork - LGPL
13815  * <script type="text/javascript">
13816  */
13817
13818  
13819 /**
13820  * @class Roo.KeyMap
13821  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13822  * The constructor accepts the same config object as defined by {@link #addBinding}.
13823  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13824  * combination it will call the function with this signature (if the match is a multi-key
13825  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13826  * A KeyMap can also handle a string representation of keys.<br />
13827  * Usage:
13828  <pre><code>
13829 // map one key by key code
13830 var map = new Roo.KeyMap("my-element", {
13831     key: 13, // or Roo.EventObject.ENTER
13832     fn: myHandler,
13833     scope: myObject
13834 });
13835
13836 // map multiple keys to one action by string
13837 var map = new Roo.KeyMap("my-element", {
13838     key: "a\r\n\t",
13839     fn: myHandler,
13840     scope: myObject
13841 });
13842
13843 // map multiple keys to multiple actions by strings and array of codes
13844 var map = new Roo.KeyMap("my-element", [
13845     {
13846         key: [10,13],
13847         fn: function(){ alert("Return was pressed"); }
13848     }, {
13849         key: "abc",
13850         fn: function(){ alert('a, b or c was pressed'); }
13851     }, {
13852         key: "\t",
13853         ctrl:true,
13854         shift:true,
13855         fn: function(){ alert('Control + shift + tab was pressed.'); }
13856     }
13857 ]);
13858 </code></pre>
13859  * <b>Note: A KeyMap starts enabled</b>
13860  * @constructor
13861  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13862  * @param {Object} config The config (see {@link #addBinding})
13863  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13864  */
13865 Roo.KeyMap = function(el, config, eventName){
13866     this.el  = Roo.get(el);
13867     this.eventName = eventName || "keydown";
13868     this.bindings = [];
13869     if(config){
13870         this.addBinding(config);
13871     }
13872     this.enable();
13873 };
13874
13875 Roo.KeyMap.prototype = {
13876     /**
13877      * True to stop the event from bubbling and prevent the default browser action if the
13878      * key was handled by the KeyMap (defaults to false)
13879      * @type Boolean
13880      */
13881     stopEvent : false,
13882
13883     /**
13884      * Add a new binding to this KeyMap. The following config object properties are supported:
13885      * <pre>
13886 Property    Type             Description
13887 ----------  ---------------  ----------------------------------------------------------------------
13888 key         String/Array     A single keycode or an array of keycodes to handle
13889 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13890 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13891 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13892 fn          Function         The function to call when KeyMap finds the expected key combination
13893 scope       Object           The scope of the callback function
13894 </pre>
13895      *
13896      * Usage:
13897      * <pre><code>
13898 // Create a KeyMap
13899 var map = new Roo.KeyMap(document, {
13900     key: Roo.EventObject.ENTER,
13901     fn: handleKey,
13902     scope: this
13903 });
13904
13905 //Add a new binding to the existing KeyMap later
13906 map.addBinding({
13907     key: 'abc',
13908     shift: true,
13909     fn: handleKey,
13910     scope: this
13911 });
13912 </code></pre>
13913      * @param {Object/Array} config A single KeyMap config or an array of configs
13914      */
13915         addBinding : function(config){
13916         if(config instanceof Array){
13917             for(var i = 0, len = config.length; i < len; i++){
13918                 this.addBinding(config[i]);
13919             }
13920             return;
13921         }
13922         var keyCode = config.key,
13923             shift = config.shift, 
13924             ctrl = config.ctrl, 
13925             alt = config.alt,
13926             fn = config.fn,
13927             scope = config.scope;
13928         if(typeof keyCode == "string"){
13929             var ks = [];
13930             var keyString = keyCode.toUpperCase();
13931             for(var j = 0, len = keyString.length; j < len; j++){
13932                 ks.push(keyString.charCodeAt(j));
13933             }
13934             keyCode = ks;
13935         }
13936         var keyArray = keyCode instanceof Array;
13937         var handler = function(e){
13938             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13939                 var k = e.getKey();
13940                 if(keyArray){
13941                     for(var i = 0, len = keyCode.length; i < len; i++){
13942                         if(keyCode[i] == k){
13943                           if(this.stopEvent){
13944                               e.stopEvent();
13945                           }
13946                           fn.call(scope || window, k, e);
13947                           return;
13948                         }
13949                     }
13950                 }else{
13951                     if(k == keyCode){
13952                         if(this.stopEvent){
13953                            e.stopEvent();
13954                         }
13955                         fn.call(scope || window, k, e);
13956                     }
13957                 }
13958             }
13959         };
13960         this.bindings.push(handler);  
13961         },
13962
13963     /**
13964      * Shorthand for adding a single key listener
13965      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13966      * following options:
13967      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13968      * @param {Function} fn The function to call
13969      * @param {Object} scope (optional) The scope of the function
13970      */
13971     on : function(key, fn, scope){
13972         var keyCode, shift, ctrl, alt;
13973         if(typeof key == "object" && !(key instanceof Array)){
13974             keyCode = key.key;
13975             shift = key.shift;
13976             ctrl = key.ctrl;
13977             alt = key.alt;
13978         }else{
13979             keyCode = key;
13980         }
13981         this.addBinding({
13982             key: keyCode,
13983             shift: shift,
13984             ctrl: ctrl,
13985             alt: alt,
13986             fn: fn,
13987             scope: scope
13988         })
13989     },
13990
13991     // private
13992     handleKeyDown : function(e){
13993             if(this.enabled){ //just in case
13994             var b = this.bindings;
13995             for(var i = 0, len = b.length; i < len; i++){
13996                 b[i].call(this, e);
13997             }
13998             }
13999         },
14000         
14001         /**
14002          * Returns true if this KeyMap is enabled
14003          * @return {Boolean} 
14004          */
14005         isEnabled : function(){
14006             return this.enabled;  
14007         },
14008         
14009         /**
14010          * Enables this KeyMap
14011          */
14012         enable: function(){
14013                 if(!this.enabled){
14014                     this.el.on(this.eventName, this.handleKeyDown, this);
14015                     this.enabled = true;
14016                 }
14017         },
14018
14019         /**
14020          * Disable this KeyMap
14021          */
14022         disable: function(){
14023                 if(this.enabled){
14024                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14025                     this.enabled = false;
14026                 }
14027         }
14028 };/*
14029  * Based on:
14030  * Ext JS Library 1.1.1
14031  * Copyright(c) 2006-2007, Ext JS, LLC.
14032  *
14033  * Originally Released Under LGPL - original licence link has changed is not relivant.
14034  *
14035  * Fork - LGPL
14036  * <script type="text/javascript">
14037  */
14038
14039  
14040 /**
14041  * @class Roo.util.TextMetrics
14042  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14043  * wide, in pixels, a given block of text will be.
14044  * @singleton
14045  */
14046 Roo.util.TextMetrics = function(){
14047     var shared;
14048     return {
14049         /**
14050          * Measures the size of the specified text
14051          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14052          * that can affect the size of the rendered text
14053          * @param {String} text The text to measure
14054          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14055          * in order to accurately measure the text height
14056          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14057          */
14058         measure : function(el, text, fixedWidth){
14059             if(!shared){
14060                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14061             }
14062             shared.bind(el);
14063             shared.setFixedWidth(fixedWidth || 'auto');
14064             return shared.getSize(text);
14065         },
14066
14067         /**
14068          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14069          * the overhead of multiple calls to initialize the style properties on each measurement.
14070          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14071          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14072          * in order to accurately measure the text height
14073          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14074          */
14075         createInstance : function(el, fixedWidth){
14076             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14077         }
14078     };
14079 }();
14080
14081  
14082
14083 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14084     var ml = new Roo.Element(document.createElement('div'));
14085     document.body.appendChild(ml.dom);
14086     ml.position('absolute');
14087     ml.setLeftTop(-1000, -1000);
14088     ml.hide();
14089
14090     if(fixedWidth){
14091         ml.setWidth(fixedWidth);
14092     }
14093      
14094     var instance = {
14095         /**
14096          * Returns the size of the specified text based on the internal element's style and width properties
14097          * @memberOf Roo.util.TextMetrics.Instance#
14098          * @param {String} text The text to measure
14099          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14100          */
14101         getSize : function(text){
14102             ml.update(text);
14103             var s = ml.getSize();
14104             ml.update('');
14105             return s;
14106         },
14107
14108         /**
14109          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14110          * that can affect the size of the rendered text
14111          * @memberOf Roo.util.TextMetrics.Instance#
14112          * @param {String/HTMLElement} el The element, dom node or id
14113          */
14114         bind : function(el){
14115             ml.setStyle(
14116                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14117             );
14118         },
14119
14120         /**
14121          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14122          * to set a fixed width in order to accurately measure the text height.
14123          * @memberOf Roo.util.TextMetrics.Instance#
14124          * @param {Number} width The width to set on the element
14125          */
14126         setFixedWidth : function(width){
14127             ml.setWidth(width);
14128         },
14129
14130         /**
14131          * Returns the measured width of the specified text
14132          * @memberOf Roo.util.TextMetrics.Instance#
14133          * @param {String} text The text to measure
14134          * @return {Number} width The width in pixels
14135          */
14136         getWidth : function(text){
14137             ml.dom.style.width = 'auto';
14138             return this.getSize(text).width;
14139         },
14140
14141         /**
14142          * Returns the measured height of the specified text.  For multiline text, be sure to call
14143          * {@link #setFixedWidth} if necessary.
14144          * @memberOf Roo.util.TextMetrics.Instance#
14145          * @param {String} text The text to measure
14146          * @return {Number} height The height in pixels
14147          */
14148         getHeight : function(text){
14149             return this.getSize(text).height;
14150         }
14151     };
14152
14153     instance.bind(bindTo);
14154
14155     return instance;
14156 };
14157
14158 // backwards compat
14159 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14160  * Based on:
14161  * Ext JS Library 1.1.1
14162  * Copyright(c) 2006-2007, Ext JS, LLC.
14163  *
14164  * Originally Released Under LGPL - original licence link has changed is not relivant.
14165  *
14166  * Fork - LGPL
14167  * <script type="text/javascript">
14168  */
14169
14170 /**
14171  * @class Roo.state.Provider
14172  * Abstract base class for state provider implementations. This class provides methods
14173  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14174  * Provider interface.
14175  */
14176 Roo.state.Provider = function(){
14177     /**
14178      * @event statechange
14179      * Fires when a state change occurs.
14180      * @param {Provider} this This state provider
14181      * @param {String} key The state key which was changed
14182      * @param {String} value The encoded value for the state
14183      */
14184     this.addEvents({
14185         "statechange": true
14186     });
14187     this.state = {};
14188     Roo.state.Provider.superclass.constructor.call(this);
14189 };
14190 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14191     /**
14192      * Returns the current value for a key
14193      * @param {String} name The key name
14194      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14195      * @return {Mixed} The state data
14196      */
14197     get : function(name, defaultValue){
14198         return typeof this.state[name] == "undefined" ?
14199             defaultValue : this.state[name];
14200     },
14201     
14202     /**
14203      * Clears a value from the state
14204      * @param {String} name The key name
14205      */
14206     clear : function(name){
14207         delete this.state[name];
14208         this.fireEvent("statechange", this, name, null);
14209     },
14210     
14211     /**
14212      * Sets the value for a key
14213      * @param {String} name The key name
14214      * @param {Mixed} value The value to set
14215      */
14216     set : function(name, value){
14217         this.state[name] = value;
14218         this.fireEvent("statechange", this, name, value);
14219     },
14220     
14221     /**
14222      * Decodes a string previously encoded with {@link #encodeValue}.
14223      * @param {String} value The value to decode
14224      * @return {Mixed} The decoded value
14225      */
14226     decodeValue : function(cookie){
14227         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14228         var matches = re.exec(unescape(cookie));
14229         if(!matches || !matches[1]) return; // non state cookie
14230         var type = matches[1];
14231         var v = matches[2];
14232         switch(type){
14233             case "n":
14234                 return parseFloat(v);
14235             case "d":
14236                 return new Date(Date.parse(v));
14237             case "b":
14238                 return (v == "1");
14239             case "a":
14240                 var all = [];
14241                 var values = v.split("^");
14242                 for(var i = 0, len = values.length; i < len; i++){
14243                     all.push(this.decodeValue(values[i]));
14244                 }
14245                 return all;
14246            case "o":
14247                 var all = {};
14248                 var values = v.split("^");
14249                 for(var i = 0, len = values.length; i < len; i++){
14250                     var kv = values[i].split("=");
14251                     all[kv[0]] = this.decodeValue(kv[1]);
14252                 }
14253                 return all;
14254            default:
14255                 return v;
14256         }
14257     },
14258     
14259     /**
14260      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14261      * @param {Mixed} value The value to encode
14262      * @return {String} The encoded value
14263      */
14264     encodeValue : function(v){
14265         var enc;
14266         if(typeof v == "number"){
14267             enc = "n:" + v;
14268         }else if(typeof v == "boolean"){
14269             enc = "b:" + (v ? "1" : "0");
14270         }else if(v instanceof Date){
14271             enc = "d:" + v.toGMTString();
14272         }else if(v instanceof Array){
14273             var flat = "";
14274             for(var i = 0, len = v.length; i < len; i++){
14275                 flat += this.encodeValue(v[i]);
14276                 if(i != len-1) flat += "^";
14277             }
14278             enc = "a:" + flat;
14279         }else if(typeof v == "object"){
14280             var flat = "";
14281             for(var key in v){
14282                 if(typeof v[key] != "function"){
14283                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14284                 }
14285             }
14286             enc = "o:" + flat.substring(0, flat.length-1);
14287         }else{
14288             enc = "s:" + v;
14289         }
14290         return escape(enc);        
14291     }
14292 });
14293
14294 /*
14295  * Based on:
14296  * Ext JS Library 1.1.1
14297  * Copyright(c) 2006-2007, Ext JS, LLC.
14298  *
14299  * Originally Released Under LGPL - original licence link has changed is not relivant.
14300  *
14301  * Fork - LGPL
14302  * <script type="text/javascript">
14303  */
14304 /**
14305  * @class Roo.state.Manager
14306  * This is the global state manager. By default all components that are "state aware" check this class
14307  * for state information if you don't pass them a custom state provider. In order for this class
14308  * to be useful, it must be initialized with a provider when your application initializes.
14309  <pre><code>
14310 // in your initialization function
14311 init : function(){
14312    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14313    ...
14314    // supposed you have a {@link Roo.BorderLayout}
14315    var layout = new Roo.BorderLayout(...);
14316    layout.restoreState();
14317    // or a {Roo.BasicDialog}
14318    var dialog = new Roo.BasicDialog(...);
14319    dialog.restoreState();
14320  </code></pre>
14321  * @singleton
14322  */
14323 Roo.state.Manager = function(){
14324     var provider = new Roo.state.Provider();
14325     
14326     return {
14327         /**
14328          * Configures the default state provider for your application
14329          * @param {Provider} stateProvider The state provider to set
14330          */
14331         setProvider : function(stateProvider){
14332             provider = stateProvider;
14333         },
14334         
14335         /**
14336          * Returns the current value for a key
14337          * @param {String} name The key name
14338          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14339          * @return {Mixed} The state data
14340          */
14341         get : function(key, defaultValue){
14342             return provider.get(key, defaultValue);
14343         },
14344         
14345         /**
14346          * Sets the value for a key
14347          * @param {String} name The key name
14348          * @param {Mixed} value The state data
14349          */
14350          set : function(key, value){
14351             provider.set(key, value);
14352         },
14353         
14354         /**
14355          * Clears a value from the state
14356          * @param {String} name The key name
14357          */
14358         clear : function(key){
14359             provider.clear(key);
14360         },
14361         
14362         /**
14363          * Gets the currently configured state provider
14364          * @return {Provider} The state provider
14365          */
14366         getProvider : function(){
14367             return provider;
14368         }
14369     };
14370 }();
14371 /*
14372  * Based on:
14373  * Ext JS Library 1.1.1
14374  * Copyright(c) 2006-2007, Ext JS, LLC.
14375  *
14376  * Originally Released Under LGPL - original licence link has changed is not relivant.
14377  *
14378  * Fork - LGPL
14379  * <script type="text/javascript">
14380  */
14381 /**
14382  * @class Roo.state.CookieProvider
14383  * @extends Roo.state.Provider
14384  * The default Provider implementation which saves state via cookies.
14385  * <br />Usage:
14386  <pre><code>
14387    var cp = new Roo.state.CookieProvider({
14388        path: "/cgi-bin/",
14389        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14390        domain: "roojs.com"
14391    })
14392    Roo.state.Manager.setProvider(cp);
14393  </code></pre>
14394  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14395  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14396  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14397  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14398  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14399  * domain the page is running on including the 'www' like 'www.roojs.com')
14400  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14401  * @constructor
14402  * Create a new CookieProvider
14403  * @param {Object} config The configuration object
14404  */
14405 Roo.state.CookieProvider = function(config){
14406     Roo.state.CookieProvider.superclass.constructor.call(this);
14407     this.path = "/";
14408     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14409     this.domain = null;
14410     this.secure = false;
14411     Roo.apply(this, config);
14412     this.state = this.readCookies();
14413 };
14414
14415 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14416     // private
14417     set : function(name, value){
14418         if(typeof value == "undefined" || value === null){
14419             this.clear(name);
14420             return;
14421         }
14422         this.setCookie(name, value);
14423         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14424     },
14425
14426     // private
14427     clear : function(name){
14428         this.clearCookie(name);
14429         Roo.state.CookieProvider.superclass.clear.call(this, name);
14430     },
14431
14432     // private
14433     readCookies : function(){
14434         var cookies = {};
14435         var c = document.cookie + ";";
14436         var re = /\s?(.*?)=(.*?);/g;
14437         var matches;
14438         while((matches = re.exec(c)) != null){
14439             var name = matches[1];
14440             var value = matches[2];
14441             if(name && name.substring(0,3) == "ys-"){
14442                 cookies[name.substr(3)] = this.decodeValue(value);
14443             }
14444         }
14445         return cookies;
14446     },
14447
14448     // private
14449     setCookie : function(name, value){
14450         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14451            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14452            ((this.path == null) ? "" : ("; path=" + this.path)) +
14453            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14454            ((this.secure == true) ? "; secure" : "");
14455     },
14456
14457     // private
14458     clearCookie : function(name){
14459         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14460            ((this.path == null) ? "" : ("; path=" + this.path)) +
14461            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14462            ((this.secure == true) ? "; secure" : "");
14463     }
14464 });