roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618
619         /**
620          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621          * you may want to set this to true.
622          * @type Boolean
623          */
624         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
625         
626         
627                 
628         /**
629          * Selects a single element as a Roo Element
630          * This is about as close as you can get to jQuery's $('do crazy stuff')
631          * @param {String} selector The selector/xpath query
632          * @param {Node} root (optional) The start of the query (defaults to document).
633          * @return {Roo.Element}
634          */
635         selectNode : function(selector, root) 
636         {
637             var node = Roo.DomQuery.selectNode(selector,root);
638             return node ? Roo.get(node) : new Roo.Element(false);
639         }
640         
641     });
642
643
644 })();
645
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
648 /*
649  * Based on:
650  * Ext JS Library 1.1.1
651  * Copyright(c) 2006-2007, Ext JS, LLC.
652  *
653  * Originally Released Under LGPL - original licence link has changed is not relivant.
654  *
655  * Fork - LGPL
656  * <script type="text/javascript">
657  */
658
659 (function() {    
660     // wrappedn so fnCleanup is not in global scope...
661     if(Roo.isIE) {
662         function fnCleanUp() {
663             var p = Function.prototype;
664             delete p.createSequence;
665             delete p.defer;
666             delete p.createDelegate;
667             delete p.createCallback;
668             delete p.createInterceptor;
669
670             window.detachEvent("onunload", fnCleanUp);
671         }
672         window.attachEvent("onunload", fnCleanUp);
673     }
674 })();
675
676
677 /**
678  * @class Function
679  * These functions are available on every Function object (any JavaScript function).
680  */
681 Roo.apply(Function.prototype, {
682      /**
683      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685      * Will create a function that is bound to those 2 args.
686      * @return {Function} The new function
687     */
688     createCallback : function(/*args...*/){
689         // make args available, in function below
690         var args = arguments;
691         var method = this;
692         return function() {
693             return method.apply(window, args);
694         };
695     },
696
697     /**
698      * Creates a delegate (callback) that sets the scope to obj.
699      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700      * Will create a function that is automatically scoped to this.
701      * @param {Object} obj (optional) The object for which the scope is set
702      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704      *                                             if a number the args are inserted at the specified position
705      * @return {Function} The new function
706      */
707     createDelegate : function(obj, args, appendArgs){
708         var method = this;
709         return function() {
710             var callArgs = args || arguments;
711             if(appendArgs === true){
712                 callArgs = Array.prototype.slice.call(arguments, 0);
713                 callArgs = callArgs.concat(args);
714             }else if(typeof appendArgs == "number"){
715                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
718             }
719             return method.apply(obj || window, callArgs);
720         };
721     },
722
723     /**
724      * Calls this function after the number of millseconds specified.
725      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726      * @param {Object} obj (optional) The object for which the scope is set
727      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729      *                                             if a number the args are inserted at the specified position
730      * @return {Number} The timeout id that can be used with clearTimeout
731      */
732     defer : function(millis, obj, args, appendArgs){
733         var fn = this.createDelegate(obj, args, appendArgs);
734         if(millis){
735             return setTimeout(fn, millis);
736         }
737         fn();
738         return 0;
739     },
740     /**
741      * Create a combined function call sequence of the original function + the passed function.
742      * The resulting function returns the results of the original function.
743      * The passed fcn is called with the parameters of the original function
744      * @param {Function} fcn The function to sequence
745      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746      * @return {Function} The new function
747      */
748     createSequence : function(fcn, scope){
749         if(typeof fcn != "function"){
750             return this;
751         }
752         var method = this;
753         return function() {
754             var retval = method.apply(this || window, arguments);
755             fcn.apply(scope || this || window, arguments);
756             return retval;
757         };
758     },
759
760     /**
761      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762      * The resulting function returns the results of the original function.
763      * The passed fcn is called with the parameters of the original function.
764      * @addon
765      * @param {Function} fcn The function to call before the original
766      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767      * @return {Function} The new function
768      */
769     createInterceptor : function(fcn, scope){
770         if(typeof fcn != "function"){
771             return this;
772         }
773         var method = this;
774         return function() {
775             fcn.target = this;
776             fcn.method = method;
777             if(fcn.apply(scope || this || window, arguments) === false){
778                 return;
779             }
780             return method.apply(this || window, arguments);
781         };
782     }
783 });
784 /*
785  * Based on:
786  * Ext JS Library 1.1.1
787  * Copyright(c) 2006-2007, Ext JS, LLC.
788  *
789  * Originally Released Under LGPL - original licence link has changed is not relivant.
790  *
791  * Fork - LGPL
792  * <script type="text/javascript">
793  */
794
795 Roo.applyIf(String, {
796     
797     /** @scope String */
798     
799     /**
800      * Escapes the passed string for ' and \
801      * @param {String} string The string to escape
802      * @return {String} The escaped string
803      * @static
804      */
805     escape : function(string) {
806         return string.replace(/('|\\)/g, "\\$1");
807     },
808
809     /**
810      * Pads the left side of a string with a specified character.  This is especially useful
811      * for normalizing number and date strings.  Example usage:
812      * <pre><code>
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
815 </code></pre>
816      * @param {String} string The original string
817      * @param {Number} size The total length of the output string
818      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819      * @return {String} The padded string
820      * @static
821      */
822     leftPad : function (val, size, ch) {
823         var result = new String(val);
824         if(ch === null || ch === undefined || ch === '') {
825             ch = " ";
826         }
827         while (result.length < size) {
828             result = ch + result;
829         }
830         return result;
831     },
832
833     /**
834      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
835      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
836      * <pre><code>
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
840 </code></pre>
841      * @param {String} string The tokenized string to be formatted
842      * @param {String} value1 The value to replace token {0}
843      * @param {String} value2 Etc...
844      * @return {String} The formatted string
845      * @static
846      */
847     format : function(format){
848         var args = Array.prototype.slice.call(arguments, 1);
849         return format.replace(/\{(\d+)\}/g, function(m, i){
850             return Roo.util.Format.htmlEncode(args[i]);
851         });
852     }
853 });
854
855 /**
856  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
857  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
858  * they are already different, the first value passed in is returned.  Note that this method returns the new value
859  * but does not change the current string.
860  * <pre><code>
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
863
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
866 </code></pre>
867  * @param {String} value The value to compare to the current string
868  * @param {String} other The new value to use if the string already equals the first value passed in
869  * @return {String} The new value
870  */
871  
872 String.prototype.toggle = function(value, other){
873     return this == value ? other : value;
874 };/*
875  * Based on:
876  * Ext JS Library 1.1.1
877  * Copyright(c) 2006-2007, Ext JS, LLC.
878  *
879  * Originally Released Under LGPL - original licence link has changed is not relivant.
880  *
881  * Fork - LGPL
882  * <script type="text/javascript">
883  */
884
885  /**
886  * @class Number
887  */
888 Roo.applyIf(Number.prototype, {
889     /**
890      * Checks whether or not the current number is within a desired range.  If the number is already within the
891      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892      * exceeded.  Note that this method returns the constrained value but does not change the current number.
893      * @param {Number} min The minimum number in the range
894      * @param {Number} max The maximum number in the range
895      * @return {Number} The constrained value if outside the range, otherwise the current value
896      */
897     constrain : function(min, max){
898         return Math.min(Math.max(this, min), max);
899     }
900 });/*
901  * Based on:
902  * Ext JS Library 1.1.1
903  * Copyright(c) 2006-2007, Ext JS, LLC.
904  *
905  * Originally Released Under LGPL - original licence link has changed is not relivant.
906  *
907  * Fork - LGPL
908  * <script type="text/javascript">
909  */
910  /**
911  * @class Array
912  */
913 Roo.applyIf(Array.prototype, {
914     /**
915      * Checks whether or not the specified object exists in the array.
916      * @param {Object} o The object to check for
917      * @return {Number} The index of o in the array (or -1 if it is not found)
918      */
919     indexOf : function(o){
920        for (var i = 0, len = this.length; i < len; i++){
921               if(this[i] == o) return i;
922        }
923            return -1;
924     },
925
926     /**
927      * Removes the specified object from the array.  If the object is not found nothing happens.
928      * @param {Object} o The object to remove
929      */
930     remove : function(o){
931        var index = this.indexOf(o);
932        if(index != -1){
933            this.splice(index, 1);
934        }
935     },
936     /**
937      * Map (JS 1.6 compatibility)
938      * @param {Function} function  to call
939      */
940     map : function(fun )
941     {
942         var len = this.length >>> 0;
943         if (typeof fun != "function")
944             throw new TypeError();
945
946         var res = new Array(len);
947         var thisp = arguments[1];
948         for (var i = 0; i < len; i++)
949         {
950             if (i in this)
951                 res[i] = fun.call(thisp, this[i], i, this);
952         }
953
954         return res;
955     }
956     
957 });
958
959
960  /*
961  * Based on:
962  * Ext JS Library 1.1.1
963  * Copyright(c) 2006-2007, Ext JS, LLC.
964  *
965  * Originally Released Under LGPL - original licence link has changed is not relivant.
966  *
967  * Fork - LGPL
968  * <script type="text/javascript">
969  */
970
971 /**
972  * @class Date
973  *
974  * The date parsing and format syntax is a subset of
975  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976  * supported will provide results equivalent to their PHP versions.
977  *
978  * Following is the list of all currently supported formats:
979  *<pre>
980 Sample date:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
982
983 Format  Output      Description
984 ------  ----------  --------------------------------------------------------------
985   d      10         Day of the month, 2 digits with leading zeros
986   D      Wed        A textual representation of a day, three letters
987   j      10         Day of the month without leading zeros
988   l      Wednesday  A full textual representation of the day of the week
989   S      th         English ordinal day of month suffix, 2 chars (use with j)
990   w      3          Numeric representation of the day of the week
991   z      9          The julian date, or day of the year (0-365)
992   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993   F      January    A full textual representation of the month
994   m      01         Numeric representation of a month, with leading zeros
995   M      Jan        Month name abbreviation, three letters
996   n      1          Numeric representation of a month, without leading zeros
997   t      31         Number of days in the given month
998   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
999   Y      2007       A full numeric representation of a year, 4 digits
1000   y      07         A two digit representation of a year
1001   a      pm         Lowercase Ante meridiem and Post meridiem
1002   A      PM         Uppercase Ante meridiem and Post meridiem
1003   g      3          12-hour format of an hour without leading zeros
1004   G      15         24-hour format of an hour without leading zeros
1005   h      03         12-hour format of an hour with leading zeros
1006   H      15         24-hour format of an hour with leading zeros
1007   i      05         Minutes with leading zeros
1008   s      01         Seconds, with leading zeros
1009   O      -0600      Difference to Greenwich time (GMT) in hours
1010   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1011   T      CST        Timezone setting of the machine running the code
1012   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1013 </pre>
1014  *
1015  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1016  * <pre><code>
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d'));                         //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1020 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1021  </code></pre>
1022  *
1023  * Here are some standard date/time patterns that you might find helpful.  They
1024  * are not part of the source of Date.js, but to use them you can simply copy this
1025  * block of code into any script that is included after Date.js and they will also become
1026  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1027  * <pre><code>
1028 Date.patterns = {
1029     ISO8601Long:"Y-m-d H:i:s",
1030     ISO8601Short:"Y-m-d",
1031     ShortDate: "n/j/Y",
1032     LongDate: "l, F d, Y",
1033     FullDateTime: "l, F d, Y g:i:s A",
1034     MonthDay: "F d",
1035     ShortTime: "g:i A",
1036     LongTime: "g:i:s A",
1037     SortableDateTime: "Y-m-d\\TH:i:s",
1038     UniversalSortableDateTime: "Y-m-d H:i:sO",
1039     YearMonth: "F, Y"
1040 };
1041 </code></pre>
1042  *
1043  * Example usage:
1044  * <pre><code>
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1047  </code></pre>
1048  */
1049
1050 /*
1051  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052  * They generate precompiled functions from date formats instead of parsing and
1053  * processing the pattern every time you format a date.  These functions are available
1054  * on every Date object (any javascript function).
1055  *
1056  * The original article and download are here:
1057  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1058  *
1059  */
1060  
1061  
1062  // was in core
1063 /**
1064  Returns the number of milliseconds between this date and date
1065  @param {Date} date (optional) Defaults to now
1066  @return {Number} The diff in milliseconds
1067  @member Date getElapsed
1068  */
1069 Date.prototype.getElapsed = function(date) {
1070         return Math.abs((date || new Date()).getTime()-this.getTime());
1071 };
1072 // was in date file..
1073
1074
1075 // private
1076 Date.parseFunctions = {count:0};
1077 // private
1078 Date.parseRegexes = [];
1079 // private
1080 Date.formatFunctions = {count:0};
1081
1082 // private
1083 Date.prototype.dateFormat = function(format) {
1084     if (Date.formatFunctions[format] == null) {
1085         Date.createNewFormat(format);
1086     }
1087     var func = Date.formatFunctions[format];
1088     return this[func]();
1089 };
1090
1091
1092 /**
1093  * Formats a date given the supplied format string
1094  * @param {String} format The format string
1095  * @return {String} The formatted date
1096  * @method
1097  */
1098 Date.prototype.format = Date.prototype.dateFormat;
1099
1100 // private
1101 Date.createNewFormat = function(format) {
1102     var funcName = "format" + Date.formatFunctions.count++;
1103     Date.formatFunctions[format] = funcName;
1104     var code = "Date.prototype." + funcName + " = function(){return ";
1105     var special = false;
1106     var ch = '';
1107     for (var i = 0; i < format.length; ++i) {
1108         ch = format.charAt(i);
1109         if (!special && ch == "\\") {
1110             special = true;
1111         }
1112         else if (special) {
1113             special = false;
1114             code += "'" + String.escape(ch) + "' + ";
1115         }
1116         else {
1117             code += Date.getFormatCode(ch);
1118         }
1119     }
1120     /** eval:var:zzzzzzzzzzzzz */
1121     eval(code.substring(0, code.length - 3) + ";}");
1122 };
1123
1124 // private
1125 Date.getFormatCode = function(character) {
1126     switch (character) {
1127     case "d":
1128         return "String.leftPad(this.getDate(), 2, '0') + ";
1129     case "D":
1130         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1131     case "j":
1132         return "this.getDate() + ";
1133     case "l":
1134         return "Date.dayNames[this.getDay()] + ";
1135     case "S":
1136         return "this.getSuffix() + ";
1137     case "w":
1138         return "this.getDay() + ";
1139     case "z":
1140         return "this.getDayOfYear() + ";
1141     case "W":
1142         return "this.getWeekOfYear() + ";
1143     case "F":
1144         return "Date.monthNames[this.getMonth()] + ";
1145     case "m":
1146         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1147     case "M":
1148         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1149     case "n":
1150         return "(this.getMonth() + 1) + ";
1151     case "t":
1152         return "this.getDaysInMonth() + ";
1153     case "L":
1154         return "(this.isLeapYear() ? 1 : 0) + ";
1155     case "Y":
1156         return "this.getFullYear() + ";
1157     case "y":
1158         return "('' + this.getFullYear()).substring(2, 4) + ";
1159     case "a":
1160         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1161     case "A":
1162         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1163     case "g":
1164         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1165     case "G":
1166         return "this.getHours() + ";
1167     case "h":
1168         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1169     case "H":
1170         return "String.leftPad(this.getHours(), 2, '0') + ";
1171     case "i":
1172         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1173     case "s":
1174         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1175     case "O":
1176         return "this.getGMTOffset() + ";
1177     case "P":
1178         return "this.getGMTColonOffset() + ";
1179     case "T":
1180         return "this.getTimezone() + ";
1181     case "Z":
1182         return "(this.getTimezoneOffset() * -60) + ";
1183     default:
1184         return "'" + String.escape(character) + "' + ";
1185     }
1186 };
1187
1188 /**
1189  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1191  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1192  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1193  * string or the parse operation will fail.
1194  * Example Usage:
1195 <pre><code>
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1198
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1201
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1204
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1207 </code></pre>
1208  * @param {String} input The unparsed date as a string
1209  * @param {String} format The format the date is in
1210  * @return {Date} The parsed date
1211  * @static
1212  */
1213 Date.parseDate = function(input, format) {
1214     if (Date.parseFunctions[format] == null) {
1215         Date.createParser(format);
1216     }
1217     var func = Date.parseFunctions[format];
1218     return Date[func](input);
1219 };
1220 /**
1221  * @private
1222  */
1223 Date.createParser = function(format) {
1224     var funcName = "parse" + Date.parseFunctions.count++;
1225     var regexNum = Date.parseRegexes.length;
1226     var currentGroup = 1;
1227     Date.parseFunctions[format] = funcName;
1228
1229     var code = "Date." + funcName + " = function(input){\n"
1230         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231         + "var d = new Date();\n"
1232         + "y = d.getFullYear();\n"
1233         + "m = d.getMonth();\n"
1234         + "d = d.getDate();\n"
1235         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236         + "if (results && results.length > 0) {";
1237     var regex = "";
1238
1239     var special = false;
1240     var ch = '';
1241     for (var i = 0; i < format.length; ++i) {
1242         ch = format.charAt(i);
1243         if (!special && ch == "\\") {
1244             special = true;
1245         }
1246         else if (special) {
1247             special = false;
1248             regex += String.escape(ch);
1249         }
1250         else {
1251             var obj = Date.formatCodeToRegex(ch, currentGroup);
1252             currentGroup += obj.g;
1253             regex += obj.s;
1254             if (obj.g && obj.c) {
1255                 code += obj.c;
1256             }
1257         }
1258     }
1259
1260     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261         + "{v = new Date(y, m, d, h, i, s);}\n"
1262         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265         + "{v = new Date(y, m, d, h);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267         + "{v = new Date(y, m, d);}\n"
1268         + "else if (y >= 0 && m >= 0)\n"
1269         + "{v = new Date(y, m);}\n"
1270         + "else if (y >= 0)\n"
1271         + "{v = new Date(y);}\n"
1272         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1275         + ";}";
1276
1277     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278     /** eval:var:zzzzzzzzzzzzz */
1279     eval(code);
1280 };
1281
1282 // private
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284     switch (character) {
1285     case "D":
1286         return {g:0,
1287         c:null,
1288         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1289     case "j":
1290         return {g:1,
1291             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292             s:"(\\d{1,2})"}; // day of month without leading zeroes
1293     case "d":
1294         return {g:1,
1295             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296             s:"(\\d{2})"}; // day of month with leading zeroes
1297     case "l":
1298         return {g:0,
1299             c:null,
1300             s:"(?:" + Date.dayNames.join("|") + ")"};
1301     case "S":
1302         return {g:0,
1303             c:null,
1304             s:"(?:st|nd|rd|th)"};
1305     case "w":
1306         return {g:0,
1307             c:null,
1308             s:"\\d"};
1309     case "z":
1310         return {g:0,
1311             c:null,
1312             s:"(?:\\d{1,3})"};
1313     case "W":
1314         return {g:0,
1315             c:null,
1316             s:"(?:\\d{2})"};
1317     case "F":
1318         return {g:1,
1319             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320             s:"(" + Date.monthNames.join("|") + ")"};
1321     case "M":
1322         return {g:1,
1323             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1325     case "n":
1326         return {g:1,
1327             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1329     case "m":
1330         return {g:1,
1331             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1333     case "t":
1334         return {g:0,
1335             c:null,
1336             s:"\\d{1,2}"};
1337     case "L":
1338         return {g:0,
1339             c:null,
1340             s:"(?:1|0)"};
1341     case "Y":
1342         return {g:1,
1343             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1344             s:"(\\d{4})"};
1345     case "y":
1346         return {g:1,
1347             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1349             s:"(\\d{1,2})"};
1350     case "a":
1351         return {g:1,
1352             c:"if (results[" + currentGroup + "] == 'am') {\n"
1353                 + "if (h == 12) { h = 0; }\n"
1354                 + "} else { if (h < 12) { h += 12; }}",
1355             s:"(am|pm)"};
1356     case "A":
1357         return {g:1,
1358             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359                 + "if (h == 12) { h = 0; }\n"
1360                 + "} else { if (h < 12) { h += 12; }}",
1361             s:"(AM|PM)"};
1362     case "g":
1363     case "G":
1364         return {g:1,
1365             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1367     case "h":
1368     case "H":
1369         return {g:1,
1370             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1372     case "i":
1373         return {g:1,
1374             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1375             s:"(\\d{2})"};
1376     case "s":
1377         return {g:1,
1378             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1379             s:"(\\d{2})"};
1380     case "O":
1381         return {g:1,
1382             c:[
1383                 "o = results[", currentGroup, "];\n",
1384                 "var sn = o.substring(0,1);\n", // get + / - sign
1385                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1389             ].join(""),
1390             s:"([+\-]\\d{4})"};
1391     case "P":
1392         return {g:1,
1393                 c:[
1394                    "o = results[", currentGroup, "];\n",
1395                    "var sn = o.substring(0,1);\n",
1396                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1397                    "var mn = o.substring(4,6) % 60;\n",
1398                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1399                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1400             ].join(""),
1401             s:"([+\-]\\d{4})"};
1402     case "T":
1403         return {g:0,
1404             c:null,
1405             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1406     case "Z":
1407         return {g:1,
1408             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1409                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1410             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1411     default:
1412         return {g:0,
1413             c:null,
1414             s:String.escape(character)};
1415     }
1416 };
1417
1418 /**
1419  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1420  * @return {String} The abbreviated timezone name (e.g. 'CST')
1421  */
1422 Date.prototype.getTimezone = function() {
1423     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1424 };
1425
1426 /**
1427  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1428  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1429  */
1430 Date.prototype.getGMTOffset = function() {
1431     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1432         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1433         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1434 };
1435
1436 /**
1437  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1438  * @return {String} 2-characters representing hours and 2-characters representing minutes
1439  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1440  */
1441 Date.prototype.getGMTColonOffset = function() {
1442         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1443                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1444                 + ":"
1445                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1446 }
1447
1448 /**
1449  * Get the numeric day number of the year, adjusted for leap year.
1450  * @return {Number} 0 through 364 (365 in leap years)
1451  */
1452 Date.prototype.getDayOfYear = function() {
1453     var num = 0;
1454     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1455     for (var i = 0; i < this.getMonth(); ++i) {
1456         num += Date.daysInMonth[i];
1457     }
1458     return num + this.getDate() - 1;
1459 };
1460
1461 /**
1462  * Get the string representation of the numeric week number of the year
1463  * (equivalent to the format specifier 'W').
1464  * @return {String} '00' through '52'
1465  */
1466 Date.prototype.getWeekOfYear = function() {
1467     // Skip to Thursday of this week
1468     var now = this.getDayOfYear() + (4 - this.getDay());
1469     // Find the first Thursday of the year
1470     var jan1 = new Date(this.getFullYear(), 0, 1);
1471     var then = (7 - jan1.getDay() + 4);
1472     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1473 };
1474
1475 /**
1476  * Whether or not the current date is in a leap year.
1477  * @return {Boolean} True if the current date is in a leap year, else false
1478  */
1479 Date.prototype.isLeapYear = function() {
1480     var year = this.getFullYear();
1481     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1482 };
1483
1484 /**
1485  * Get the first day of the current month, adjusted for leap year.  The returned value
1486  * is the numeric day index within the week (0-6) which can be used in conjunction with
1487  * the {@link #monthNames} array to retrieve the textual day name.
1488  * Example:
1489  *<pre><code>
1490 var dt = new Date('1/10/2007');
1491 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1492 </code></pre>
1493  * @return {Number} The day number (0-6)
1494  */
1495 Date.prototype.getFirstDayOfMonth = function() {
1496     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1497     return (day < 0) ? (day + 7) : day;
1498 };
1499
1500 /**
1501  * Get the last day of the current month, adjusted for leap year.  The returned value
1502  * is the numeric day index within the week (0-6) which can be used in conjunction with
1503  * the {@link #monthNames} array to retrieve the textual day name.
1504  * Example:
1505  *<pre><code>
1506 var dt = new Date('1/10/2007');
1507 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1508 </code></pre>
1509  * @return {Number} The day number (0-6)
1510  */
1511 Date.prototype.getLastDayOfMonth = function() {
1512     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1513     return (day < 0) ? (day + 7) : day;
1514 };
1515
1516
1517 /**
1518  * Get the first date of this date's month
1519  * @return {Date}
1520  */
1521 Date.prototype.getFirstDateOfMonth = function() {
1522     return new Date(this.getFullYear(), this.getMonth(), 1);
1523 };
1524
1525 /**
1526  * Get the last date of this date's month
1527  * @return {Date}
1528  */
1529 Date.prototype.getLastDateOfMonth = function() {
1530     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1531 };
1532 /**
1533  * Get the number of days in the current month, adjusted for leap year.
1534  * @return {Number} The number of days in the month
1535  */
1536 Date.prototype.getDaysInMonth = function() {
1537     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1538     return Date.daysInMonth[this.getMonth()];
1539 };
1540
1541 /**
1542  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1543  * @return {String} 'st, 'nd', 'rd' or 'th'
1544  */
1545 Date.prototype.getSuffix = function() {
1546     switch (this.getDate()) {
1547         case 1:
1548         case 21:
1549         case 31:
1550             return "st";
1551         case 2:
1552         case 22:
1553             return "nd";
1554         case 3:
1555         case 23:
1556             return "rd";
1557         default:
1558             return "th";
1559     }
1560 };
1561
1562 // private
1563 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1564
1565 /**
1566  * An array of textual month names.
1567  * Override these values for international dates, for example...
1568  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1569  * @type Array
1570  * @static
1571  */
1572 Date.monthNames =
1573    ["January",
1574     "February",
1575     "March",
1576     "April",
1577     "May",
1578     "June",
1579     "July",
1580     "August",
1581     "September",
1582     "October",
1583     "November",
1584     "December"];
1585
1586 /**
1587  * An array of textual day names.
1588  * Override these values for international dates, for example...
1589  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1590  * @type Array
1591  * @static
1592  */
1593 Date.dayNames =
1594    ["Sunday",
1595     "Monday",
1596     "Tuesday",
1597     "Wednesday",
1598     "Thursday",
1599     "Friday",
1600     "Saturday"];
1601
1602 // private
1603 Date.y2kYear = 50;
1604 // private
1605 Date.monthNumbers = {
1606     Jan:0,
1607     Feb:1,
1608     Mar:2,
1609     Apr:3,
1610     May:4,
1611     Jun:5,
1612     Jul:6,
1613     Aug:7,
1614     Sep:8,
1615     Oct:9,
1616     Nov:10,
1617     Dec:11};
1618
1619 /**
1620  * Creates and returns a new Date instance with the exact same date value as the called instance.
1621  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1622  * variable will also be changed.  When the intention is to create a new variable that will not
1623  * modify the original instance, you should create a clone.
1624  *
1625  * Example of correctly cloning a date:
1626  * <pre><code>
1627 //wrong way:
1628 var orig = new Date('10/1/2006');
1629 var copy = orig;
1630 copy.setDate(5);
1631 document.write(orig);  //returns 'Thu Oct 05 2006'!
1632
1633 //correct way:
1634 var orig = new Date('10/1/2006');
1635 var copy = orig.clone();
1636 copy.setDate(5);
1637 document.write(orig);  //returns 'Thu Oct 01 2006'
1638 </code></pre>
1639  * @return {Date} The new Date instance
1640  */
1641 Date.prototype.clone = function() {
1642         return new Date(this.getTime());
1643 };
1644
1645 /**
1646  * Clears any time information from this date
1647  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1648  @return {Date} this or the clone
1649  */
1650 Date.prototype.clearTime = function(clone){
1651     if(clone){
1652         return this.clone().clearTime();
1653     }
1654     this.setHours(0);
1655     this.setMinutes(0);
1656     this.setSeconds(0);
1657     this.setMilliseconds(0);
1658     return this;
1659 };
1660
1661 // private
1662 // safari setMonth is broken
1663 if(Roo.isSafari){
1664     Date.brokenSetMonth = Date.prototype.setMonth;
1665         Date.prototype.setMonth = function(num){
1666                 if(num <= -1){
1667                         var n = Math.ceil(-num);
1668                         var back_year = Math.ceil(n/12);
1669                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1670                         this.setFullYear(this.getFullYear() - back_year);
1671                         return Date.brokenSetMonth.call(this, month);
1672                 } else {
1673                         return Date.brokenSetMonth.apply(this, arguments);
1674                 }
1675         };
1676 }
1677
1678 /** Date interval constant 
1679 * @static 
1680 * @type String */
1681 Date.MILLI = "ms";
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.SECOND = "s";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.MINUTE = "mi";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.HOUR = "h";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.DAY = "d";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.MONTH = "mo";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.YEAR = "y";
1706
1707 /**
1708  * Provides a convenient method of performing basic date arithmetic.  This method
1709  * does not modify the Date instance being called - it creates and returns
1710  * a new Date instance containing the resulting date value.
1711  *
1712  * Examples:
1713  * <pre><code>
1714 //Basic usage:
1715 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1716 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1717
1718 //Negative values will subtract correctly:
1719 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1720 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1721
1722 //You can even chain several calls together in one line!
1723 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1724 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1725  </code></pre>
1726  *
1727  * @param {String} interval   A valid date interval enum value
1728  * @param {Number} value      The amount to add to the current date
1729  * @return {Date} The new Date instance
1730  */
1731 Date.prototype.add = function(interval, value){
1732   var d = this.clone();
1733   if (!interval || value === 0) return d;
1734   switch(interval.toLowerCase()){
1735     case Date.MILLI:
1736       d.setMilliseconds(this.getMilliseconds() + value);
1737       break;
1738     case Date.SECOND:
1739       d.setSeconds(this.getSeconds() + value);
1740       break;
1741     case Date.MINUTE:
1742       d.setMinutes(this.getMinutes() + value);
1743       break;
1744     case Date.HOUR:
1745       d.setHours(this.getHours() + value);
1746       break;
1747     case Date.DAY:
1748       d.setDate(this.getDate() + value);
1749       break;
1750     case Date.MONTH:
1751       var day = this.getDate();
1752       if(day > 28){
1753           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1754       }
1755       d.setDate(day);
1756       d.setMonth(this.getMonth() + value);
1757       break;
1758     case Date.YEAR:
1759       d.setFullYear(this.getFullYear() + value);
1760       break;
1761   }
1762   return d;
1763 };
1764 /*
1765  * Based on:
1766  * Ext JS Library 1.1.1
1767  * Copyright(c) 2006-2007, Ext JS, LLC.
1768  *
1769  * Originally Released Under LGPL - original licence link has changed is not relivant.
1770  *
1771  * Fork - LGPL
1772  * <script type="text/javascript">
1773  */
1774
1775 Roo.lib.Dom = {
1776     getViewWidth : function(full) {
1777         return full ? this.getDocumentWidth() : this.getViewportWidth();
1778     },
1779
1780     getViewHeight : function(full) {
1781         return full ? this.getDocumentHeight() : this.getViewportHeight();
1782     },
1783
1784     getDocumentHeight: function() {
1785         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1786         return Math.max(scrollHeight, this.getViewportHeight());
1787     },
1788
1789     getDocumentWidth: function() {
1790         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1791         return Math.max(scrollWidth, this.getViewportWidth());
1792     },
1793
1794     getViewportHeight: function() {
1795         var height = self.innerHeight;
1796         var mode = document.compatMode;
1797
1798         if ((mode || Roo.isIE) && !Roo.isOpera) {
1799             height = (mode == "CSS1Compat") ?
1800                      document.documentElement.clientHeight :
1801                      document.body.clientHeight;
1802         }
1803
1804         return height;
1805     },
1806
1807     getViewportWidth: function() {
1808         var width = self.innerWidth;
1809         var mode = document.compatMode;
1810
1811         if (mode || Roo.isIE) {
1812             width = (mode == "CSS1Compat") ?
1813                     document.documentElement.clientWidth :
1814                     document.body.clientWidth;
1815         }
1816         return width;
1817     },
1818
1819     isAncestor : function(p, c) {
1820         p = Roo.getDom(p);
1821         c = Roo.getDom(c);
1822         if (!p || !c) {
1823             return false;
1824         }
1825
1826         if (p.contains && !Roo.isSafari) {
1827             return p.contains(c);
1828         } else if (p.compareDocumentPosition) {
1829             return !!(p.compareDocumentPosition(c) & 16);
1830         } else {
1831             var parent = c.parentNode;
1832             while (parent) {
1833                 if (parent == p) {
1834                     return true;
1835                 }
1836                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1837                     return false;
1838                 }
1839                 parent = parent.parentNode;
1840             }
1841             return false;
1842         }
1843     },
1844
1845     getRegion : function(el) {
1846         return Roo.lib.Region.getRegion(el);
1847     },
1848
1849     getY : function(el) {
1850         return this.getXY(el)[1];
1851     },
1852
1853     getX : function(el) {
1854         return this.getXY(el)[0];
1855     },
1856
1857     getXY : function(el) {
1858         var p, pe, b, scroll, bd = document.body;
1859         el = Roo.getDom(el);
1860         var fly = Roo.lib.AnimBase.fly;
1861         if (el.getBoundingClientRect) {
1862             b = el.getBoundingClientRect();
1863             scroll = fly(document).getScroll();
1864             return [b.left + scroll.left, b.top + scroll.top];
1865         }
1866         var x = 0, y = 0;
1867
1868         p = el;
1869
1870         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1871
1872         while (p) {
1873
1874             x += p.offsetLeft;
1875             y += p.offsetTop;
1876
1877             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1878                 hasAbsolute = true;
1879             }
1880
1881             if (Roo.isGecko) {
1882                 pe = fly(p);
1883
1884                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1885                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1886
1887
1888                 x += bl;
1889                 y += bt;
1890
1891
1892                 if (p != el && pe.getStyle('overflow') != 'visible') {
1893                     x += bl;
1894                     y += bt;
1895                 }
1896             }
1897             p = p.offsetParent;
1898         }
1899
1900         if (Roo.isSafari && hasAbsolute) {
1901             x -= bd.offsetLeft;
1902             y -= bd.offsetTop;
1903         }
1904
1905         if (Roo.isGecko && !hasAbsolute) {
1906             var dbd = fly(bd);
1907             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1908             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1909         }
1910
1911         p = el.parentNode;
1912         while (p && p != bd) {
1913             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1914                 x -= p.scrollLeft;
1915                 y -= p.scrollTop;
1916             }
1917             p = p.parentNode;
1918         }
1919         return [x, y];
1920     },
1921  
1922   
1923
1924
1925     setXY : function(el, xy) {
1926         el = Roo.fly(el, '_setXY');
1927         el.position();
1928         var pts = el.translatePoints(xy);
1929         if (xy[0] !== false) {
1930             el.dom.style.left = pts.left + "px";
1931         }
1932         if (xy[1] !== false) {
1933             el.dom.style.top = pts.top + "px";
1934         }
1935     },
1936
1937     setX : function(el, x) {
1938         this.setXY(el, [x, false]);
1939     },
1940
1941     setY : function(el, y) {
1942         this.setXY(el, [false, y]);
1943     }
1944 };
1945 /*
1946  * Portions of this file are based on pieces of Yahoo User Interface Library
1947  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1948  * YUI licensed under the BSD License:
1949  * http://developer.yahoo.net/yui/license.txt
1950  * <script type="text/javascript">
1951  *
1952  */
1953
1954 Roo.lib.Event = function() {
1955     var loadComplete = false;
1956     var listeners = [];
1957     var unloadListeners = [];
1958     var retryCount = 0;
1959     var onAvailStack = [];
1960     var counter = 0;
1961     var lastError = null;
1962
1963     return {
1964         POLL_RETRYS: 200,
1965         POLL_INTERVAL: 20,
1966         EL: 0,
1967         TYPE: 1,
1968         FN: 2,
1969         WFN: 3,
1970         OBJ: 3,
1971         ADJ_SCOPE: 4,
1972         _interval: null,
1973
1974         startInterval: function() {
1975             if (!this._interval) {
1976                 var self = this;
1977                 var callback = function() {
1978                     self._tryPreloadAttach();
1979                 };
1980                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1981
1982             }
1983         },
1984
1985         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1986             onAvailStack.push({ id:         p_id,
1987                 fn:         p_fn,
1988                 obj:        p_obj,
1989                 override:   p_override,
1990                 checkReady: false    });
1991
1992             retryCount = this.POLL_RETRYS;
1993             this.startInterval();
1994         },
1995
1996
1997         addListener: function(el, eventName, fn) {
1998             el = Roo.getDom(el);
1999             if (!el || !fn) {
2000                 return false;
2001             }
2002
2003             if ("unload" == eventName) {
2004                 unloadListeners[unloadListeners.length] =
2005                 [el, eventName, fn];
2006                 return true;
2007             }
2008
2009             var wrappedFn = function(e) {
2010                 return fn(Roo.lib.Event.getEvent(e));
2011             };
2012
2013             var li = [el, eventName, fn, wrappedFn];
2014
2015             var index = listeners.length;
2016             listeners[index] = li;
2017
2018             this.doAdd(el, eventName, wrappedFn, false);
2019             return true;
2020
2021         },
2022
2023
2024         removeListener: function(el, eventName, fn) {
2025             var i, len;
2026
2027             el = Roo.getDom(el);
2028
2029             if(!fn) {
2030                 return this.purgeElement(el, false, eventName);
2031             }
2032
2033
2034             if ("unload" == eventName) {
2035
2036                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2037                     var li = unloadListeners[i];
2038                     if (li &&
2039                         li[0] == el &&
2040                         li[1] == eventName &&
2041                         li[2] == fn) {
2042                         unloadListeners.splice(i, 1);
2043                         return true;
2044                     }
2045                 }
2046
2047                 return false;
2048             }
2049
2050             var cacheItem = null;
2051
2052
2053             var index = arguments[3];
2054
2055             if ("undefined" == typeof index) {
2056                 index = this._getCacheIndex(el, eventName, fn);
2057             }
2058
2059             if (index >= 0) {
2060                 cacheItem = listeners[index];
2061             }
2062
2063             if (!el || !cacheItem) {
2064                 return false;
2065             }
2066
2067             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2068
2069             delete listeners[index][this.WFN];
2070             delete listeners[index][this.FN];
2071             listeners.splice(index, 1);
2072
2073             return true;
2074
2075         },
2076
2077
2078         getTarget: function(ev, resolveTextNode) {
2079             ev = ev.browserEvent || ev;
2080             var t = ev.target || ev.srcElement;
2081             return this.resolveTextNode(t);
2082         },
2083
2084
2085         resolveTextNode: function(node) {
2086             if (Roo.isSafari && node && 3 == node.nodeType) {
2087                 return node.parentNode;
2088             } else {
2089                 return node;
2090             }
2091         },
2092
2093
2094         getPageX: function(ev) {
2095             ev = ev.browserEvent || ev;
2096             var x = ev.pageX;
2097             if (!x && 0 !== x) {
2098                 x = ev.clientX || 0;
2099
2100                 if (Roo.isIE) {
2101                     x += this.getScroll()[1];
2102                 }
2103             }
2104
2105             return x;
2106         },
2107
2108
2109         getPageY: function(ev) {
2110             ev = ev.browserEvent || ev;
2111             var y = ev.pageY;
2112             if (!y && 0 !== y) {
2113                 y = ev.clientY || 0;
2114
2115                 if (Roo.isIE) {
2116                     y += this.getScroll()[0];
2117                 }
2118             }
2119
2120
2121             return y;
2122         },
2123
2124
2125         getXY: function(ev) {
2126             ev = ev.browserEvent || ev;
2127             return [this.getPageX(ev), this.getPageY(ev)];
2128         },
2129
2130
2131         getRelatedTarget: function(ev) {
2132             ev = ev.browserEvent || ev;
2133             var t = ev.relatedTarget;
2134             if (!t) {
2135                 if (ev.type == "mouseout") {
2136                     t = ev.toElement;
2137                 } else if (ev.type == "mouseover") {
2138                     t = ev.fromElement;
2139                 }
2140             }
2141
2142             return this.resolveTextNode(t);
2143         },
2144
2145
2146         getTime: function(ev) {
2147             ev = ev.browserEvent || ev;
2148             if (!ev.time) {
2149                 var t = new Date().getTime();
2150                 try {
2151                     ev.time = t;
2152                 } catch(ex) {
2153                     this.lastError = ex;
2154                     return t;
2155                 }
2156             }
2157
2158             return ev.time;
2159         },
2160
2161
2162         stopEvent: function(ev) {
2163             this.stopPropagation(ev);
2164             this.preventDefault(ev);
2165         },
2166
2167
2168         stopPropagation: function(ev) {
2169             ev = ev.browserEvent || ev;
2170             if (ev.stopPropagation) {
2171                 ev.stopPropagation();
2172             } else {
2173                 ev.cancelBubble = true;
2174             }
2175         },
2176
2177
2178         preventDefault: function(ev) {
2179             ev = ev.browserEvent || ev;
2180             if(ev.preventDefault) {
2181                 ev.preventDefault();
2182             } else {
2183                 ev.returnValue = false;
2184             }
2185         },
2186
2187
2188         getEvent: function(e) {
2189             var ev = e || window.event;
2190             if (!ev) {
2191                 var c = this.getEvent.caller;
2192                 while (c) {
2193                     ev = c.arguments[0];
2194                     if (ev && Event == ev.constructor) {
2195                         break;
2196                     }
2197                     c = c.caller;
2198                 }
2199             }
2200             return ev;
2201         },
2202
2203
2204         getCharCode: function(ev) {
2205             ev = ev.browserEvent || ev;
2206             return ev.charCode || ev.keyCode || 0;
2207         },
2208
2209
2210         _getCacheIndex: function(el, eventName, fn) {
2211             for (var i = 0,len = listeners.length; i < len; ++i) {
2212                 var li = listeners[i];
2213                 if (li &&
2214                     li[this.FN] == fn &&
2215                     li[this.EL] == el &&
2216                     li[this.TYPE] == eventName) {
2217                     return i;
2218                 }
2219             }
2220
2221             return -1;
2222         },
2223
2224
2225         elCache: {},
2226
2227
2228         getEl: function(id) {
2229             return document.getElementById(id);
2230         },
2231
2232
2233         clearCache: function() {
2234         },
2235
2236
2237         _load: function(e) {
2238             loadComplete = true;
2239             var EU = Roo.lib.Event;
2240
2241
2242             if (Roo.isIE) {
2243                 EU.doRemove(window, "load", EU._load);
2244             }
2245         },
2246
2247
2248         _tryPreloadAttach: function() {
2249
2250             if (this.locked) {
2251                 return false;
2252             }
2253
2254             this.locked = true;
2255
2256
2257             var tryAgain = !loadComplete;
2258             if (!tryAgain) {
2259                 tryAgain = (retryCount > 0);
2260             }
2261
2262
2263             var notAvail = [];
2264             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2265                 var item = onAvailStack[i];
2266                 if (item) {
2267                     var el = this.getEl(item.id);
2268
2269                     if (el) {
2270                         if (!item.checkReady ||
2271                             loadComplete ||
2272                             el.nextSibling ||
2273                             (document && document.body)) {
2274
2275                             var scope = el;
2276                             if (item.override) {
2277                                 if (item.override === true) {
2278                                     scope = item.obj;
2279                                 } else {
2280                                     scope = item.override;
2281                                 }
2282                             }
2283                             item.fn.call(scope, item.obj);
2284                             onAvailStack[i] = null;
2285                         }
2286                     } else {
2287                         notAvail.push(item);
2288                     }
2289                 }
2290             }
2291
2292             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2293
2294             if (tryAgain) {
2295
2296                 this.startInterval();
2297             } else {
2298                 clearInterval(this._interval);
2299                 this._interval = null;
2300             }
2301
2302             this.locked = false;
2303
2304             return true;
2305
2306         },
2307
2308
2309         purgeElement: function(el, recurse, eventName) {
2310             var elListeners = this.getListeners(el, eventName);
2311             if (elListeners) {
2312                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2313                     var l = elListeners[i];
2314                     this.removeListener(el, l.type, l.fn);
2315                 }
2316             }
2317
2318             if (recurse && el && el.childNodes) {
2319                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2320                     this.purgeElement(el.childNodes[i], recurse, eventName);
2321                 }
2322             }
2323         },
2324
2325
2326         getListeners: function(el, eventName) {
2327             var results = [], searchLists;
2328             if (!eventName) {
2329                 searchLists = [listeners, unloadListeners];
2330             } else if (eventName == "unload") {
2331                 searchLists = [unloadListeners];
2332             } else {
2333                 searchLists = [listeners];
2334             }
2335
2336             for (var j = 0; j < searchLists.length; ++j) {
2337                 var searchList = searchLists[j];
2338                 if (searchList && searchList.length > 0) {
2339                     for (var i = 0,len = searchList.length; i < len; ++i) {
2340                         var l = searchList[i];
2341                         if (l && l[this.EL] === el &&
2342                             (!eventName || eventName === l[this.TYPE])) {
2343                             results.push({
2344                                 type:   l[this.TYPE],
2345                                 fn:     l[this.FN],
2346                                 obj:    l[this.OBJ],
2347                                 adjust: l[this.ADJ_SCOPE],
2348                                 index:  i
2349                             });
2350                         }
2351                     }
2352                 }
2353             }
2354
2355             return (results.length) ? results : null;
2356         },
2357
2358
2359         _unload: function(e) {
2360
2361             var EU = Roo.lib.Event, i, j, l, len, index;
2362
2363             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2364                 l = unloadListeners[i];
2365                 if (l) {
2366                     var scope = window;
2367                     if (l[EU.ADJ_SCOPE]) {
2368                         if (l[EU.ADJ_SCOPE] === true) {
2369                             scope = l[EU.OBJ];
2370                         } else {
2371                             scope = l[EU.ADJ_SCOPE];
2372                         }
2373                     }
2374                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2375                     unloadListeners[i] = null;
2376                     l = null;
2377                     scope = null;
2378                 }
2379             }
2380
2381             unloadListeners = null;
2382
2383             if (listeners && listeners.length > 0) {
2384                 j = listeners.length;
2385                 while (j) {
2386                     index = j - 1;
2387                     l = listeners[index];
2388                     if (l) {
2389                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2390                                 l[EU.FN], index);
2391                     }
2392                     j = j - 1;
2393                 }
2394                 l = null;
2395
2396                 EU.clearCache();
2397             }
2398
2399             EU.doRemove(window, "unload", EU._unload);
2400
2401         },
2402
2403
2404         getScroll: function() {
2405             var dd = document.documentElement, db = document.body;
2406             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2407                 return [dd.scrollTop, dd.scrollLeft];
2408             } else if (db) {
2409                 return [db.scrollTop, db.scrollLeft];
2410             } else {
2411                 return [0, 0];
2412             }
2413         },
2414
2415
2416         doAdd: function () {
2417             if (window.addEventListener) {
2418                 return function(el, eventName, fn, capture) {
2419                     el.addEventListener(eventName, fn, (capture));
2420                 };
2421             } else if (window.attachEvent) {
2422                 return function(el, eventName, fn, capture) {
2423                     el.attachEvent("on" + eventName, fn);
2424                 };
2425             } else {
2426                 return function() {
2427                 };
2428             }
2429         }(),
2430
2431
2432         doRemove: function() {
2433             if (window.removeEventListener) {
2434                 return function (el, eventName, fn, capture) {
2435                     el.removeEventListener(eventName, fn, (capture));
2436                 };
2437             } else if (window.detachEvent) {
2438                 return function (el, eventName, fn) {
2439                     el.detachEvent("on" + eventName, fn);
2440                 };
2441             } else {
2442                 return function() {
2443                 };
2444             }
2445         }()
2446     };
2447     
2448 }();
2449 (function() {     
2450    
2451     var E = Roo.lib.Event;
2452     E.on = E.addListener;
2453     E.un = E.removeListener;
2454
2455     if (document && document.body) {
2456         E._load();
2457     } else {
2458         E.doAdd(window, "load", E._load);
2459     }
2460     E.doAdd(window, "unload", E._unload);
2461     E._tryPreloadAttach();
2462 })();
2463
2464 /*
2465  * Portions of this file are based on pieces of Yahoo User Interface Library
2466  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2467  * YUI licensed under the BSD License:
2468  * http://developer.yahoo.net/yui/license.txt
2469  * <script type="text/javascript">
2470  *
2471  */
2472
2473 (function() {
2474     /**
2475      * @class Roo.lib.Ajax
2476      *
2477      */
2478     Roo.lib.Ajax = {
2479         /**
2480          * @static 
2481          */
2482         request : function(method, uri, cb, data, options) {
2483             if(options){
2484                 var hs = options.headers;
2485                 if(hs){
2486                     for(var h in hs){
2487                         if(hs.hasOwnProperty(h)){
2488                             this.initHeader(h, hs[h], false);
2489                         }
2490                     }
2491                 }
2492                 if(options.xmlData){
2493                     this.initHeader('Content-Type', 'text/xml', false);
2494                     method = 'POST';
2495                     data = options.xmlData;
2496                 }
2497             }
2498
2499             return this.asyncRequest(method, uri, cb, data);
2500         },
2501
2502         serializeForm : function(form) {
2503             if(typeof form == 'string') {
2504                 form = (document.getElementById(form) || document.forms[form]);
2505             }
2506
2507             var el, name, val, disabled, data = '', hasSubmit = false;
2508             for (var i = 0; i < form.elements.length; i++) {
2509                 el = form.elements[i];
2510                 disabled = form.elements[i].disabled;
2511                 name = form.elements[i].name;
2512                 val = form.elements[i].value;
2513
2514                 if (!disabled && name){
2515                     switch (el.type)
2516                             {
2517                         case 'select-one':
2518                         case 'select-multiple':
2519                             for (var j = 0; j < el.options.length; j++) {
2520                                 if (el.options[j].selected) {
2521                                     if (Roo.isIE) {
2522                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2523                                     }
2524                                     else {
2525                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2526                                     }
2527                                 }
2528                             }
2529                             break;
2530                         case 'radio':
2531                         case 'checkbox':
2532                             if (el.checked) {
2533                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2534                             }
2535                             break;
2536                         case 'file':
2537
2538                         case undefined:
2539
2540                         case 'reset':
2541
2542                         case 'button':
2543
2544                             break;
2545                         case 'submit':
2546                             if(hasSubmit == false) {
2547                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2548                                 hasSubmit = true;
2549                             }
2550                             break;
2551                         default:
2552                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2553                             break;
2554                     }
2555                 }
2556             }
2557             data = data.substr(0, data.length - 1);
2558             return data;
2559         },
2560
2561         headers:{},
2562
2563         hasHeaders:false,
2564
2565         useDefaultHeader:true,
2566
2567         defaultPostHeader:'application/x-www-form-urlencoded',
2568
2569         useDefaultXhrHeader:true,
2570
2571         defaultXhrHeader:'XMLHttpRequest',
2572
2573         hasDefaultHeaders:true,
2574
2575         defaultHeaders:{},
2576
2577         poll:{},
2578
2579         timeout:{},
2580
2581         pollInterval:50,
2582
2583         transactionId:0,
2584
2585         setProgId:function(id)
2586         {
2587             this.activeX.unshift(id);
2588         },
2589
2590         setDefaultPostHeader:function(b)
2591         {
2592             this.useDefaultHeader = b;
2593         },
2594
2595         setDefaultXhrHeader:function(b)
2596         {
2597             this.useDefaultXhrHeader = b;
2598         },
2599
2600         setPollingInterval:function(i)
2601         {
2602             if (typeof i == 'number' && isFinite(i)) {
2603                 this.pollInterval = i;
2604             }
2605         },
2606
2607         createXhrObject:function(transactionId)
2608         {
2609             var obj,http;
2610             try
2611             {
2612
2613                 http = new XMLHttpRequest();
2614
2615                 obj = { conn:http, tId:transactionId };
2616             }
2617             catch(e)
2618             {
2619                 for (var i = 0; i < this.activeX.length; ++i) {
2620                     try
2621                     {
2622
2623                         http = new ActiveXObject(this.activeX[i]);
2624
2625                         obj = { conn:http, tId:transactionId };
2626                         break;
2627                     }
2628                     catch(e) {
2629                     }
2630                 }
2631             }
2632             finally
2633             {
2634                 return obj;
2635             }
2636         },
2637
2638         getConnectionObject:function()
2639         {
2640             var o;
2641             var tId = this.transactionId;
2642
2643             try
2644             {
2645                 o = this.createXhrObject(tId);
2646                 if (o) {
2647                     this.transactionId++;
2648                 }
2649             }
2650             catch(e) {
2651             }
2652             finally
2653             {
2654                 return o;
2655             }
2656         },
2657
2658         asyncRequest:function(method, uri, callback, postData)
2659         {
2660             var o = this.getConnectionObject();
2661
2662             if (!o) {
2663                 return null;
2664             }
2665             else {
2666                 o.conn.open(method, uri, true);
2667
2668                 if (this.useDefaultXhrHeader) {
2669                     if (!this.defaultHeaders['X-Requested-With']) {
2670                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2671                     }
2672                 }
2673
2674                 if(postData && this.useDefaultHeader){
2675                     this.initHeader('Content-Type', this.defaultPostHeader);
2676                 }
2677
2678                  if (this.hasDefaultHeaders || this.hasHeaders) {
2679                     this.setHeader(o);
2680                 }
2681
2682                 this.handleReadyState(o, callback);
2683                 o.conn.send(postData || null);
2684
2685                 return o;
2686             }
2687         },
2688
2689         handleReadyState:function(o, callback)
2690         {
2691             var oConn = this;
2692
2693             if (callback && callback.timeout) {
2694                 this.timeout[o.tId] = window.setTimeout(function() {
2695                     oConn.abort(o, callback, true);
2696                 }, callback.timeout);
2697             }
2698
2699             this.poll[o.tId] = window.setInterval(
2700                     function() {
2701                         if (o.conn && o.conn.readyState == 4) {
2702                             window.clearInterval(oConn.poll[o.tId]);
2703                             delete oConn.poll[o.tId];
2704
2705                             if(callback && callback.timeout) {
2706                                 window.clearTimeout(oConn.timeout[o.tId]);
2707                                 delete oConn.timeout[o.tId];
2708                             }
2709
2710                             oConn.handleTransactionResponse(o, callback);
2711                         }
2712                     }
2713                     , this.pollInterval);
2714         },
2715
2716         handleTransactionResponse:function(o, callback, isAbort)
2717         {
2718
2719             if (!callback) {
2720                 this.releaseObject(o);
2721                 return;
2722             }
2723
2724             var httpStatus, responseObject;
2725
2726             try
2727             {
2728                 if (o.conn.status !== undefined && o.conn.status != 0) {
2729                     httpStatus = o.conn.status;
2730                 }
2731                 else {
2732                     httpStatus = 13030;
2733                 }
2734             }
2735             catch(e) {
2736
2737
2738                 httpStatus = 13030;
2739             }
2740
2741             if (httpStatus >= 200 && httpStatus < 300) {
2742                 responseObject = this.createResponseObject(o, callback.argument);
2743                 if (callback.success) {
2744                     if (!callback.scope) {
2745                         callback.success(responseObject);
2746                     }
2747                     else {
2748
2749
2750                         callback.success.apply(callback.scope, [responseObject]);
2751                     }
2752                 }
2753             }
2754             else {
2755                 switch (httpStatus) {
2756
2757                     case 12002:
2758                     case 12029:
2759                     case 12030:
2760                     case 12031:
2761                     case 12152:
2762                     case 13030:
2763                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2764                         if (callback.failure) {
2765                             if (!callback.scope) {
2766                                 callback.failure(responseObject);
2767                             }
2768                             else {
2769                                 callback.failure.apply(callback.scope, [responseObject]);
2770                             }
2771                         }
2772                         break;
2773                     default:
2774                         responseObject = this.createResponseObject(o, callback.argument);
2775                         if (callback.failure) {
2776                             if (!callback.scope) {
2777                                 callback.failure(responseObject);
2778                             }
2779                             else {
2780                                 callback.failure.apply(callback.scope, [responseObject]);
2781                             }
2782                         }
2783                 }
2784             }
2785
2786             this.releaseObject(o);
2787             responseObject = null;
2788         },
2789
2790         createResponseObject:function(o, callbackArg)
2791         {
2792             var obj = {};
2793             var headerObj = {};
2794
2795             try
2796             {
2797                 var headerStr = o.conn.getAllResponseHeaders();
2798                 var header = headerStr.split('\n');
2799                 for (var i = 0; i < header.length; i++) {
2800                     var delimitPos = header[i].indexOf(':');
2801                     if (delimitPos != -1) {
2802                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2803                     }
2804                 }
2805             }
2806             catch(e) {
2807             }
2808
2809             obj.tId = o.tId;
2810             obj.status = o.conn.status;
2811             obj.statusText = o.conn.statusText;
2812             obj.getResponseHeader = headerObj;
2813             obj.getAllResponseHeaders = headerStr;
2814             obj.responseText = o.conn.responseText;
2815             obj.responseXML = o.conn.responseXML;
2816
2817             if (typeof callbackArg !== undefined) {
2818                 obj.argument = callbackArg;
2819             }
2820
2821             return obj;
2822         },
2823
2824         createExceptionObject:function(tId, callbackArg, isAbort)
2825         {
2826             var COMM_CODE = 0;
2827             var COMM_ERROR = 'communication failure';
2828             var ABORT_CODE = -1;
2829             var ABORT_ERROR = 'transaction aborted';
2830
2831             var obj = {};
2832
2833             obj.tId = tId;
2834             if (isAbort) {
2835                 obj.status = ABORT_CODE;
2836                 obj.statusText = ABORT_ERROR;
2837             }
2838             else {
2839                 obj.status = COMM_CODE;
2840                 obj.statusText = COMM_ERROR;
2841             }
2842
2843             if (callbackArg) {
2844                 obj.argument = callbackArg;
2845             }
2846
2847             return obj;
2848         },
2849
2850         initHeader:function(label, value, isDefault)
2851         {
2852             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2853
2854             if (headerObj[label] === undefined) {
2855                 headerObj[label] = value;
2856             }
2857             else {
2858
2859
2860                 headerObj[label] = value + "," + headerObj[label];
2861             }
2862
2863             if (isDefault) {
2864                 this.hasDefaultHeaders = true;
2865             }
2866             else {
2867                 this.hasHeaders = true;
2868             }
2869         },
2870
2871
2872         setHeader:function(o)
2873         {
2874             if (this.hasDefaultHeaders) {
2875                 for (var prop in this.defaultHeaders) {
2876                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2877                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2878                     }
2879                 }
2880             }
2881
2882             if (this.hasHeaders) {
2883                 for (var prop in this.headers) {
2884                     if (this.headers.hasOwnProperty(prop)) {
2885                         o.conn.setRequestHeader(prop, this.headers[prop]);
2886                     }
2887                 }
2888                 this.headers = {};
2889                 this.hasHeaders = false;
2890             }
2891         },
2892
2893         resetDefaultHeaders:function() {
2894             delete this.defaultHeaders;
2895             this.defaultHeaders = {};
2896             this.hasDefaultHeaders = false;
2897         },
2898
2899         abort:function(o, callback, isTimeout)
2900         {
2901             if(this.isCallInProgress(o)) {
2902                 o.conn.abort();
2903                 window.clearInterval(this.poll[o.tId]);
2904                 delete this.poll[o.tId];
2905                 if (isTimeout) {
2906                     delete this.timeout[o.tId];
2907                 }
2908
2909                 this.handleTransactionResponse(o, callback, true);
2910
2911                 return true;
2912             }
2913             else {
2914                 return false;
2915             }
2916         },
2917
2918
2919         isCallInProgress:function(o)
2920         {
2921             if (o && o.conn) {
2922                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2923             }
2924             else {
2925
2926                 return false;
2927             }
2928         },
2929
2930
2931         releaseObject:function(o)
2932         {
2933
2934             o.conn = null;
2935
2936             o = null;
2937         },
2938
2939         activeX:[
2940         'MSXML2.XMLHTTP.3.0',
2941         'MSXML2.XMLHTTP',
2942         'Microsoft.XMLHTTP'
2943         ]
2944
2945
2946     };
2947 })();/*
2948  * Portions of this file are based on pieces of Yahoo User Interface Library
2949  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2950  * YUI licensed under the BSD License:
2951  * http://developer.yahoo.net/yui/license.txt
2952  * <script type="text/javascript">
2953  *
2954  */
2955
2956 Roo.lib.Region = function(t, r, b, l) {
2957     this.top = t;
2958     this[1] = t;
2959     this.right = r;
2960     this.bottom = b;
2961     this.left = l;
2962     this[0] = l;
2963 };
2964
2965
2966 Roo.lib.Region.prototype = {
2967     contains : function(region) {
2968         return ( region.left >= this.left &&
2969                  region.right <= this.right &&
2970                  region.top >= this.top &&
2971                  region.bottom <= this.bottom    );
2972
2973     },
2974
2975     getArea : function() {
2976         return ( (this.bottom - this.top) * (this.right - this.left) );
2977     },
2978
2979     intersect : function(region) {
2980         var t = Math.max(this.top, region.top);
2981         var r = Math.min(this.right, region.right);
2982         var b = Math.min(this.bottom, region.bottom);
2983         var l = Math.max(this.left, region.left);
2984
2985         if (b >= t && r >= l) {
2986             return new Roo.lib.Region(t, r, b, l);
2987         } else {
2988             return null;
2989         }
2990     },
2991     union : function(region) {
2992         var t = Math.min(this.top, region.top);
2993         var r = Math.max(this.right, region.right);
2994         var b = Math.max(this.bottom, region.bottom);
2995         var l = Math.min(this.left, region.left);
2996
2997         return new Roo.lib.Region(t, r, b, l);
2998     },
2999
3000     adjust : function(t, l, b, r) {
3001         this.top += t;
3002         this.left += l;
3003         this.right += r;
3004         this.bottom += b;
3005         return this;
3006     }
3007 };
3008
3009 Roo.lib.Region.getRegion = function(el) {
3010     var p = Roo.lib.Dom.getXY(el);
3011
3012     var t = p[1];
3013     var r = p[0] + el.offsetWidth;
3014     var b = p[1] + el.offsetHeight;
3015     var l = p[0];
3016
3017     return new Roo.lib.Region(t, r, b, l);
3018 };
3019 /*
3020  * Portions of this file are based on pieces of Yahoo User Interface Library
3021  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3022  * YUI licensed under the BSD License:
3023  * http://developer.yahoo.net/yui/license.txt
3024  * <script type="text/javascript">
3025  *
3026  */
3027 //@@dep Roo.lib.Region
3028
3029
3030 Roo.lib.Point = function(x, y) {
3031     if (x instanceof Array) {
3032         y = x[1];
3033         x = x[0];
3034     }
3035     this.x = this.right = this.left = this[0] = x;
3036     this.y = this.top = this.bottom = this[1] = y;
3037 };
3038
3039 Roo.lib.Point.prototype = new Roo.lib.Region();
3040 /*
3041  * Portions of this file are based on pieces of Yahoo User Interface Library
3042  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3043  * YUI licensed under the BSD License:
3044  * http://developer.yahoo.net/yui/license.txt
3045  * <script type="text/javascript">
3046  *
3047  */
3048  
3049 (function() {   
3050
3051     Roo.lib.Anim = {
3052         scroll : function(el, args, duration, easing, cb, scope) {
3053             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3054         },
3055
3056         motion : function(el, args, duration, easing, cb, scope) {
3057             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3058         },
3059
3060         color : function(el, args, duration, easing, cb, scope) {
3061             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3062         },
3063
3064         run : function(el, args, duration, easing, cb, scope, type) {
3065             type = type || Roo.lib.AnimBase;
3066             if (typeof easing == "string") {
3067                 easing = Roo.lib.Easing[easing];
3068             }
3069             var anim = new type(el, args, duration, easing);
3070             anim.animateX(function() {
3071                 Roo.callback(cb, scope);
3072             });
3073             return anim;
3074         }
3075     };
3076 })();/*
3077  * Portions of this file are based on pieces of Yahoo User Interface Library
3078  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3079  * YUI licensed under the BSD License:
3080  * http://developer.yahoo.net/yui/license.txt
3081  * <script type="text/javascript">
3082  *
3083  */
3084
3085 (function() {    
3086     var libFlyweight;
3087     
3088     function fly(el) {
3089         if (!libFlyweight) {
3090             libFlyweight = new Roo.Element.Flyweight();
3091         }
3092         libFlyweight.dom = el;
3093         return libFlyweight;
3094     }
3095
3096     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3097     
3098    
3099     
3100     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3101         if (el) {
3102             this.init(el, attributes, duration, method);
3103         }
3104     };
3105
3106     Roo.lib.AnimBase.fly = fly;
3107     
3108     
3109     
3110     Roo.lib.AnimBase.prototype = {
3111
3112         toString: function() {
3113             var el = this.getEl();
3114             var id = el.id || el.tagName;
3115             return ("Anim " + id);
3116         },
3117
3118         patterns: {
3119             noNegatives:        /width|height|opacity|padding/i,
3120             offsetAttribute:  /^((width|height)|(top|left))$/,
3121             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3122             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3123         },
3124
3125
3126         doMethod: function(attr, start, end) {
3127             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3128         },
3129
3130
3131         setAttribute: function(attr, val, unit) {
3132             if (this.patterns.noNegatives.test(attr)) {
3133                 val = (val > 0) ? val : 0;
3134             }
3135
3136             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3137         },
3138
3139
3140         getAttribute: function(attr) {
3141             var el = this.getEl();
3142             var val = fly(el).getStyle(attr);
3143
3144             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3145                 return parseFloat(val);
3146             }
3147
3148             var a = this.patterns.offsetAttribute.exec(attr) || [];
3149             var pos = !!( a[3] );
3150             var box = !!( a[2] );
3151
3152
3153             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3154                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3155             } else {
3156                 val = 0;
3157             }
3158
3159             return val;
3160         },
3161
3162
3163         getDefaultUnit: function(attr) {
3164             if (this.patterns.defaultUnit.test(attr)) {
3165                 return 'px';
3166             }
3167
3168             return '';
3169         },
3170
3171         animateX : function(callback, scope) {
3172             var f = function() {
3173                 this.onComplete.removeListener(f);
3174                 if (typeof callback == "function") {
3175                     callback.call(scope || this, this);
3176                 }
3177             };
3178             this.onComplete.addListener(f, this);
3179             this.animate();
3180         },
3181
3182
3183         setRuntimeAttribute: function(attr) {
3184             var start;
3185             var end;
3186             var attributes = this.attributes;
3187
3188             this.runtimeAttributes[attr] = {};
3189
3190             var isset = function(prop) {
3191                 return (typeof prop !== 'undefined');
3192             };
3193
3194             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3195                 return false;
3196             }
3197
3198             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3199
3200
3201             if (isset(attributes[attr]['to'])) {
3202                 end = attributes[attr]['to'];
3203             } else if (isset(attributes[attr]['by'])) {
3204                 if (start.constructor == Array) {
3205                     end = [];
3206                     for (var i = 0, len = start.length; i < len; ++i) {
3207                         end[i] = start[i] + attributes[attr]['by'][i];
3208                     }
3209                 } else {
3210                     end = start + attributes[attr]['by'];
3211                 }
3212             }
3213
3214             this.runtimeAttributes[attr].start = start;
3215             this.runtimeAttributes[attr].end = end;
3216
3217
3218             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3219         },
3220
3221
3222         init: function(el, attributes, duration, method) {
3223
3224             var isAnimated = false;
3225
3226
3227             var startTime = null;
3228
3229
3230             var actualFrames = 0;
3231
3232
3233             el = Roo.getDom(el);
3234
3235
3236             this.attributes = attributes || {};
3237
3238
3239             this.duration = duration || 1;
3240
3241
3242             this.method = method || Roo.lib.Easing.easeNone;
3243
3244
3245             this.useSeconds = true;
3246
3247
3248             this.currentFrame = 0;
3249
3250
3251             this.totalFrames = Roo.lib.AnimMgr.fps;
3252
3253
3254             this.getEl = function() {
3255                 return el;
3256             };
3257
3258
3259             this.isAnimated = function() {
3260                 return isAnimated;
3261             };
3262
3263
3264             this.getStartTime = function() {
3265                 return startTime;
3266             };
3267
3268             this.runtimeAttributes = {};
3269
3270
3271             this.animate = function() {
3272                 if (this.isAnimated()) {
3273                     return false;
3274                 }
3275
3276                 this.currentFrame = 0;
3277
3278                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3279
3280                 Roo.lib.AnimMgr.registerElement(this);
3281             };
3282
3283
3284             this.stop = function(finish) {
3285                 if (finish) {
3286                     this.currentFrame = this.totalFrames;
3287                     this._onTween.fire();
3288                 }
3289                 Roo.lib.AnimMgr.stop(this);
3290             };
3291
3292             var onStart = function() {
3293                 this.onStart.fire();
3294
3295                 this.runtimeAttributes = {};
3296                 for (var attr in this.attributes) {
3297                     this.setRuntimeAttribute(attr);
3298                 }
3299
3300                 isAnimated = true;
3301                 actualFrames = 0;
3302                 startTime = new Date();
3303             };
3304
3305
3306             var onTween = function() {
3307                 var data = {
3308                     duration: new Date() - this.getStartTime(),
3309                     currentFrame: this.currentFrame
3310                 };
3311
3312                 data.toString = function() {
3313                     return (
3314                             'duration: ' + data.duration +
3315                             ', currentFrame: ' + data.currentFrame
3316                             );
3317                 };
3318
3319                 this.onTween.fire(data);
3320
3321                 var runtimeAttributes = this.runtimeAttributes;
3322
3323                 for (var attr in runtimeAttributes) {
3324                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3325                 }
3326
3327                 actualFrames += 1;
3328             };
3329
3330             var onComplete = function() {
3331                 var actual_duration = (new Date() - startTime) / 1000 ;
3332
3333                 var data = {
3334                     duration: actual_duration,
3335                     frames: actualFrames,
3336                     fps: actualFrames / actual_duration
3337                 };
3338
3339                 data.toString = function() {
3340                     return (
3341                             'duration: ' + data.duration +
3342                             ', frames: ' + data.frames +
3343                             ', fps: ' + data.fps
3344                             );
3345                 };
3346
3347                 isAnimated = false;
3348                 actualFrames = 0;
3349                 this.onComplete.fire(data);
3350             };
3351
3352
3353             this._onStart = new Roo.util.Event(this);
3354             this.onStart = new Roo.util.Event(this);
3355             this.onTween = new Roo.util.Event(this);
3356             this._onTween = new Roo.util.Event(this);
3357             this.onComplete = new Roo.util.Event(this);
3358             this._onComplete = new Roo.util.Event(this);
3359             this._onStart.addListener(onStart);
3360             this._onTween.addListener(onTween);
3361             this._onComplete.addListener(onComplete);
3362         }
3363     };
3364 })();
3365 /*
3366  * Portions of this file are based on pieces of Yahoo User Interface Library
3367  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3368  * YUI licensed under the BSD License:
3369  * http://developer.yahoo.net/yui/license.txt
3370  * <script type="text/javascript">
3371  *
3372  */
3373
3374 Roo.lib.AnimMgr = new function() {
3375
3376         var thread = null;
3377
3378
3379         var queue = [];
3380
3381
3382         var tweenCount = 0;
3383
3384
3385         this.fps = 1000;
3386
3387
3388         this.delay = 1;
3389
3390
3391         this.registerElement = function(tween) {
3392             queue[queue.length] = tween;
3393             tweenCount += 1;
3394             tween._onStart.fire();
3395             this.start();
3396         };
3397
3398
3399         this.unRegister = function(tween, index) {
3400             tween._onComplete.fire();
3401             index = index || getIndex(tween);
3402             if (index != -1) {
3403                 queue.splice(index, 1);
3404             }
3405
3406             tweenCount -= 1;
3407             if (tweenCount <= 0) {
3408                 this.stop();
3409             }
3410         };
3411
3412
3413         this.start = function() {
3414             if (thread === null) {
3415                 thread = setInterval(this.run, this.delay);
3416             }
3417         };
3418
3419
3420         this.stop = function(tween) {
3421             if (!tween) {
3422                 clearInterval(thread);
3423
3424                 for (var i = 0, len = queue.length; i < len; ++i) {
3425                     if (queue[0].isAnimated()) {
3426                         this.unRegister(queue[0], 0);
3427                     }
3428                 }
3429
3430                 queue = [];
3431                 thread = null;
3432                 tweenCount = 0;
3433             }
3434             else {
3435                 this.unRegister(tween);
3436             }
3437         };
3438
3439
3440         this.run = function() {
3441             for (var i = 0, len = queue.length; i < len; ++i) {
3442                 var tween = queue[i];
3443                 if (!tween || !tween.isAnimated()) {
3444                     continue;
3445                 }
3446
3447                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3448                 {
3449                     tween.currentFrame += 1;
3450
3451                     if (tween.useSeconds) {
3452                         correctFrame(tween);
3453                     }
3454                     tween._onTween.fire();
3455                 }
3456                 else {
3457                     Roo.lib.AnimMgr.stop(tween, i);
3458                 }
3459             }
3460         };
3461
3462         var getIndex = function(anim) {
3463             for (var i = 0, len = queue.length; i < len; ++i) {
3464                 if (queue[i] == anim) {
3465                     return i;
3466                 }
3467             }
3468             return -1;
3469         };
3470
3471
3472         var correctFrame = function(tween) {
3473             var frames = tween.totalFrames;
3474             var frame = tween.currentFrame;
3475             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3476             var elapsed = (new Date() - tween.getStartTime());
3477             var tweak = 0;
3478
3479             if (elapsed < tween.duration * 1000) {
3480                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3481             } else {
3482                 tweak = frames - (frame + 1);
3483             }
3484             if (tweak > 0 && isFinite(tweak)) {
3485                 if (tween.currentFrame + tweak >= frames) {
3486                     tweak = frames - (frame + 1);
3487                 }
3488
3489                 tween.currentFrame += tweak;
3490             }
3491         };
3492     };/*
3493  * Portions of this file are based on pieces of Yahoo User Interface Library
3494  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3495  * YUI licensed under the BSD License:
3496  * http://developer.yahoo.net/yui/license.txt
3497  * <script type="text/javascript">
3498  *
3499  */
3500 Roo.lib.Bezier = new function() {
3501
3502         this.getPosition = function(points, t) {
3503             var n = points.length;
3504             var tmp = [];
3505
3506             for (var i = 0; i < n; ++i) {
3507                 tmp[i] = [points[i][0], points[i][1]];
3508             }
3509
3510             for (var j = 1; j < n; ++j) {
3511                 for (i = 0; i < n - j; ++i) {
3512                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3513                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3514                 }
3515             }
3516
3517             return [ tmp[0][0], tmp[0][1] ];
3518
3519         };
3520     };/*
3521  * Portions of this file are based on pieces of Yahoo User Interface Library
3522  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3523  * YUI licensed under the BSD License:
3524  * http://developer.yahoo.net/yui/license.txt
3525  * <script type="text/javascript">
3526  *
3527  */
3528 (function() {
3529
3530     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3531         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3532     };
3533
3534     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3535
3536     var fly = Roo.lib.AnimBase.fly;
3537     var Y = Roo.lib;
3538     var superclass = Y.ColorAnim.superclass;
3539     var proto = Y.ColorAnim.prototype;
3540
3541     proto.toString = function() {
3542         var el = this.getEl();
3543         var id = el.id || el.tagName;
3544         return ("ColorAnim " + id);
3545     };
3546
3547     proto.patterns.color = /color$/i;
3548     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3549     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3550     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3551     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3552
3553
3554     proto.parseColor = function(s) {
3555         if (s.length == 3) {
3556             return s;
3557         }
3558
3559         var c = this.patterns.hex.exec(s);
3560         if (c && c.length == 4) {
3561             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3562         }
3563
3564         c = this.patterns.rgb.exec(s);
3565         if (c && c.length == 4) {
3566             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3567         }
3568
3569         c = this.patterns.hex3.exec(s);
3570         if (c && c.length == 4) {
3571             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3572         }
3573
3574         return null;
3575     };
3576     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3577     proto.getAttribute = function(attr) {
3578         var el = this.getEl();
3579         if (this.patterns.color.test(attr)) {
3580             var val = fly(el).getStyle(attr);
3581
3582             if (this.patterns.transparent.test(val)) {
3583                 var parent = el.parentNode;
3584                 val = fly(parent).getStyle(attr);
3585
3586                 while (parent && this.patterns.transparent.test(val)) {
3587                     parent = parent.parentNode;
3588                     val = fly(parent).getStyle(attr);
3589                     if (parent.tagName.toUpperCase() == 'HTML') {
3590                         val = '#fff';
3591                     }
3592                 }
3593             }
3594         } else {
3595             val = superclass.getAttribute.call(this, attr);
3596         }
3597
3598         return val;
3599     };
3600     proto.getAttribute = function(attr) {
3601         var el = this.getEl();
3602         if (this.patterns.color.test(attr)) {
3603             var val = fly(el).getStyle(attr);
3604
3605             if (this.patterns.transparent.test(val)) {
3606                 var parent = el.parentNode;
3607                 val = fly(parent).getStyle(attr);
3608
3609                 while (parent && this.patterns.transparent.test(val)) {
3610                     parent = parent.parentNode;
3611                     val = fly(parent).getStyle(attr);
3612                     if (parent.tagName.toUpperCase() == 'HTML') {
3613                         val = '#fff';
3614                     }
3615                 }
3616             }
3617         } else {
3618             val = superclass.getAttribute.call(this, attr);
3619         }
3620
3621         return val;
3622     };
3623
3624     proto.doMethod = function(attr, start, end) {
3625         var val;
3626
3627         if (this.patterns.color.test(attr)) {
3628             val = [];
3629             for (var i = 0, len = start.length; i < len; ++i) {
3630                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3631             }
3632
3633             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3634         }
3635         else {
3636             val = superclass.doMethod.call(this, attr, start, end);
3637         }
3638
3639         return val;
3640     };
3641
3642     proto.setRuntimeAttribute = function(attr) {
3643         superclass.setRuntimeAttribute.call(this, attr);
3644
3645         if (this.patterns.color.test(attr)) {
3646             var attributes = this.attributes;
3647             var start = this.parseColor(this.runtimeAttributes[attr].start);
3648             var end = this.parseColor(this.runtimeAttributes[attr].end);
3649
3650             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3651                 end = this.parseColor(attributes[attr].by);
3652
3653                 for (var i = 0, len = start.length; i < len; ++i) {
3654                     end[i] = start[i] + end[i];
3655                 }
3656             }
3657
3658             this.runtimeAttributes[attr].start = start;
3659             this.runtimeAttributes[attr].end = end;
3660         }
3661     };
3662 })();
3663
3664 /*
3665  * Portions of this file are based on pieces of Yahoo User Interface Library
3666  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3667  * YUI licensed under the BSD License:
3668  * http://developer.yahoo.net/yui/license.txt
3669  * <script type="text/javascript">
3670  *
3671  */
3672 Roo.lib.Easing = {
3673
3674
3675     easeNone: function (t, b, c, d) {
3676         return c * t / d + b;
3677     },
3678
3679
3680     easeIn: function (t, b, c, d) {
3681         return c * (t /= d) * t + b;
3682     },
3683
3684
3685     easeOut: function (t, b, c, d) {
3686         return -c * (t /= d) * (t - 2) + b;
3687     },
3688
3689
3690     easeBoth: function (t, b, c, d) {
3691         if ((t /= d / 2) < 1) {
3692             return c / 2 * t * t + b;
3693         }
3694
3695         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3696     },
3697
3698
3699     easeInStrong: function (t, b, c, d) {
3700         return c * (t /= d) * t * t * t + b;
3701     },
3702
3703
3704     easeOutStrong: function (t, b, c, d) {
3705         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3706     },
3707
3708
3709     easeBothStrong: function (t, b, c, d) {
3710         if ((t /= d / 2) < 1) {
3711             return c / 2 * t * t * t * t + b;
3712         }
3713
3714         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3715     },
3716
3717
3718
3719     elasticIn: function (t, b, c, d, a, p) {
3720         if (t == 0) {
3721             return b;
3722         }
3723         if ((t /= d) == 1) {
3724             return b + c;
3725         }
3726         if (!p) {
3727             p = d * .3;
3728         }
3729
3730         if (!a || a < Math.abs(c)) {
3731             a = c;
3732             var s = p / 4;
3733         }
3734         else {
3735             var s = p / (2 * Math.PI) * Math.asin(c / a);
3736         }
3737
3738         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3739     },
3740
3741
3742     elasticOut: function (t, b, c, d, a, p) {
3743         if (t == 0) {
3744             return b;
3745         }
3746         if ((t /= d) == 1) {
3747             return b + c;
3748         }
3749         if (!p) {
3750             p = d * .3;
3751         }
3752
3753         if (!a || a < Math.abs(c)) {
3754             a = c;
3755             var s = p / 4;
3756         }
3757         else {
3758             var s = p / (2 * Math.PI) * Math.asin(c / a);
3759         }
3760
3761         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3762     },
3763
3764
3765     elasticBoth: function (t, b, c, d, a, p) {
3766         if (t == 0) {
3767             return b;
3768         }
3769
3770         if ((t /= d / 2) == 2) {
3771             return b + c;
3772         }
3773
3774         if (!p) {
3775             p = d * (.3 * 1.5);
3776         }
3777
3778         if (!a || a < Math.abs(c)) {
3779             a = c;
3780             var s = p / 4;
3781         }
3782         else {
3783             var s = p / (2 * Math.PI) * Math.asin(c / a);
3784         }
3785
3786         if (t < 1) {
3787             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3788                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3789         }
3790         return a * Math.pow(2, -10 * (t -= 1)) *
3791                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3792     },
3793
3794
3795
3796     backIn: function (t, b, c, d, s) {
3797         if (typeof s == 'undefined') {
3798             s = 1.70158;
3799         }
3800         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3801     },
3802
3803
3804     backOut: function (t, b, c, d, s) {
3805         if (typeof s == 'undefined') {
3806             s = 1.70158;
3807         }
3808         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3809     },
3810
3811
3812     backBoth: function (t, b, c, d, s) {
3813         if (typeof s == 'undefined') {
3814             s = 1.70158;
3815         }
3816
3817         if ((t /= d / 2 ) < 1) {
3818             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3819         }
3820         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3821     },
3822
3823
3824     bounceIn: function (t, b, c, d) {
3825         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3826     },
3827
3828
3829     bounceOut: function (t, b, c, d) {
3830         if ((t /= d) < (1 / 2.75)) {
3831             return c * (7.5625 * t * t) + b;
3832         } else if (t < (2 / 2.75)) {
3833             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3834         } else if (t < (2.5 / 2.75)) {
3835             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3836         }
3837         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3838     },
3839
3840
3841     bounceBoth: function (t, b, c, d) {
3842         if (t < d / 2) {
3843             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3844         }
3845         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3846     }
3847 };/*
3848  * Portions of this file are based on pieces of Yahoo User Interface Library
3849  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3850  * YUI licensed under the BSD License:
3851  * http://developer.yahoo.net/yui/license.txt
3852  * <script type="text/javascript">
3853  *
3854  */
3855     (function() {
3856         Roo.lib.Motion = function(el, attributes, duration, method) {
3857             if (el) {
3858                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3859             }
3860         };
3861
3862         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3863
3864
3865         var Y = Roo.lib;
3866         var superclass = Y.Motion.superclass;
3867         var proto = Y.Motion.prototype;
3868
3869         proto.toString = function() {
3870             var el = this.getEl();
3871             var id = el.id || el.tagName;
3872             return ("Motion " + id);
3873         };
3874
3875         proto.patterns.points = /^points$/i;
3876
3877         proto.setAttribute = function(attr, val, unit) {
3878             if (this.patterns.points.test(attr)) {
3879                 unit = unit || 'px';
3880                 superclass.setAttribute.call(this, 'left', val[0], unit);
3881                 superclass.setAttribute.call(this, 'top', val[1], unit);
3882             } else {
3883                 superclass.setAttribute.call(this, attr, val, unit);
3884             }
3885         };
3886
3887         proto.getAttribute = function(attr) {
3888             if (this.patterns.points.test(attr)) {
3889                 var val = [
3890                         superclass.getAttribute.call(this, 'left'),
3891                         superclass.getAttribute.call(this, 'top')
3892                         ];
3893             } else {
3894                 val = superclass.getAttribute.call(this, attr);
3895             }
3896
3897             return val;
3898         };
3899
3900         proto.doMethod = function(attr, start, end) {
3901             var val = null;
3902
3903             if (this.patterns.points.test(attr)) {
3904                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3905                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3906             } else {
3907                 val = superclass.doMethod.call(this, attr, start, end);
3908             }
3909             return val;
3910         };
3911
3912         proto.setRuntimeAttribute = function(attr) {
3913             if (this.patterns.points.test(attr)) {
3914                 var el = this.getEl();
3915                 var attributes = this.attributes;
3916                 var start;
3917                 var control = attributes['points']['control'] || [];
3918                 var end;
3919                 var i, len;
3920
3921                 if (control.length > 0 && !(control[0] instanceof Array)) {
3922                     control = [control];
3923                 } else {
3924                     var tmp = [];
3925                     for (i = 0,len = control.length; i < len; ++i) {
3926                         tmp[i] = control[i];
3927                     }
3928                     control = tmp;
3929                 }
3930
3931                 Roo.fly(el).position();
3932
3933                 if (isset(attributes['points']['from'])) {
3934                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3935                 }
3936                 else {
3937                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3938                 }
3939
3940                 start = this.getAttribute('points');
3941
3942
3943                 if (isset(attributes['points']['to'])) {
3944                     end = translateValues.call(this, attributes['points']['to'], start);
3945
3946                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3947                     for (i = 0,len = control.length; i < len; ++i) {
3948                         control[i] = translateValues.call(this, control[i], start);
3949                     }
3950
3951
3952                 } else if (isset(attributes['points']['by'])) {
3953                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3954
3955                     for (i = 0,len = control.length; i < len; ++i) {
3956                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3957                     }
3958                 }
3959
3960                 this.runtimeAttributes[attr] = [start];
3961
3962                 if (control.length > 0) {
3963                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3964                 }
3965
3966                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3967             }
3968             else {
3969                 superclass.setRuntimeAttribute.call(this, attr);
3970             }
3971         };
3972
3973         var translateValues = function(val, start) {
3974             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3975             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3976
3977             return val;
3978         };
3979
3980         var isset = function(prop) {
3981             return (typeof prop !== 'undefined');
3982         };
3983     })();
3984 /*
3985  * Portions of this file are based on pieces of Yahoo User Interface Library
3986  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3987  * YUI licensed under the BSD License:
3988  * http://developer.yahoo.net/yui/license.txt
3989  * <script type="text/javascript">
3990  *
3991  */
3992     (function() {
3993         Roo.lib.Scroll = function(el, attributes, duration, method) {
3994             if (el) {
3995                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3996             }
3997         };
3998
3999         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4000
4001
4002         var Y = Roo.lib;
4003         var superclass = Y.Scroll.superclass;
4004         var proto = Y.Scroll.prototype;
4005
4006         proto.toString = function() {
4007             var el = this.getEl();
4008             var id = el.id || el.tagName;
4009             return ("Scroll " + id);
4010         };
4011
4012         proto.doMethod = function(attr, start, end) {
4013             var val = null;
4014
4015             if (attr == 'scroll') {
4016                 val = [
4017                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4018                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4019                         ];
4020
4021             } else {
4022                 val = superclass.doMethod.call(this, attr, start, end);
4023             }
4024             return val;
4025         };
4026
4027         proto.getAttribute = function(attr) {
4028             var val = null;
4029             var el = this.getEl();
4030
4031             if (attr == 'scroll') {
4032                 val = [ el.scrollLeft, el.scrollTop ];
4033             } else {
4034                 val = superclass.getAttribute.call(this, attr);
4035             }
4036
4037             return val;
4038         };
4039
4040         proto.setAttribute = function(attr, val, unit) {
4041             var el = this.getEl();
4042
4043             if (attr == 'scroll') {
4044                 el.scrollLeft = val[0];
4045                 el.scrollTop = val[1];
4046             } else {
4047                 superclass.setAttribute.call(this, attr, val, unit);
4048             }
4049         };
4050     })();
4051 /*
4052  * Based on:
4053  * Ext JS Library 1.1.1
4054  * Copyright(c) 2006-2007, Ext JS, LLC.
4055  *
4056  * Originally Released Under LGPL - original licence link has changed is not relivant.
4057  *
4058  * Fork - LGPL
4059  * <script type="text/javascript">
4060  */
4061
4062
4063 // nasty IE9 hack - what a pile of crap that is..
4064
4065  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4066     Range.prototype.createContextualFragment = function (html) {
4067         var doc = window.document;
4068         var container = doc.createElement("div");
4069         container.innerHTML = html;
4070         var frag = doc.createDocumentFragment(), n;
4071         while ((n = container.firstChild)) {
4072             frag.appendChild(n);
4073         }
4074         return frag;
4075     };
4076 }
4077
4078 /**
4079  * @class Roo.DomHelper
4080  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4081  * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4082  * @singleton
4083  */
4084 Roo.DomHelper = function(){
4085     var tempTableEl = null;
4086     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4087     var tableRe = /^table|tbody|tr|td$/i;
4088     var xmlns = {};
4089     // build as innerHTML where available
4090     /** @ignore */
4091     var createHtml = function(o){
4092         if(typeof o == 'string'){
4093             return o;
4094         }
4095         var b = "";
4096         if(!o.tag){
4097             o.tag = "div";
4098         }
4099         b += "<" + o.tag;
4100         for(var attr in o){
4101             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4102             if(attr == "style"){
4103                 var s = o["style"];
4104                 if(typeof s == "function"){
4105                     s = s.call();
4106                 }
4107                 if(typeof s == "string"){
4108                     b += ' style="' + s + '"';
4109                 }else if(typeof s == "object"){
4110                     b += ' style="';
4111                     for(var key in s){
4112                         if(typeof s[key] != "function"){
4113                             b += key + ":" + s[key] + ";";
4114                         }
4115                     }
4116                     b += '"';
4117                 }
4118             }else{
4119                 if(attr == "cls"){
4120                     b += ' class="' + o["cls"] + '"';
4121                 }else if(attr == "htmlFor"){
4122                     b += ' for="' + o["htmlFor"] + '"';
4123                 }else{
4124                     b += " " + attr + '="' + o[attr] + '"';
4125                 }
4126             }
4127         }
4128         if(emptyTags.test(o.tag)){
4129             b += "/>";
4130         }else{
4131             b += ">";
4132             var cn = o.children || o.cn;
4133             if(cn){
4134                 //http://bugs.kde.org/show_bug.cgi?id=71506
4135                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4136                     for(var i = 0, len = cn.length; i < len; i++) {
4137                         b += createHtml(cn[i], b);
4138                     }
4139                 }else{
4140                     b += createHtml(cn, b);
4141                 }
4142             }
4143             if(o.html){
4144                 b += o.html;
4145             }
4146             b += "</" + o.tag + ">";
4147         }
4148         return b;
4149     };
4150
4151     // build as dom
4152     /** @ignore */
4153     var createDom = function(o, parentNode){
4154          
4155         // defininition craeted..
4156         var ns = false;
4157         if (o.ns && o.ns != 'html') {
4158                
4159             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4160                 xmlns[o.ns] = o.xmlns;
4161                 ns = o.xmlns;
4162             }
4163             if (typeof(xmlns[o.ns]) == 'undefined') {
4164                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4165             }
4166             ns = xmlns[o.ns];
4167         }
4168         
4169         
4170         if (typeof(o) == 'string') {
4171             return parentNode.appendChild(document.createTextNode(o));
4172         }
4173         o.tag = o.tag || div;
4174         if (o.ns && Roo.isIE) {
4175             ns = false;
4176             o.tag = o.ns + ':' + o.tag;
4177             
4178         }
4179         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4180         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4181         for(var attr in o){
4182             
4183             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4184                     attr == "style" || typeof o[attr] == "function") continue;
4185                     
4186             if(attr=="cls" && Roo.isIE){
4187                 el.className = o["cls"];
4188             }else{
4189                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4190                 else el[attr] = o[attr];
4191             }
4192         }
4193         Roo.DomHelper.applyStyles(el, o.style);
4194         var cn = o.children || o.cn;
4195         if(cn){
4196             //http://bugs.kde.org/show_bug.cgi?id=71506
4197              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198                 for(var i = 0, len = cn.length; i < len; i++) {
4199                     createDom(cn[i], el);
4200                 }
4201             }else{
4202                 createDom(cn, el);
4203             }
4204         }
4205         if(o.html){
4206             el.innerHTML = o.html;
4207         }
4208         if(parentNode){
4209            parentNode.appendChild(el);
4210         }
4211         return el;
4212     };
4213
4214     var ieTable = function(depth, s, h, e){
4215         tempTableEl.innerHTML = [s, h, e].join('');
4216         var i = -1, el = tempTableEl;
4217         while(++i < depth){
4218             el = el.firstChild;
4219         }
4220         return el;
4221     };
4222
4223     // kill repeat to save bytes
4224     var ts = '<table>',
4225         te = '</table>',
4226         tbs = ts+'<tbody>',
4227         tbe = '</tbody>'+te,
4228         trs = tbs + '<tr>',
4229         tre = '</tr>'+tbe;
4230
4231     /**
4232      * @ignore
4233      * Nasty code for IE's broken table implementation
4234      */
4235     var insertIntoTable = function(tag, where, el, html){
4236         if(!tempTableEl){
4237             tempTableEl = document.createElement('div');
4238         }
4239         var node;
4240         var before = null;
4241         if(tag == 'td'){
4242             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4243                 return;
4244             }
4245             if(where == 'beforebegin'){
4246                 before = el;
4247                 el = el.parentNode;
4248             } else{
4249                 before = el.nextSibling;
4250                 el = el.parentNode;
4251             }
4252             node = ieTable(4, trs, html, tre);
4253         }
4254         else if(tag == 'tr'){
4255             if(where == 'beforebegin'){
4256                 before = el;
4257                 el = el.parentNode;
4258                 node = ieTable(3, tbs, html, tbe);
4259             } else if(where == 'afterend'){
4260                 before = el.nextSibling;
4261                 el = el.parentNode;
4262                 node = ieTable(3, tbs, html, tbe);
4263             } else{ // INTO a TR
4264                 if(where == 'afterbegin'){
4265                     before = el.firstChild;
4266                 }
4267                 node = ieTable(4, trs, html, tre);
4268             }
4269         } else if(tag == 'tbody'){
4270             if(where == 'beforebegin'){
4271                 before = el;
4272                 el = el.parentNode;
4273                 node = ieTable(2, ts, html, te);
4274             } else if(where == 'afterend'){
4275                 before = el.nextSibling;
4276                 el = el.parentNode;
4277                 node = ieTable(2, ts, html, te);
4278             } else{
4279                 if(where == 'afterbegin'){
4280                     before = el.firstChild;
4281                 }
4282                 node = ieTable(3, tbs, html, tbe);
4283             }
4284         } else{ // TABLE
4285             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4286                 return;
4287             }
4288             if(where == 'afterbegin'){
4289                 before = el.firstChild;
4290             }
4291             node = ieTable(2, ts, html, te);
4292         }
4293         el.insertBefore(node, before);
4294         return node;
4295     };
4296
4297     return {
4298     /** True to force the use of DOM instead of html fragments @type Boolean */
4299     useDom : false,
4300
4301     /**
4302      * Returns the markup for the passed Element(s) config
4303      * @param {Object} o The Dom object spec (and children)
4304      * @return {String}
4305      */
4306     markup : function(o){
4307         return createHtml(o);
4308     },
4309
4310     /**
4311      * Applies a style specification to an element
4312      * @param {String/HTMLElement} el The element to apply styles to
4313      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4314      * a function which returns such a specification.
4315      */
4316     applyStyles : function(el, styles){
4317         if(styles){
4318            el = Roo.fly(el);
4319            if(typeof styles == "string"){
4320                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4321                var matches;
4322                while ((matches = re.exec(styles)) != null){
4323                    el.setStyle(matches[1], matches[2]);
4324                }
4325            }else if (typeof styles == "object"){
4326                for (var style in styles){
4327                   el.setStyle(style, styles[style]);
4328                }
4329            }else if (typeof styles == "function"){
4330                 Roo.DomHelper.applyStyles(el, styles.call());
4331            }
4332         }
4333     },
4334
4335     /**
4336      * Inserts an HTML fragment into the Dom
4337      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4338      * @param {HTMLElement} el The context element
4339      * @param {String} html The HTML fragmenet
4340      * @return {HTMLElement} The new node
4341      */
4342     insertHtml : function(where, el, html){
4343         where = where.toLowerCase();
4344         if(el.insertAdjacentHTML){
4345             if(tableRe.test(el.tagName)){
4346                 var rs;
4347                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4348                     return rs;
4349                 }
4350             }
4351             switch(where){
4352                 case "beforebegin":
4353                     el.insertAdjacentHTML('BeforeBegin', html);
4354                     return el.previousSibling;
4355                 case "afterbegin":
4356                     el.insertAdjacentHTML('AfterBegin', html);
4357                     return el.firstChild;
4358                 case "beforeend":
4359                     el.insertAdjacentHTML('BeforeEnd', html);
4360                     return el.lastChild;
4361                 case "afterend":
4362                     el.insertAdjacentHTML('AfterEnd', html);
4363                     return el.nextSibling;
4364             }
4365             throw 'Illegal insertion point -> "' + where + '"';
4366         }
4367         var range = el.ownerDocument.createRange();
4368         var frag;
4369         switch(where){
4370              case "beforebegin":
4371                 range.setStartBefore(el);
4372                 frag = range.createContextualFragment(html);
4373                 el.parentNode.insertBefore(frag, el);
4374                 return el.previousSibling;
4375              case "afterbegin":
4376                 if(el.firstChild){
4377                     range.setStartBefore(el.firstChild);
4378                     frag = range.createContextualFragment(html);
4379                     el.insertBefore(frag, el.firstChild);
4380                     return el.firstChild;
4381                 }else{
4382                     el.innerHTML = html;
4383                     return el.firstChild;
4384                 }
4385             case "beforeend":
4386                 if(el.lastChild){
4387                     range.setStartAfter(el.lastChild);
4388                     frag = range.createContextualFragment(html);
4389                     el.appendChild(frag);
4390                     return el.lastChild;
4391                 }else{
4392                     el.innerHTML = html;
4393                     return el.lastChild;
4394                 }
4395             case "afterend":
4396                 range.setStartAfter(el);
4397                 frag = range.createContextualFragment(html);
4398                 el.parentNode.insertBefore(frag, el.nextSibling);
4399                 return el.nextSibling;
4400             }
4401             throw 'Illegal insertion point -> "' + where + '"';
4402     },
4403
4404     /**
4405      * Creates new Dom element(s) and inserts them before el
4406      * @param {String/HTMLElement/Element} el The context element
4407      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4408      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4409      * @return {HTMLElement/Roo.Element} The new node
4410      */
4411     insertBefore : function(el, o, returnElement){
4412         return this.doInsert(el, o, returnElement, "beforeBegin");
4413     },
4414
4415     /**
4416      * Creates new Dom element(s) and inserts them after el
4417      * @param {String/HTMLElement/Element} el The context element
4418      * @param {Object} o The Dom object spec (and children)
4419      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4420      * @return {HTMLElement/Roo.Element} The new node
4421      */
4422     insertAfter : function(el, o, returnElement){
4423         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4424     },
4425
4426     /**
4427      * Creates new Dom element(s) and inserts them as the first child of el
4428      * @param {String/HTMLElement/Element} el The context element
4429      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4430      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4431      * @return {HTMLElement/Roo.Element} The new node
4432      */
4433     insertFirst : function(el, o, returnElement){
4434         return this.doInsert(el, o, returnElement, "afterBegin");
4435     },
4436
4437     // private
4438     doInsert : function(el, o, returnElement, pos, sibling){
4439         el = Roo.getDom(el);
4440         var newNode;
4441         if(this.useDom || o.ns){
4442             newNode = createDom(o, null);
4443             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4444         }else{
4445             var html = createHtml(o);
4446             newNode = this.insertHtml(pos, el, html);
4447         }
4448         return returnElement ? Roo.get(newNode, true) : newNode;
4449     },
4450
4451     /**
4452      * Creates new Dom element(s) and appends them to el
4453      * @param {String/HTMLElement/Element} el The context element
4454      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4455      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4456      * @return {HTMLElement/Roo.Element} The new node
4457      */
4458     append : function(el, o, returnElement){
4459         el = Roo.getDom(el);
4460         var newNode;
4461         if(this.useDom || o.ns){
4462             newNode = createDom(o, null);
4463             el.appendChild(newNode);
4464         }else{
4465             var html = createHtml(o);
4466             newNode = this.insertHtml("beforeEnd", el, html);
4467         }
4468         return returnElement ? Roo.get(newNode, true) : newNode;
4469     },
4470
4471     /**
4472      * Creates new Dom element(s) and overwrites the contents of el with them
4473      * @param {String/HTMLElement/Element} el The context element
4474      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476      * @return {HTMLElement/Roo.Element} The new node
4477      */
4478     overwrite : function(el, o, returnElement){
4479         el = Roo.getDom(el);
4480         if (o.ns) {
4481           
4482             while (el.childNodes.length) {
4483                 el.removeChild(el.firstChild);
4484             }
4485             createDom(o, el);
4486         } else {
4487             el.innerHTML = createHtml(o);   
4488         }
4489         
4490         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4491     },
4492
4493     /**
4494      * Creates a new Roo.DomHelper.Template from the Dom object spec
4495      * @param {Object} o The Dom object spec (and children)
4496      * @return {Roo.DomHelper.Template} The new template
4497      */
4498     createTemplate : function(o){
4499         var html = createHtml(o);
4500         return new Roo.Template(html);
4501     }
4502     };
4503 }();
4504 /*
4505  * Based on:
4506  * Ext JS Library 1.1.1
4507  * Copyright(c) 2006-2007, Ext JS, LLC.
4508  *
4509  * Originally Released Under LGPL - original licence link has changed is not relivant.
4510  *
4511  * Fork - LGPL
4512  * <script type="text/javascript">
4513  */
4514  
4515 /**
4516 * @class Roo.Template
4517 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4518 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4519 * Usage:
4520 <pre><code>
4521 var t = new Roo.Template({
4522     html :  '&lt;div name="{id}"&gt;' + 
4523         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4524         '&lt;/div&gt;',
4525     myformat: function (value, allValues) {
4526         return 'XX' + value;
4527     }
4528 });
4529 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4530 </code></pre>
4531 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
4532 * @constructor
4533 * @param {Object} cfg - Configuration object.
4534 */
4535 Roo.Template = function(cfg){
4536     // BC!
4537     if(cfg instanceof Array){
4538         cfg = cfg.join("");
4539     }else if(arguments.length > 1){
4540         cfg = Array.prototype.join.call(arguments, "");
4541     }
4542     
4543     
4544     if (typeof(cfg) == 'object') {
4545         Roo.apply(this,cfg)
4546     } else {
4547         // bc
4548         this.html = cfg;
4549     }
4550     
4551     
4552 };
4553 Roo.Template.prototype = {
4554     
4555     /**
4556      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4557      */
4558     html : '',
4559     /**
4560      * Returns an HTML fragment of this template with the specified values applied.
4561      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4562      * @return {String} The HTML fragment
4563      */
4564     applyTemplate : function(values){
4565         try {
4566             
4567             if(this.compiled){
4568                 return this.compiled(values);
4569             }
4570             var useF = this.disableFormats !== true;
4571             var fm = Roo.util.Format, tpl = this;
4572             var fn = function(m, name, format, args){
4573                 if(format && useF){
4574                     if(format.substr(0, 5) == "this."){
4575                         return tpl.call(format.substr(5), values[name], values);
4576                     }else{
4577                         if(args){
4578                             // quoted values are required for strings in compiled templates, 
4579                             // but for non compiled we need to strip them
4580                             // quoted reversed for jsmin
4581                             var re = /^\s*['"](.*)["']\s*$/;
4582                             args = args.split(',');
4583                             for(var i = 0, len = args.length; i < len; i++){
4584                                 args[i] = args[i].replace(re, "$1");
4585                             }
4586                             args = [values[name]].concat(args);
4587                         }else{
4588                             args = [values[name]];
4589                         }
4590                         return fm[format].apply(fm, args);
4591                     }
4592                 }else{
4593                     return values[name] !== undefined ? values[name] : "";
4594                 }
4595             };
4596             return this.html.replace(this.re, fn);
4597         } catch (e) {
4598             Roo.log(e);
4599             throw e;
4600         }
4601          
4602     },
4603     
4604     /**
4605      * Sets the HTML used as the template and optionally compiles it.
4606      * @param {String} html
4607      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4608      * @return {Roo.Template} this
4609      */
4610     set : function(html, compile){
4611         this.html = html;
4612         this.compiled = null;
4613         if(compile){
4614             this.compile();
4615         }
4616         return this;
4617     },
4618     
4619     /**
4620      * True to disable format functions (defaults to false)
4621      * @type Boolean
4622      */
4623     disableFormats : false,
4624     
4625     /**
4626     * The regular expression used to match template variables 
4627     * @type RegExp
4628     * @property 
4629     */
4630     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4631     
4632     /**
4633      * Compiles the template into an internal function, eliminating the RegEx overhead.
4634      * @return {Roo.Template} this
4635      */
4636     compile : function(){
4637         var fm = Roo.util.Format;
4638         var useF = this.disableFormats !== true;
4639         var sep = Roo.isGecko ? "+" : ",";
4640         var fn = function(m, name, format, args){
4641             if(format && useF){
4642                 args = args ? ',' + args : "";
4643                 if(format.substr(0, 5) != "this."){
4644                     format = "fm." + format + '(';
4645                 }else{
4646                     format = 'this.call("'+ format.substr(5) + '", ';
4647                     args = ", values";
4648                 }
4649             }else{
4650                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4651             }
4652             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4653         };
4654         var body;
4655         // branched to use + in gecko and [].join() in others
4656         if(Roo.isGecko){
4657             body = "this.compiled = function(values){ return '" +
4658                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4659                     "';};";
4660         }else{
4661             body = ["this.compiled = function(values){ return ['"];
4662             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4663             body.push("'].join('');};");
4664             body = body.join('');
4665         }
4666         /**
4667          * eval:var:values
4668          * eval:var:fm
4669          */
4670         eval(body);
4671         return this;
4672     },
4673     
4674     // private function used to call members
4675     call : function(fnName, value, allValues){
4676         return this[fnName](value, allValues);
4677     },
4678     
4679     /**
4680      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4681      * @param {String/HTMLElement/Roo.Element} el The context element
4682      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4683      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4684      * @return {HTMLElement/Roo.Element} The new node or Element
4685      */
4686     insertFirst: function(el, values, returnElement){
4687         return this.doInsert('afterBegin', el, values, returnElement);
4688     },
4689
4690     /**
4691      * Applies the supplied values to the template and inserts the new node(s) before el.
4692      * @param {String/HTMLElement/Roo.Element} el The context element
4693      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4694      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4695      * @return {HTMLElement/Roo.Element} The new node or Element
4696      */
4697     insertBefore: function(el, values, returnElement){
4698         return this.doInsert('beforeBegin', el, values, returnElement);
4699     },
4700
4701     /**
4702      * Applies the supplied values to the template and inserts the new node(s) after el.
4703      * @param {String/HTMLElement/Roo.Element} el The context element
4704      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4705      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4706      * @return {HTMLElement/Roo.Element} The new node or Element
4707      */
4708     insertAfter : function(el, values, returnElement){
4709         return this.doInsert('afterEnd', el, values, returnElement);
4710     },
4711     
4712     /**
4713      * Applies the supplied values to the template and appends the new node(s) to el.
4714      * @param {String/HTMLElement/Roo.Element} el The context element
4715      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4716      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4717      * @return {HTMLElement/Roo.Element} The new node or Element
4718      */
4719     append : function(el, values, returnElement){
4720         return this.doInsert('beforeEnd', el, values, returnElement);
4721     },
4722
4723     doInsert : function(where, el, values, returnEl){
4724         el = Roo.getDom(el);
4725         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4726         return returnEl ? Roo.get(newNode, true) : newNode;
4727     },
4728
4729     /**
4730      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4731      * @param {String/HTMLElement/Roo.Element} el The context element
4732      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4733      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4734      * @return {HTMLElement/Roo.Element} The new node or Element
4735      */
4736     overwrite : function(el, values, returnElement){
4737         el = Roo.getDom(el);
4738         el.innerHTML = this.applyTemplate(values);
4739         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4740     }
4741 };
4742 /**
4743  * Alias for {@link #applyTemplate}
4744  * @method
4745  */
4746 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4747
4748 // backwards compat
4749 Roo.DomHelper.Template = Roo.Template;
4750
4751 /**
4752  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4753  * @param {String/HTMLElement} el A DOM element or its id
4754  * @returns {Roo.Template} The created template
4755  * @static
4756  */
4757 Roo.Template.from = function(el){
4758     el = Roo.getDom(el);
4759     return new Roo.Template(el.value || el.innerHTML);
4760 };/*
4761  * Based on:
4762  * Ext JS Library 1.1.1
4763  * Copyright(c) 2006-2007, Ext JS, LLC.
4764  *
4765  * Originally Released Under LGPL - original licence link has changed is not relivant.
4766  *
4767  * Fork - LGPL
4768  * <script type="text/javascript">
4769  */
4770  
4771
4772 /*
4773  * This is code is also distributed under MIT license for use
4774  * with jQuery and prototype JavaScript libraries.
4775  */
4776 /**
4777  * @class Roo.DomQuery
4778 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4779 <p>
4780 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4781
4782 <p>
4783 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4784 </p>
4785 <h4>Element Selectors:</h4>
4786 <ul class="list">
4787     <li> <b>*</b> any element</li>
4788     <li> <b>E</b> an element with the tag E</li>
4789     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4790     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4791     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4792     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4793 </ul>
4794 <h4>Attribute Selectors:</h4>
4795 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4796 <ul class="list">
4797     <li> <b>E[foo]</b> has an attribute "foo"</li>
4798     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4799     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4800     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4801     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4802     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4803     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4804 </ul>
4805 <h4>Pseudo Classes:</h4>
4806 <ul class="list">
4807     <li> <b>E:first-child</b> E is the first child of its parent</li>
4808     <li> <b>E:last-child</b> E is the last child of its parent</li>
4809     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4810     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4811     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4812     <li> <b>E:only-child</b> E is the only child of its parent</li>
4813     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4814     <li> <b>E:first</b> the first E in the resultset</li>
4815     <li> <b>E:last</b> the last E in the resultset</li>
4816     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4817     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4818     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4819     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4820     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4821     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4822     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4823     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4824     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4825 </ul>
4826 <h4>CSS Value Selectors:</h4>
4827 <ul class="list">
4828     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4829     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4830     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4831     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4832     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4833     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4834 </ul>
4835  * @singleton
4836  */
4837 Roo.DomQuery = function(){
4838     var cache = {}, simpleCache = {}, valueCache = {};
4839     var nonSpace = /\S/;
4840     var trimRe = /^\s+|\s+$/g;
4841     var tplRe = /\{(\d+)\}/g;
4842     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4843     var tagTokenRe = /^(#)?([\w-\*]+)/;
4844     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4845
4846     function child(p, index){
4847         var i = 0;
4848         var n = p.firstChild;
4849         while(n){
4850             if(n.nodeType == 1){
4851                if(++i == index){
4852                    return n;
4853                }
4854             }
4855             n = n.nextSibling;
4856         }
4857         return null;
4858     };
4859
4860     function next(n){
4861         while((n = n.nextSibling) && n.nodeType != 1);
4862         return n;
4863     };
4864
4865     function prev(n){
4866         while((n = n.previousSibling) && n.nodeType != 1);
4867         return n;
4868     };
4869
4870     function children(d){
4871         var n = d.firstChild, ni = -1;
4872             while(n){
4873                 var nx = n.nextSibling;
4874                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4875                     d.removeChild(n);
4876                 }else{
4877                     n.nodeIndex = ++ni;
4878                 }
4879                 n = nx;
4880             }
4881             return this;
4882         };
4883
4884     function byClassName(c, a, v){
4885         if(!v){
4886             return c;
4887         }
4888         var r = [], ri = -1, cn;
4889         for(var i = 0, ci; ci = c[i]; i++){
4890             if((' '+ci.className+' ').indexOf(v) != -1){
4891                 r[++ri] = ci;
4892             }
4893         }
4894         return r;
4895     };
4896
4897     function attrValue(n, attr){
4898         if(!n.tagName && typeof n.length != "undefined"){
4899             n = n[0];
4900         }
4901         if(!n){
4902             return null;
4903         }
4904         if(attr == "for"){
4905             return n.htmlFor;
4906         }
4907         if(attr == "class" || attr == "className"){
4908             return n.className;
4909         }
4910         return n.getAttribute(attr) || n[attr];
4911
4912     };
4913
4914     function getNodes(ns, mode, tagName){
4915         var result = [], ri = -1, cs;
4916         if(!ns){
4917             return result;
4918         }
4919         tagName = tagName || "*";
4920         if(typeof ns.getElementsByTagName != "undefined"){
4921             ns = [ns];
4922         }
4923         if(!mode){
4924             for(var i = 0, ni; ni = ns[i]; i++){
4925                 cs = ni.getElementsByTagName(tagName);
4926                 for(var j = 0, ci; ci = cs[j]; j++){
4927                     result[++ri] = ci;
4928                 }
4929             }
4930         }else if(mode == "/" || mode == ">"){
4931             var utag = tagName.toUpperCase();
4932             for(var i = 0, ni, cn; ni = ns[i]; i++){
4933                 cn = ni.children || ni.childNodes;
4934                 for(var j = 0, cj; cj = cn[j]; j++){
4935                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4936                         result[++ri] = cj;
4937                     }
4938                 }
4939             }
4940         }else if(mode == "+"){
4941             var utag = tagName.toUpperCase();
4942             for(var i = 0, n; n = ns[i]; i++){
4943                 while((n = n.nextSibling) && n.nodeType != 1);
4944                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4945                     result[++ri] = n;
4946                 }
4947             }
4948         }else if(mode == "~"){
4949             for(var i = 0, n; n = ns[i]; i++){
4950                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4951                 if(n){
4952                     result[++ri] = n;
4953                 }
4954             }
4955         }
4956         return result;
4957     };
4958
4959     function concat(a, b){
4960         if(b.slice){
4961             return a.concat(b);
4962         }
4963         for(var i = 0, l = b.length; i < l; i++){
4964             a[a.length] = b[i];
4965         }
4966         return a;
4967     }
4968
4969     function byTag(cs, tagName){
4970         if(cs.tagName || cs == document){
4971             cs = [cs];
4972         }
4973         if(!tagName){
4974             return cs;
4975         }
4976         var r = [], ri = -1;
4977         tagName = tagName.toLowerCase();
4978         for(var i = 0, ci; ci = cs[i]; i++){
4979             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4980                 r[++ri] = ci;
4981             }
4982         }
4983         return r;
4984     };
4985
4986     function byId(cs, attr, id){
4987         if(cs.tagName || cs == document){
4988             cs = [cs];
4989         }
4990         if(!id){
4991             return cs;
4992         }
4993         var r = [], ri = -1;
4994         for(var i = 0,ci; ci = cs[i]; i++){
4995             if(ci && ci.id == id){
4996                 r[++ri] = ci;
4997                 return r;
4998             }
4999         }
5000         return r;
5001     };
5002
5003     function byAttribute(cs, attr, value, op, custom){
5004         var r = [], ri = -1, st = custom=="{";
5005         var f = Roo.DomQuery.operators[op];
5006         for(var i = 0, ci; ci = cs[i]; i++){
5007             var a;
5008             if(st){
5009                 a = Roo.DomQuery.getStyle(ci, attr);
5010             }
5011             else if(attr == "class" || attr == "className"){
5012                 a = ci.className;
5013             }else if(attr == "for"){
5014                 a = ci.htmlFor;
5015             }else if(attr == "href"){
5016                 a = ci.getAttribute("href", 2);
5017             }else{
5018                 a = ci.getAttribute(attr);
5019             }
5020             if((f && f(a, value)) || (!f && a)){
5021                 r[++ri] = ci;
5022             }
5023         }
5024         return r;
5025     };
5026
5027     function byPseudo(cs, name, value){
5028         return Roo.DomQuery.pseudos[name](cs, value);
5029     };
5030
5031     // This is for IE MSXML which does not support expandos.
5032     // IE runs the same speed using setAttribute, however FF slows way down
5033     // and Safari completely fails so they need to continue to use expandos.
5034     var isIE = window.ActiveXObject ? true : false;
5035
5036     // this eval is stop the compressor from
5037     // renaming the variable to something shorter
5038     
5039     /** eval:var:batch */
5040     var batch = 30803; 
5041
5042     var key = 30803;
5043
5044     function nodupIEXml(cs){
5045         var d = ++key;
5046         cs[0].setAttribute("_nodup", d);
5047         var r = [cs[0]];
5048         for(var i = 1, len = cs.length; i < len; i++){
5049             var c = cs[i];
5050             if(!c.getAttribute("_nodup") != d){
5051                 c.setAttribute("_nodup", d);
5052                 r[r.length] = c;
5053             }
5054         }
5055         for(var i = 0, len = cs.length; i < len; i++){
5056             cs[i].removeAttribute("_nodup");
5057         }
5058         return r;
5059     }
5060
5061     function nodup(cs){
5062         if(!cs){
5063             return [];
5064         }
5065         var len = cs.length, c, i, r = cs, cj, ri = -1;
5066         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5067             return cs;
5068         }
5069         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5070             return nodupIEXml(cs);
5071         }
5072         var d = ++key;
5073         cs[0]._nodup = d;
5074         for(i = 1; c = cs[i]; i++){
5075             if(c._nodup != d){
5076                 c._nodup = d;
5077             }else{
5078                 r = [];
5079                 for(var j = 0; j < i; j++){
5080                     r[++ri] = cs[j];
5081                 }
5082                 for(j = i+1; cj = cs[j]; j++){
5083                     if(cj._nodup != d){
5084                         cj._nodup = d;
5085                         r[++ri] = cj;
5086                     }
5087                 }
5088                 return r;
5089             }
5090         }
5091         return r;
5092     }
5093
5094     function quickDiffIEXml(c1, c2){
5095         var d = ++key;
5096         for(var i = 0, len = c1.length; i < len; i++){
5097             c1[i].setAttribute("_qdiff", d);
5098         }
5099         var r = [];
5100         for(var i = 0, len = c2.length; i < len; i++){
5101             if(c2[i].getAttribute("_qdiff") != d){
5102                 r[r.length] = c2[i];
5103             }
5104         }
5105         for(var i = 0, len = c1.length; i < len; i++){
5106            c1[i].removeAttribute("_qdiff");
5107         }
5108         return r;
5109     }
5110
5111     function quickDiff(c1, c2){
5112         var len1 = c1.length;
5113         if(!len1){
5114             return c2;
5115         }
5116         if(isIE && c1[0].selectSingleNode){
5117             return quickDiffIEXml(c1, c2);
5118         }
5119         var d = ++key;
5120         for(var i = 0; i < len1; i++){
5121             c1[i]._qdiff = d;
5122         }
5123         var r = [];
5124         for(var i = 0, len = c2.length; i < len; i++){
5125             if(c2[i]._qdiff != d){
5126                 r[r.length] = c2[i];
5127             }
5128         }
5129         return r;
5130     }
5131
5132     function quickId(ns, mode, root, id){
5133         if(ns == root){
5134            var d = root.ownerDocument || root;
5135            return d.getElementById(id);
5136         }
5137         ns = getNodes(ns, mode, "*");
5138         return byId(ns, null, id);
5139     }
5140
5141     return {
5142         getStyle : function(el, name){
5143             return Roo.fly(el).getStyle(name);
5144         },
5145         /**
5146          * Compiles a selector/xpath query into a reusable function. The returned function
5147          * takes one parameter "root" (optional), which is the context node from where the query should start.
5148          * @param {String} selector The selector/xpath query
5149          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5150          * @return {Function}
5151          */
5152         compile : function(path, type){
5153             type = type || "select";
5154             
5155             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5156             var q = path, mode, lq;
5157             var tk = Roo.DomQuery.matchers;
5158             var tklen = tk.length;
5159             var mm;
5160
5161             // accept leading mode switch
5162             var lmode = q.match(modeRe);
5163             if(lmode && lmode[1]){
5164                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5165                 q = q.replace(lmode[1], "");
5166             }
5167             // strip leading slashes
5168             while(path.substr(0, 1)=="/"){
5169                 path = path.substr(1);
5170             }
5171
5172             while(q && lq != q){
5173                 lq = q;
5174                 var tm = q.match(tagTokenRe);
5175                 if(type == "select"){
5176                     if(tm){
5177                         if(tm[1] == "#"){
5178                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5179                         }else{
5180                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5181                         }
5182                         q = q.replace(tm[0], "");
5183                     }else if(q.substr(0, 1) != '@'){
5184                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5185                     }
5186                 }else{
5187                     if(tm){
5188                         if(tm[1] == "#"){
5189                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5190                         }else{
5191                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5192                         }
5193                         q = q.replace(tm[0], "");
5194                     }
5195                 }
5196                 while(!(mm = q.match(modeRe))){
5197                     var matched = false;
5198                     for(var j = 0; j < tklen; j++){
5199                         var t = tk[j];
5200                         var m = q.match(t.re);
5201                         if(m){
5202                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5203                                                     return m[i];
5204                                                 });
5205                             q = q.replace(m[0], "");
5206                             matched = true;
5207                             break;
5208                         }
5209                     }
5210                     // prevent infinite loop on bad selector
5211                     if(!matched){
5212                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5213                     }
5214                 }
5215                 if(mm[1]){
5216                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5217                     q = q.replace(mm[1], "");
5218                 }
5219             }
5220             fn[fn.length] = "return nodup(n);\n}";
5221             
5222              /** 
5223               * list of variables that need from compression as they are used by eval.
5224              *  eval:var:batch 
5225              *  eval:var:nodup
5226              *  eval:var:byTag
5227              *  eval:var:ById
5228              *  eval:var:getNodes
5229              *  eval:var:quickId
5230              *  eval:var:mode
5231              *  eval:var:root
5232              *  eval:var:n
5233              *  eval:var:byClassName
5234              *  eval:var:byPseudo
5235              *  eval:var:byAttribute
5236              *  eval:var:attrValue
5237              * 
5238              **/ 
5239             eval(fn.join(""));
5240             return f;
5241         },
5242
5243         /**
5244          * Selects a group of elements.
5245          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5246          * @param {Node} root (optional) The start of the query (defaults to document).
5247          * @return {Array}
5248          */
5249         select : function(path, root, type){
5250             if(!root || root == document){
5251                 root = document;
5252             }
5253             if(typeof root == "string"){
5254                 root = document.getElementById(root);
5255             }
5256             var paths = path.split(",");
5257             var results = [];
5258             for(var i = 0, len = paths.length; i < len; i++){
5259                 var p = paths[i].replace(trimRe, "");
5260                 if(!cache[p]){
5261                     cache[p] = Roo.DomQuery.compile(p);
5262                     if(!cache[p]){
5263                         throw p + " is not a valid selector";
5264                     }
5265                 }
5266                 var result = cache[p](root);
5267                 if(result && result != document){
5268                     results = results.concat(result);
5269                 }
5270             }
5271             if(paths.length > 1){
5272                 return nodup(results);
5273             }
5274             return results;
5275         },
5276
5277         /**
5278          * Selects a single element.
5279          * @param {String} selector The selector/xpath query
5280          * @param {Node} root (optional) The start of the query (defaults to document).
5281          * @return {Element}
5282          */
5283         selectNode : function(path, root){
5284             return Roo.DomQuery.select(path, root)[0];
5285         },
5286
5287         /**
5288          * Selects the value of a node, optionally replacing null with the defaultValue.
5289          * @param {String} selector The selector/xpath query
5290          * @param {Node} root (optional) The start of the query (defaults to document).
5291          * @param {String} defaultValue
5292          */
5293         selectValue : function(path, root, defaultValue){
5294             path = path.replace(trimRe, "");
5295             if(!valueCache[path]){
5296                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5297             }
5298             var n = valueCache[path](root);
5299             n = n[0] ? n[0] : n;
5300             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5301             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5302         },
5303
5304         /**
5305          * Selects the value of a node, parsing integers and floats.
5306          * @param {String} selector The selector/xpath query
5307          * @param {Node} root (optional) The start of the query (defaults to document).
5308          * @param {Number} defaultValue
5309          * @return {Number}
5310          */
5311         selectNumber : function(path, root, defaultValue){
5312             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5313             return parseFloat(v);
5314         },
5315
5316         /**
5317          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5318          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5319          * @param {String} selector The simple selector to test
5320          * @return {Boolean}
5321          */
5322         is : function(el, ss){
5323             if(typeof el == "string"){
5324                 el = document.getElementById(el);
5325             }
5326             var isArray = (el instanceof Array);
5327             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5328             return isArray ? (result.length == el.length) : (result.length > 0);
5329         },
5330
5331         /**
5332          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5333          * @param {Array} el An array of elements to filter
5334          * @param {String} selector The simple selector to test
5335          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5336          * the selector instead of the ones that match
5337          * @return {Array}
5338          */
5339         filter : function(els, ss, nonMatches){
5340             ss = ss.replace(trimRe, "");
5341             if(!simpleCache[ss]){
5342                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5343             }
5344             var result = simpleCache[ss](els);
5345             return nonMatches ? quickDiff(result, els) : result;
5346         },
5347
5348         /**
5349          * Collection of matching regular expressions and code snippets.
5350          */
5351         matchers : [{
5352                 re: /^\.([\w-]+)/,
5353                 select: 'n = byClassName(n, null, " {1} ");'
5354             }, {
5355                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5356                 select: 'n = byPseudo(n, "{1}", "{2}");'
5357             },{
5358                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5359                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5360             }, {
5361                 re: /^#([\w-]+)/,
5362                 select: 'n = byId(n, null, "{1}");'
5363             },{
5364                 re: /^@([\w-]+)/,
5365                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5366             }
5367         ],
5368
5369         /**
5370          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5371          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5372          */
5373         operators : {
5374             "=" : function(a, v){
5375                 return a == v;
5376             },
5377             "!=" : function(a, v){
5378                 return a != v;
5379             },
5380             "^=" : function(a, v){
5381                 return a && a.substr(0, v.length) == v;
5382             },
5383             "$=" : function(a, v){
5384                 return a && a.substr(a.length-v.length) == v;
5385             },
5386             "*=" : function(a, v){
5387                 return a && a.indexOf(v) !== -1;
5388             },
5389             "%=" : function(a, v){
5390                 return (a % v) == 0;
5391             },
5392             "|=" : function(a, v){
5393                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5394             },
5395             "~=" : function(a, v){
5396                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5397             }
5398         },
5399
5400         /**
5401          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5402          * and the argument (if any) supplied in the selector.
5403          */
5404         pseudos : {
5405             "first-child" : function(c){
5406                 var r = [], ri = -1, n;
5407                 for(var i = 0, ci; ci = n = c[i]; i++){
5408                     while((n = n.previousSibling) && n.nodeType != 1);
5409                     if(!n){
5410                         r[++ri] = ci;
5411                     }
5412                 }
5413                 return r;
5414             },
5415
5416             "last-child" : function(c){
5417                 var r = [], ri = -1, n;
5418                 for(var i = 0, ci; ci = n = c[i]; i++){
5419                     while((n = n.nextSibling) && n.nodeType != 1);
5420                     if(!n){
5421                         r[++ri] = ci;
5422                     }
5423                 }
5424                 return r;
5425             },
5426
5427             "nth-child" : function(c, a) {
5428                 var r = [], ri = -1;
5429                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5430                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5431                 for(var i = 0, n; n = c[i]; i++){
5432                     var pn = n.parentNode;
5433                     if (batch != pn._batch) {
5434                         var j = 0;
5435                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5436                             if(cn.nodeType == 1){
5437                                cn.nodeIndex = ++j;
5438                             }
5439                         }
5440                         pn._batch = batch;
5441                     }
5442                     if (f == 1) {
5443                         if (l == 0 || n.nodeIndex == l){
5444                             r[++ri] = n;
5445                         }
5446                     } else if ((n.nodeIndex + l) % f == 0){
5447                         r[++ri] = n;
5448                     }
5449                 }
5450
5451                 return r;
5452             },
5453
5454             "only-child" : function(c){
5455                 var r = [], ri = -1;;
5456                 for(var i = 0, ci; ci = c[i]; i++){
5457                     if(!prev(ci) && !next(ci)){
5458                         r[++ri] = ci;
5459                     }
5460                 }
5461                 return r;
5462             },
5463
5464             "empty" : function(c){
5465                 var r = [], ri = -1;
5466                 for(var i = 0, ci; ci = c[i]; i++){
5467                     var cns = ci.childNodes, j = 0, cn, empty = true;
5468                     while(cn = cns[j]){
5469                         ++j;
5470                         if(cn.nodeType == 1 || cn.nodeType == 3){
5471                             empty = false;
5472                             break;
5473                         }
5474                     }
5475                     if(empty){
5476                         r[++ri] = ci;
5477                     }
5478                 }
5479                 return r;
5480             },
5481
5482             "contains" : function(c, v){
5483                 var r = [], ri = -1;
5484                 for(var i = 0, ci; ci = c[i]; i++){
5485                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5486                         r[++ri] = ci;
5487                     }
5488                 }
5489                 return r;
5490             },
5491
5492             "nodeValue" : function(c, v){
5493                 var r = [], ri = -1;
5494                 for(var i = 0, ci; ci = c[i]; i++){
5495                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5496                         r[++ri] = ci;
5497                     }
5498                 }
5499                 return r;
5500             },
5501
5502             "checked" : function(c){
5503                 var r = [], ri = -1;
5504                 for(var i = 0, ci; ci = c[i]; i++){
5505                     if(ci.checked == true){
5506                         r[++ri] = ci;
5507                     }
5508                 }
5509                 return r;
5510             },
5511
5512             "not" : function(c, ss){
5513                 return Roo.DomQuery.filter(c, ss, true);
5514             },
5515
5516             "odd" : function(c){
5517                 return this["nth-child"](c, "odd");
5518             },
5519
5520             "even" : function(c){
5521                 return this["nth-child"](c, "even");
5522             },
5523
5524             "nth" : function(c, a){
5525                 return c[a-1] || [];
5526             },
5527
5528             "first" : function(c){
5529                 return c[0] || [];
5530             },
5531
5532             "last" : function(c){
5533                 return c[c.length-1] || [];
5534             },
5535
5536             "has" : function(c, ss){
5537                 var s = Roo.DomQuery.select;
5538                 var r = [], ri = -1;
5539                 for(var i = 0, ci; ci = c[i]; i++){
5540                     if(s(ss, ci).length > 0){
5541                         r[++ri] = ci;
5542                     }
5543                 }
5544                 return r;
5545             },
5546
5547             "next" : function(c, ss){
5548                 var is = Roo.DomQuery.is;
5549                 var r = [], ri = -1;
5550                 for(var i = 0, ci; ci = c[i]; i++){
5551                     var n = next(ci);
5552                     if(n && is(n, ss)){
5553                         r[++ri] = ci;
5554                     }
5555                 }
5556                 return r;
5557             },
5558
5559             "prev" : function(c, ss){
5560                 var is = Roo.DomQuery.is;
5561                 var r = [], ri = -1;
5562                 for(var i = 0, ci; ci = c[i]; i++){
5563                     var n = prev(ci);
5564                     if(n && is(n, ss)){
5565                         r[++ri] = ci;
5566                     }
5567                 }
5568                 return r;
5569             }
5570         }
5571     };
5572 }();
5573
5574 /**
5575  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5576  * @param {String} path The selector/xpath query
5577  * @param {Node} root (optional) The start of the query (defaults to document).
5578  * @return {Array}
5579  * @member Roo
5580  * @method query
5581  */
5582 Roo.query = Roo.DomQuery.select;
5583 /*
5584  * Based on:
5585  * Ext JS Library 1.1.1
5586  * Copyright(c) 2006-2007, Ext JS, LLC.
5587  *
5588  * Originally Released Under LGPL - original licence link has changed is not relivant.
5589  *
5590  * Fork - LGPL
5591  * <script type="text/javascript">
5592  */
5593
5594 /**
5595  * @class Roo.util.Observable
5596  * Base class that provides a common interface for publishing events. Subclasses are expected to
5597  * to have a property "events" with all the events defined.<br>
5598  * For example:
5599  * <pre><code>
5600  Employee = function(name){
5601     this.name = name;
5602     this.addEvents({
5603         "fired" : true,
5604         "quit" : true
5605     });
5606  }
5607  Roo.extend(Employee, Roo.util.Observable);
5608 </code></pre>
5609  * @param {Object} config properties to use (incuding events / listeners)
5610  */
5611
5612 Roo.util.Observable = function(cfg){
5613     
5614     cfg = cfg|| {};
5615     this.addEvents(cfg.events || {});
5616     if (cfg.events) {
5617         delete cfg.events; // make sure
5618     }
5619      
5620     Roo.apply(this, cfg);
5621     
5622     if(this.listeners){
5623         this.on(this.listeners);
5624         delete this.listeners;
5625     }
5626 };
5627 Roo.util.Observable.prototype = {
5628     /** 
5629  * @cfg {Object} listeners  list of events and functions to call for this object, 
5630  * For example :
5631  * <pre><code>
5632     listeners :  { 
5633        'click' : function(e) {
5634            ..... 
5635         } ,
5636         .... 
5637     } 
5638   </code></pre>
5639  */
5640     
5641     
5642     /**
5643      * Fires the specified event with the passed parameters (minus the event name).
5644      * @param {String} eventName
5645      * @param {Object...} args Variable number of parameters are passed to handlers
5646      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5647      */
5648     fireEvent : function(){
5649         var ce = this.events[arguments[0].toLowerCase()];
5650         if(typeof ce == "object"){
5651             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5652         }else{
5653             return true;
5654         }
5655     },
5656
5657     // private
5658     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5659
5660     /**
5661      * Appends an event handler to this component
5662      * @param {String}   eventName The type of event to listen for
5663      * @param {Function} handler The method the event invokes
5664      * @param {Object}   scope (optional) The scope in which to execute the handler
5665      * function. The handler function's "this" context.
5666      * @param {Object}   options (optional) An object containing handler configuration
5667      * properties. This may contain any of the following properties:<ul>
5668      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5669      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5670      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5671      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5672      * by the specified number of milliseconds. If the event fires again within that time, the original
5673      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5674      * </ul><br>
5675      * <p>
5676      * <b>Combining Options</b><br>
5677      * Using the options argument, it is possible to combine different types of listeners:<br>
5678      * <br>
5679      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5680                 <pre><code>
5681                 el.on('click', this.onClick, this, {
5682                         single: true,
5683                 delay: 100,
5684                 forumId: 4
5685                 });
5686                 </code></pre>
5687      * <p>
5688      * <b>Attaching multiple handlers in 1 call</b><br>
5689      * The method also allows for a single argument to be passed which is a config object containing properties
5690      * which specify multiple handlers.
5691      * <pre><code>
5692                 el.on({
5693                         'click': {
5694                         fn: this.onClick,
5695                         scope: this,
5696                         delay: 100
5697                 }, 
5698                 'mouseover': {
5699                         fn: this.onMouseOver,
5700                         scope: this
5701                 },
5702                 'mouseout': {
5703                         fn: this.onMouseOut,
5704                         scope: this
5705                 }
5706                 });
5707                 </code></pre>
5708      * <p>
5709      * Or a shorthand syntax which passes the same scope object to all handlers:
5710         <pre><code>
5711                 el.on({
5712                         'click': this.onClick,
5713                 'mouseover': this.onMouseOver,
5714                 'mouseout': this.onMouseOut,
5715                 scope: this
5716                 });
5717                 </code></pre>
5718      */
5719     addListener : function(eventName, fn, scope, o){
5720         if(typeof eventName == "object"){
5721             o = eventName;
5722             for(var e in o){
5723                 if(this.filterOptRe.test(e)){
5724                     continue;
5725                 }
5726                 if(typeof o[e] == "function"){
5727                     // shared options
5728                     this.addListener(e, o[e], o.scope,  o);
5729                 }else{
5730                     // individual options
5731                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5732                 }
5733             }
5734             return;
5735         }
5736         o = (!o || typeof o == "boolean") ? {} : o;
5737         eventName = eventName.toLowerCase();
5738         var ce = this.events[eventName] || true;
5739         if(typeof ce == "boolean"){
5740             ce = new Roo.util.Event(this, eventName);
5741             this.events[eventName] = ce;
5742         }
5743         ce.addListener(fn, scope, o);
5744     },
5745
5746     /**
5747      * Removes a listener
5748      * @param {String}   eventName     The type of event to listen for
5749      * @param {Function} handler        The handler to remove
5750      * @param {Object}   scope  (optional) The scope (this object) for the handler
5751      */
5752     removeListener : function(eventName, fn, scope){
5753         var ce = this.events[eventName.toLowerCase()];
5754         if(typeof ce == "object"){
5755             ce.removeListener(fn, scope);
5756         }
5757     },
5758
5759     /**
5760      * Removes all listeners for this object
5761      */
5762     purgeListeners : function(){
5763         for(var evt in this.events){
5764             if(typeof this.events[evt] == "object"){
5765                  this.events[evt].clearListeners();
5766             }
5767         }
5768     },
5769
5770     relayEvents : function(o, events){
5771         var createHandler = function(ename){
5772             return function(){
5773                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5774             };
5775         };
5776         for(var i = 0, len = events.length; i < len; i++){
5777             var ename = events[i];
5778             if(!this.events[ename]){ this.events[ename] = true; };
5779             o.on(ename, createHandler(ename), this);
5780         }
5781     },
5782
5783     /**
5784      * Used to define events on this Observable
5785      * @param {Object} object The object with the events defined
5786      */
5787     addEvents : function(o){
5788         if(!this.events){
5789             this.events = {};
5790         }
5791         Roo.applyIf(this.events, o);
5792     },
5793
5794     /**
5795      * Checks to see if this object has any listeners for a specified event
5796      * @param {String} eventName The name of the event to check for
5797      * @return {Boolean} True if the event is being listened for, else false
5798      */
5799     hasListener : function(eventName){
5800         var e = this.events[eventName];
5801         return typeof e == "object" && e.listeners.length > 0;
5802     }
5803 };
5804 /**
5805  * Appends an event handler to this element (shorthand for addListener)
5806  * @param {String}   eventName     The type of event to listen for
5807  * @param {Function} handler        The method the event invokes
5808  * @param {Object}   scope (optional) The scope in which to execute the handler
5809  * function. The handler function's "this" context.
5810  * @param {Object}   options  (optional)
5811  * @method
5812  */
5813 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5814 /**
5815  * Removes a listener (shorthand for removeListener)
5816  * @param {String}   eventName     The type of event to listen for
5817  * @param {Function} handler        The handler to remove
5818  * @param {Object}   scope  (optional) The scope (this object) for the handler
5819  * @method
5820  */
5821 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5822
5823 /**
5824  * Starts capture on the specified Observable. All events will be passed
5825  * to the supplied function with the event name + standard signature of the event
5826  * <b>before</b> the event is fired. If the supplied function returns false,
5827  * the event will not fire.
5828  * @param {Observable} o The Observable to capture
5829  * @param {Function} fn The function to call
5830  * @param {Object} scope (optional) The scope (this object) for the fn
5831  * @static
5832  */
5833 Roo.util.Observable.capture = function(o, fn, scope){
5834     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5835 };
5836
5837 /**
5838  * Removes <b>all</b> added captures from the Observable.
5839  * @param {Observable} o The Observable to release
5840  * @static
5841  */
5842 Roo.util.Observable.releaseCapture = function(o){
5843     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5844 };
5845
5846 (function(){
5847
5848     var createBuffered = function(h, o, scope){
5849         var task = new Roo.util.DelayedTask();
5850         return function(){
5851             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5852         };
5853     };
5854
5855     var createSingle = function(h, e, fn, scope){
5856         return function(){
5857             e.removeListener(fn, scope);
5858             return h.apply(scope, arguments);
5859         };
5860     };
5861
5862     var createDelayed = function(h, o, scope){
5863         return function(){
5864             var args = Array.prototype.slice.call(arguments, 0);
5865             setTimeout(function(){
5866                 h.apply(scope, args);
5867             }, o.delay || 10);
5868         };
5869     };
5870
5871     Roo.util.Event = function(obj, name){
5872         this.name = name;
5873         this.obj = obj;
5874         this.listeners = [];
5875     };
5876
5877     Roo.util.Event.prototype = {
5878         addListener : function(fn, scope, options){
5879             var o = options || {};
5880             scope = scope || this.obj;
5881             if(!this.isListening(fn, scope)){
5882                 var l = {fn: fn, scope: scope, options: o};
5883                 var h = fn;
5884                 if(o.delay){
5885                     h = createDelayed(h, o, scope);
5886                 }
5887                 if(o.single){
5888                     h = createSingle(h, this, fn, scope);
5889                 }
5890                 if(o.buffer){
5891                     h = createBuffered(h, o, scope);
5892                 }
5893                 l.fireFn = h;
5894                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5895                     this.listeners.push(l);
5896                 }else{
5897                     this.listeners = this.listeners.slice(0);
5898                     this.listeners.push(l);
5899                 }
5900             }
5901         },
5902
5903         findListener : function(fn, scope){
5904             scope = scope || this.obj;
5905             var ls = this.listeners;
5906             for(var i = 0, len = ls.length; i < len; i++){
5907                 var l = ls[i];
5908                 if(l.fn == fn && l.scope == scope){
5909                     return i;
5910                 }
5911             }
5912             return -1;
5913         },
5914
5915         isListening : function(fn, scope){
5916             return this.findListener(fn, scope) != -1;
5917         },
5918
5919         removeListener : function(fn, scope){
5920             var index;
5921             if((index = this.findListener(fn, scope)) != -1){
5922                 if(!this.firing){
5923                     this.listeners.splice(index, 1);
5924                 }else{
5925                     this.listeners = this.listeners.slice(0);
5926                     this.listeners.splice(index, 1);
5927                 }
5928                 return true;
5929             }
5930             return false;
5931         },
5932
5933         clearListeners : function(){
5934             this.listeners = [];
5935         },
5936
5937         fire : function(){
5938             var ls = this.listeners, scope, len = ls.length;
5939             if(len > 0){
5940                 this.firing = true;
5941                 var args = Array.prototype.slice.call(arguments, 0);
5942                 for(var i = 0; i < len; i++){
5943                     var l = ls[i];
5944                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5945                         this.firing = false;
5946                         return false;
5947                     }
5948                 }
5949                 this.firing = false;
5950             }
5951             return true;
5952         }
5953     };
5954 })();/*
5955  * Based on:
5956  * Ext JS Library 1.1.1
5957  * Copyright(c) 2006-2007, Ext JS, LLC.
5958  *
5959  * Originally Released Under LGPL - original licence link has changed is not relivant.
5960  *
5961  * Fork - LGPL
5962  * <script type="text/javascript">
5963  */
5964
5965 /**
5966  * @class Roo.EventManager
5967  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5968  * several useful events directly.
5969  * See {@link Roo.EventObject} for more details on normalized event objects.
5970  * @singleton
5971  */
5972 Roo.EventManager = function(){
5973     var docReadyEvent, docReadyProcId, docReadyState = false;
5974     var resizeEvent, resizeTask, textEvent, textSize;
5975     var E = Roo.lib.Event;
5976     var D = Roo.lib.Dom;
5977
5978
5979     var fireDocReady = function(){
5980         if(!docReadyState){
5981             docReadyState = true;
5982             Roo.isReady = true;
5983             if(docReadyProcId){
5984                 clearInterval(docReadyProcId);
5985             }
5986             if(Roo.isGecko || Roo.isOpera) {
5987                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5988             }
5989             if(Roo.isIE){
5990                 var defer = document.getElementById("ie-deferred-loader");
5991                 if(defer){
5992                     defer.onreadystatechange = null;
5993                     defer.parentNode.removeChild(defer);
5994                 }
5995             }
5996             if(docReadyEvent){
5997                 docReadyEvent.fire();
5998                 docReadyEvent.clearListeners();
5999             }
6000         }
6001     };
6002     
6003     var initDocReady = function(){
6004         docReadyEvent = new Roo.util.Event();
6005         if(Roo.isGecko || Roo.isOpera) {
6006             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6007         }else if(Roo.isIE){
6008             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6009             var defer = document.getElementById("ie-deferred-loader");
6010             defer.onreadystatechange = function(){
6011                 if(this.readyState == "complete"){
6012                     fireDocReady();
6013                 }
6014             };
6015         }else if(Roo.isSafari){ 
6016             docReadyProcId = setInterval(function(){
6017                 var rs = document.readyState;
6018                 if(rs == "complete") {
6019                     fireDocReady();     
6020                  }
6021             }, 10);
6022         }
6023         // no matter what, make sure it fires on load
6024         E.on(window, "load", fireDocReady);
6025     };
6026
6027     var createBuffered = function(h, o){
6028         var task = new Roo.util.DelayedTask(h);
6029         return function(e){
6030             // create new event object impl so new events don't wipe out properties
6031             e = new Roo.EventObjectImpl(e);
6032             task.delay(o.buffer, h, null, [e]);
6033         };
6034     };
6035
6036     var createSingle = function(h, el, ename, fn){
6037         return function(e){
6038             Roo.EventManager.removeListener(el, ename, fn);
6039             h(e);
6040         };
6041     };
6042
6043     var createDelayed = function(h, o){
6044         return function(e){
6045             // create new event object impl so new events don't wipe out properties
6046             e = new Roo.EventObjectImpl(e);
6047             setTimeout(function(){
6048                 h(e);
6049             }, o.delay || 10);
6050         };
6051     };
6052
6053     var listen = function(element, ename, opt, fn, scope){
6054         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6055         fn = fn || o.fn; scope = scope || o.scope;
6056         var el = Roo.getDom(element);
6057         if(!el){
6058             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6059         }
6060         var h = function(e){
6061             e = Roo.EventObject.setEvent(e);
6062             var t;
6063             if(o.delegate){
6064                 t = e.getTarget(o.delegate, el);
6065                 if(!t){
6066                     return;
6067                 }
6068             }else{
6069                 t = e.target;
6070             }
6071             if(o.stopEvent === true){
6072                 e.stopEvent();
6073             }
6074             if(o.preventDefault === true){
6075                e.preventDefault();
6076             }
6077             if(o.stopPropagation === true){
6078                 e.stopPropagation();
6079             }
6080
6081             if(o.normalized === false){
6082                 e = e.browserEvent;
6083             }
6084
6085             fn.call(scope || el, e, t, o);
6086         };
6087         if(o.delay){
6088             h = createDelayed(h, o);
6089         }
6090         if(o.single){
6091             h = createSingle(h, el, ename, fn);
6092         }
6093         if(o.buffer){
6094             h = createBuffered(h, o);
6095         }
6096         fn._handlers = fn._handlers || [];
6097         fn._handlers.push([Roo.id(el), ename, h]);
6098
6099         E.on(el, ename, h);
6100         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6101             el.addEventListener("DOMMouseScroll", h, false);
6102             E.on(window, 'unload', function(){
6103                 el.removeEventListener("DOMMouseScroll", h, false);
6104             });
6105         }
6106         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6107             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6108         }
6109         return h;
6110     };
6111
6112     var stopListening = function(el, ename, fn){
6113         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6114         if(hds){
6115             for(var i = 0, len = hds.length; i < len; i++){
6116                 var h = hds[i];
6117                 if(h[0] == id && h[1] == ename){
6118                     hd = h[2];
6119                     hds.splice(i, 1);
6120                     break;
6121                 }
6122             }
6123         }
6124         E.un(el, ename, hd);
6125         el = Roo.getDom(el);
6126         if(ename == "mousewheel" && el.addEventListener){
6127             el.removeEventListener("DOMMouseScroll", hd, false);
6128         }
6129         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6130             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6131         }
6132     };
6133
6134     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6135     
6136     var pub = {
6137         
6138         
6139         /** 
6140          * Fix for doc tools
6141          * @scope Roo.EventManager
6142          */
6143         
6144         
6145         /** 
6146          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6147          * object with a Roo.EventObject
6148          * @param {Function} fn        The method the event invokes
6149          * @param {Object}   scope    An object that becomes the scope of the handler
6150          * @param {boolean}  override If true, the obj passed in becomes
6151          *                             the execution scope of the listener
6152          * @return {Function} The wrapped function
6153          * @deprecated
6154          */
6155         wrap : function(fn, scope, override){
6156             return function(e){
6157                 Roo.EventObject.setEvent(e);
6158                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6159             };
6160         },
6161         
6162         /**
6163      * Appends an event handler to an element (shorthand for addListener)
6164      * @param {String/HTMLElement}   element        The html element or id to assign the
6165      * @param {String}   eventName The type of event to listen for
6166      * @param {Function} handler The method the event invokes
6167      * @param {Object}   scope (optional) The scope in which to execute the handler
6168      * function. The handler function's "this" context.
6169      * @param {Object}   options (optional) An object containing handler configuration
6170      * properties. This may contain any of the following properties:<ul>
6171      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6172      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6173      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6174      * <li>preventDefault {Boolean} True to prevent the default action</li>
6175      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6176      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6177      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6178      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6179      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6180      * by the specified number of milliseconds. If the event fires again within that time, the original
6181      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6182      * </ul><br>
6183      * <p>
6184      * <b>Combining Options</b><br>
6185      * Using the options argument, it is possible to combine different types of listeners:<br>
6186      * <br>
6187      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6188      * Code:<pre><code>
6189 el.on('click', this.onClick, this, {
6190     single: true,
6191     delay: 100,
6192     stopEvent : true,
6193     forumId: 4
6194 });</code></pre>
6195      * <p>
6196      * <b>Attaching multiple handlers in 1 call</b><br>
6197       * The method also allows for a single argument to be passed which is a config object containing properties
6198      * which specify multiple handlers.
6199      * <p>
6200      * Code:<pre><code>
6201 el.on({
6202     'click' : {
6203         fn: this.onClick
6204         scope: this,
6205         delay: 100
6206     },
6207     'mouseover' : {
6208         fn: this.onMouseOver
6209         scope: this
6210     },
6211     'mouseout' : {
6212         fn: this.onMouseOut
6213         scope: this
6214     }
6215 });</code></pre>
6216      * <p>
6217      * Or a shorthand syntax:<br>
6218      * Code:<pre><code>
6219 el.on({
6220     'click' : this.onClick,
6221     'mouseover' : this.onMouseOver,
6222     'mouseout' : this.onMouseOut
6223     scope: this
6224 });</code></pre>
6225      */
6226         addListener : function(element, eventName, fn, scope, options){
6227             if(typeof eventName == "object"){
6228                 var o = eventName;
6229                 for(var e in o){
6230                     if(propRe.test(e)){
6231                         continue;
6232                     }
6233                     if(typeof o[e] == "function"){
6234                         // shared options
6235                         listen(element, e, o, o[e], o.scope);
6236                     }else{
6237                         // individual options
6238                         listen(element, e, o[e]);
6239                     }
6240                 }
6241                 return;
6242             }
6243             return listen(element, eventName, options, fn, scope);
6244         },
6245         
6246         /**
6247          * Removes an event handler
6248          *
6249          * @param {String/HTMLElement}   element        The id or html element to remove the 
6250          *                             event from
6251          * @param {String}   eventName     The type of event
6252          * @param {Function} fn
6253          * @return {Boolean} True if a listener was actually removed
6254          */
6255         removeListener : function(element, eventName, fn){
6256             return stopListening(element, eventName, fn);
6257         },
6258         
6259         /**
6260          * Fires when the document is ready (before onload and before images are loaded). Can be 
6261          * accessed shorthanded Roo.onReady().
6262          * @param {Function} fn        The method the event invokes
6263          * @param {Object}   scope    An  object that becomes the scope of the handler
6264          * @param {boolean}  options
6265          */
6266         onDocumentReady : function(fn, scope, options){
6267             if(docReadyState){ // if it already fired
6268                 docReadyEvent.addListener(fn, scope, options);
6269                 docReadyEvent.fire();
6270                 docReadyEvent.clearListeners();
6271                 return;
6272             }
6273             if(!docReadyEvent){
6274                 initDocReady();
6275             }
6276             docReadyEvent.addListener(fn, scope, options);
6277         },
6278         
6279         /**
6280          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6281          * @param {Function} fn        The method the event invokes
6282          * @param {Object}   scope    An object that becomes the scope of the handler
6283          * @param {boolean}  options
6284          */
6285         onWindowResize : function(fn, scope, options){
6286             if(!resizeEvent){
6287                 resizeEvent = new Roo.util.Event();
6288                 resizeTask = new Roo.util.DelayedTask(function(){
6289                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6290                 });
6291                 E.on(window, "resize", function(){
6292                     if(Roo.isIE){
6293                         resizeTask.delay(50);
6294                     }else{
6295                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6296                     }
6297                 });
6298             }
6299             resizeEvent.addListener(fn, scope, options);
6300         },
6301
6302         /**
6303          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6304          * @param {Function} fn        The method the event invokes
6305          * @param {Object}   scope    An object that becomes the scope of the handler
6306          * @param {boolean}  options
6307          */
6308         onTextResize : function(fn, scope, options){
6309             if(!textEvent){
6310                 textEvent = new Roo.util.Event();
6311                 var textEl = new Roo.Element(document.createElement('div'));
6312                 textEl.dom.className = 'x-text-resize';
6313                 textEl.dom.innerHTML = 'X';
6314                 textEl.appendTo(document.body);
6315                 textSize = textEl.dom.offsetHeight;
6316                 setInterval(function(){
6317                     if(textEl.dom.offsetHeight != textSize){
6318                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6319                     }
6320                 }, this.textResizeInterval);
6321             }
6322             textEvent.addListener(fn, scope, options);
6323         },
6324
6325         /**
6326          * Removes the passed window resize listener.
6327          * @param {Function} fn        The method the event invokes
6328          * @param {Object}   scope    The scope of handler
6329          */
6330         removeResizeListener : function(fn, scope){
6331             if(resizeEvent){
6332                 resizeEvent.removeListener(fn, scope);
6333             }
6334         },
6335
6336         // private
6337         fireResize : function(){
6338             if(resizeEvent){
6339                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6340             }   
6341         },
6342         /**
6343          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6344          */
6345         ieDeferSrc : false,
6346         /**
6347          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6348          */
6349         textResizeInterval : 50
6350     };
6351     
6352     /**
6353      * Fix for doc tools
6354      * @scopeAlias pub=Roo.EventManager
6355      */
6356     
6357      /**
6358      * Appends an event handler to an element (shorthand for addListener)
6359      * @param {String/HTMLElement}   element        The html element or id to assign the
6360      * @param {String}   eventName The type of event to listen for
6361      * @param {Function} handler The method the event invokes
6362      * @param {Object}   scope (optional) The scope in which to execute the handler
6363      * function. The handler function's "this" context.
6364      * @param {Object}   options (optional) An object containing handler configuration
6365      * properties. This may contain any of the following properties:<ul>
6366      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6367      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6368      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6369      * <li>preventDefault {Boolean} True to prevent the default action</li>
6370      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6371      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6372      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6373      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6374      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6375      * by the specified number of milliseconds. If the event fires again within that time, the original
6376      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6377      * </ul><br>
6378      * <p>
6379      * <b>Combining Options</b><br>
6380      * Using the options argument, it is possible to combine different types of listeners:<br>
6381      * <br>
6382      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6383      * Code:<pre><code>
6384 el.on('click', this.onClick, this, {
6385     single: true,
6386     delay: 100,
6387     stopEvent : true,
6388     forumId: 4
6389 });</code></pre>
6390      * <p>
6391      * <b>Attaching multiple handlers in 1 call</b><br>
6392       * The method also allows for a single argument to be passed which is a config object containing properties
6393      * which specify multiple handlers.
6394      * <p>
6395      * Code:<pre><code>
6396 el.on({
6397     'click' : {
6398         fn: this.onClick
6399         scope: this,
6400         delay: 100
6401     },
6402     'mouseover' : {
6403         fn: this.onMouseOver
6404         scope: this
6405     },
6406     'mouseout' : {
6407         fn: this.onMouseOut
6408         scope: this
6409     }
6410 });</code></pre>
6411      * <p>
6412      * Or a shorthand syntax:<br>
6413      * Code:<pre><code>
6414 el.on({
6415     'click' : this.onClick,
6416     'mouseover' : this.onMouseOver,
6417     'mouseout' : this.onMouseOut
6418     scope: this
6419 });</code></pre>
6420      */
6421     pub.on = pub.addListener;
6422     pub.un = pub.removeListener;
6423
6424     pub.stoppedMouseDownEvent = new Roo.util.Event();
6425     return pub;
6426 }();
6427 /**
6428   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6429   * @param {Function} fn        The method the event invokes
6430   * @param {Object}   scope    An  object that becomes the scope of the handler
6431   * @param {boolean}  override If true, the obj passed in becomes
6432   *                             the execution scope of the listener
6433   * @member Roo
6434   * @method onReady
6435  */
6436 Roo.onReady = Roo.EventManager.onDocumentReady;
6437
6438 Roo.onReady(function(){
6439     var bd = Roo.get(document.body);
6440     if(!bd){ return; }
6441
6442     var cls = [
6443             Roo.isIE ? "roo-ie"
6444             : Roo.isGecko ? "roo-gecko"
6445             : Roo.isOpera ? "roo-opera"
6446             : Roo.isSafari ? "roo-safari" : ""];
6447
6448     if(Roo.isMac){
6449         cls.push("roo-mac");
6450     }
6451     if(Roo.isLinux){
6452         cls.push("roo-linux");
6453     }
6454     if(Roo.isBorderBox){
6455         cls.push('roo-border-box');
6456     }
6457     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6458         var p = bd.dom.parentNode;
6459         if(p){
6460             p.className += ' roo-strict';
6461         }
6462     }
6463     bd.addClass(cls.join(' '));
6464 });
6465
6466 /**
6467  * @class Roo.EventObject
6468  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6469  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6470  * Example:
6471  * <pre><code>
6472  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6473     e.preventDefault();
6474     var target = e.getTarget();
6475     ...
6476  }
6477  var myDiv = Roo.get("myDiv");
6478  myDiv.on("click", handleClick);
6479  //or
6480  Roo.EventManager.on("myDiv", 'click', handleClick);
6481  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6482  </code></pre>
6483  * @singleton
6484  */
6485 Roo.EventObject = function(){
6486     
6487     var E = Roo.lib.Event;
6488     
6489     // safari keypress events for special keys return bad keycodes
6490     var safariKeys = {
6491         63234 : 37, // left
6492         63235 : 39, // right
6493         63232 : 38, // up
6494         63233 : 40, // down
6495         63276 : 33, // page up
6496         63277 : 34, // page down
6497         63272 : 46, // delete
6498         63273 : 36, // home
6499         63275 : 35  // end
6500     };
6501
6502     // normalize button clicks
6503     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6504                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6505
6506     Roo.EventObjectImpl = function(e){
6507         if(e){
6508             this.setEvent(e.browserEvent || e);
6509         }
6510     };
6511     Roo.EventObjectImpl.prototype = {
6512         /**
6513          * Used to fix doc tools.
6514          * @scope Roo.EventObject.prototype
6515          */
6516             
6517
6518         
6519         
6520         /** The normal browser event */
6521         browserEvent : null,
6522         /** The button pressed in a mouse event */
6523         button : -1,
6524         /** True if the shift key was down during the event */
6525         shiftKey : false,
6526         /** True if the control key was down during the event */
6527         ctrlKey : false,
6528         /** True if the alt key was down during the event */
6529         altKey : false,
6530
6531         /** Key constant 
6532         * @type Number */
6533         BACKSPACE : 8,
6534         /** Key constant 
6535         * @type Number */
6536         TAB : 9,
6537         /** Key constant 
6538         * @type Number */
6539         RETURN : 13,
6540         /** Key constant 
6541         * @type Number */
6542         ENTER : 13,
6543         /** Key constant 
6544         * @type Number */
6545         SHIFT : 16,
6546         /** Key constant 
6547         * @type Number */
6548         CONTROL : 17,
6549         /** Key constant 
6550         * @type Number */
6551         ESC : 27,
6552         /** Key constant 
6553         * @type Number */
6554         SPACE : 32,
6555         /** Key constant 
6556         * @type Number */
6557         PAGEUP : 33,
6558         /** Key constant 
6559         * @type Number */
6560         PAGEDOWN : 34,
6561         /** Key constant 
6562         * @type Number */
6563         END : 35,
6564         /** Key constant 
6565         * @type Number */
6566         HOME : 36,
6567         /** Key constant 
6568         * @type Number */
6569         LEFT : 37,
6570         /** Key constant 
6571         * @type Number */
6572         UP : 38,
6573         /** Key constant 
6574         * @type Number */
6575         RIGHT : 39,
6576         /** Key constant 
6577         * @type Number */
6578         DOWN : 40,
6579         /** Key constant 
6580         * @type Number */
6581         DELETE : 46,
6582         /** Key constant 
6583         * @type Number */
6584         F5 : 116,
6585
6586            /** @private */
6587         setEvent : function(e){
6588             if(e == this || (e && e.browserEvent)){ // already wrapped
6589                 return e;
6590             }
6591             this.browserEvent = e;
6592             if(e){
6593                 // normalize buttons
6594                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6595                 if(e.type == 'click' && this.button == -1){
6596                     this.button = 0;
6597                 }
6598                 this.type = e.type;
6599                 this.shiftKey = e.shiftKey;
6600                 // mac metaKey behaves like ctrlKey
6601                 this.ctrlKey = e.ctrlKey || e.metaKey;
6602                 this.altKey = e.altKey;
6603                 // in getKey these will be normalized for the mac
6604                 this.keyCode = e.keyCode;
6605                 // keyup warnings on firefox.
6606                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6607                 // cache the target for the delayed and or buffered events
6608                 this.target = E.getTarget(e);
6609                 // same for XY
6610                 this.xy = E.getXY(e);
6611             }else{
6612                 this.button = -1;
6613                 this.shiftKey = false;
6614                 this.ctrlKey = false;
6615                 this.altKey = false;
6616                 this.keyCode = 0;
6617                 this.charCode =0;
6618                 this.target = null;
6619                 this.xy = [0, 0];
6620             }
6621             return this;
6622         },
6623
6624         /**
6625          * Stop the event (preventDefault and stopPropagation)
6626          */
6627         stopEvent : function(){
6628             if(this.browserEvent){
6629                 if(this.browserEvent.type == 'mousedown'){
6630                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6631                 }
6632                 E.stopEvent(this.browserEvent);
6633             }
6634         },
6635
6636         /**
6637          * Prevents the browsers default handling of the event.
6638          */
6639         preventDefault : function(){
6640             if(this.browserEvent){
6641                 E.preventDefault(this.browserEvent);
6642             }
6643         },
6644
6645         /** @private */
6646         isNavKeyPress : function(){
6647             var k = this.keyCode;
6648             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6649             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6650         },
6651
6652         isSpecialKey : function(){
6653             var k = this.keyCode;
6654             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6655             (k == 16) || (k == 17) ||
6656             (k >= 18 && k <= 20) ||
6657             (k >= 33 && k <= 35) ||
6658             (k >= 36 && k <= 39) ||
6659             (k >= 44 && k <= 45);
6660         },
6661         /**
6662          * Cancels bubbling of the event.
6663          */
6664         stopPropagation : function(){
6665             if(this.browserEvent){
6666                 if(this.type == 'mousedown'){
6667                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6668                 }
6669                 E.stopPropagation(this.browserEvent);
6670             }
6671         },
6672
6673         /**
6674          * Gets the key code for the event.
6675          * @return {Number}
6676          */
6677         getCharCode : function(){
6678             return this.charCode || this.keyCode;
6679         },
6680
6681         /**
6682          * Returns a normalized keyCode for the event.
6683          * @return {Number} The key code
6684          */
6685         getKey : function(){
6686             var k = this.keyCode || this.charCode;
6687             return Roo.isSafari ? (safariKeys[k] || k) : k;
6688         },
6689
6690         /**
6691          * Gets the x coordinate of the event.
6692          * @return {Number}
6693          */
6694         getPageX : function(){
6695             return this.xy[0];
6696         },
6697
6698         /**
6699          * Gets the y coordinate of the event.
6700          * @return {Number}
6701          */
6702         getPageY : function(){
6703             return this.xy[1];
6704         },
6705
6706         /**
6707          * Gets the time of the event.
6708          * @return {Number}
6709          */
6710         getTime : function(){
6711             if(this.browserEvent){
6712                 return E.getTime(this.browserEvent);
6713             }
6714             return null;
6715         },
6716
6717         /**
6718          * Gets the page coordinates of the event.
6719          * @return {Array} The xy values like [x, y]
6720          */
6721         getXY : function(){
6722             return this.xy;
6723         },
6724
6725         /**
6726          * Gets the target for the event.
6727          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6728          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6729                 search as a number or element (defaults to 10 || document.body)
6730          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6731          * @return {HTMLelement}
6732          */
6733         getTarget : function(selector, maxDepth, returnEl){
6734             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6735         },
6736         /**
6737          * Gets the related target.
6738          * @return {HTMLElement}
6739          */
6740         getRelatedTarget : function(){
6741             if(this.browserEvent){
6742                 return E.getRelatedTarget(this.browserEvent);
6743             }
6744             return null;
6745         },
6746
6747         /**
6748          * Normalizes mouse wheel delta across browsers
6749          * @return {Number} The delta
6750          */
6751         getWheelDelta : function(){
6752             var e = this.browserEvent;
6753             var delta = 0;
6754             if(e.wheelDelta){ /* IE/Opera. */
6755                 delta = e.wheelDelta/120;
6756             }else if(e.detail){ /* Mozilla case. */
6757                 delta = -e.detail/3;
6758             }
6759             return delta;
6760         },
6761
6762         /**
6763          * Returns true if the control, meta, shift or alt key was pressed during this event.
6764          * @return {Boolean}
6765          */
6766         hasModifier : function(){
6767             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6768         },
6769
6770         /**
6771          * Returns true if the target of this event equals el or is a child of el
6772          * @param {String/HTMLElement/Element} el
6773          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6774          * @return {Boolean}
6775          */
6776         within : function(el, related){
6777             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6778             return t && Roo.fly(el).contains(t);
6779         },
6780
6781         getPoint : function(){
6782             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6783         }
6784     };
6785
6786     return new Roo.EventObjectImpl();
6787 }();
6788             
6789     /*
6790  * Based on:
6791  * Ext JS Library 1.1.1
6792  * Copyright(c) 2006-2007, Ext JS, LLC.
6793  *
6794  * Originally Released Under LGPL - original licence link has changed is not relivant.
6795  *
6796  * Fork - LGPL
6797  * <script type="text/javascript">
6798  */
6799
6800  
6801 // was in Composite Element!??!?!
6802  
6803 (function(){
6804     var D = Roo.lib.Dom;
6805     var E = Roo.lib.Event;
6806     var A = Roo.lib.Anim;
6807
6808     // local style camelizing for speed
6809     var propCache = {};
6810     var camelRe = /(-[a-z])/gi;
6811     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6812     var view = document.defaultView;
6813
6814 /**
6815  * @class Roo.Element
6816  * Represents an Element in the DOM.<br><br>
6817  * Usage:<br>
6818 <pre><code>
6819 var el = Roo.get("my-div");
6820
6821 // or with getEl
6822 var el = getEl("my-div");
6823
6824 // or with a DOM element
6825 var el = Roo.get(myDivElement);
6826 </code></pre>
6827  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6828  * each call instead of constructing a new one.<br><br>
6829  * <b>Animations</b><br />
6830  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6831  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6832 <pre>
6833 Option    Default   Description
6834 --------- --------  ---------------------------------------------
6835 duration  .35       The duration of the animation in seconds
6836 easing    easeOut   The YUI easing method
6837 callback  none      A function to execute when the anim completes
6838 scope     this      The scope (this) of the callback function
6839 </pre>
6840 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6841 * manipulate the animation. Here's an example:
6842 <pre><code>
6843 var el = Roo.get("my-div");
6844
6845 // no animation
6846 el.setWidth(100);
6847
6848 // default animation
6849 el.setWidth(100, true);
6850
6851 // animation with some options set
6852 el.setWidth(100, {
6853     duration: 1,
6854     callback: this.foo,
6855     scope: this
6856 });
6857
6858 // using the "anim" property to get the Anim object
6859 var opt = {
6860     duration: 1,
6861     callback: this.foo,
6862     scope: this
6863 };
6864 el.setWidth(100, opt);
6865 ...
6866 if(opt.anim.isAnimated()){
6867     opt.anim.stop();
6868 }
6869 </code></pre>
6870 * <b> Composite (Collections of) Elements</b><br />
6871  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6872  * @constructor Create a new Element directly.
6873  * @param {String/HTMLElement} element
6874  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6875  */
6876     Roo.Element = function(element, forceNew){
6877         var dom = typeof element == "string" ?
6878                 document.getElementById(element) : element;
6879         if(!dom){ // invalid id/element
6880             return null;
6881         }
6882         var id = dom.id;
6883         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6884             return Roo.Element.cache[id];
6885         }
6886
6887         /**
6888          * The DOM element
6889          * @type HTMLElement
6890          */
6891         this.dom = dom;
6892
6893         /**
6894          * The DOM element ID
6895          * @type String
6896          */
6897         this.id = id || Roo.id(dom);
6898     };
6899
6900     var El = Roo.Element;
6901
6902     El.prototype = {
6903         /**
6904          * The element's default display mode  (defaults to "")
6905          * @type String
6906          */
6907         originalDisplay : "",
6908
6909         visibilityMode : 1,
6910         /**
6911          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6912          * @type String
6913          */
6914         defaultUnit : "px",
6915         /**
6916          * Sets the element's visibility mode. When setVisible() is called it
6917          * will use this to determine whether to set the visibility or the display property.
6918          * @param visMode Element.VISIBILITY or Element.DISPLAY
6919          * @return {Roo.Element} this
6920          */
6921         setVisibilityMode : function(visMode){
6922             this.visibilityMode = visMode;
6923             return this;
6924         },
6925         /**
6926          * Convenience method for setVisibilityMode(Element.DISPLAY)
6927          * @param {String} display (optional) What to set display to when visible
6928          * @return {Roo.Element} this
6929          */
6930         enableDisplayMode : function(display){
6931             this.setVisibilityMode(El.DISPLAY);
6932             if(typeof display != "undefined") this.originalDisplay = display;
6933             return this;
6934         },
6935
6936         /**
6937          * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6938          * @param {String} selector The simple selector to test
6939          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6940                 search as a number or element (defaults to 10 || document.body)
6941          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6942          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6943          */
6944         findParent : function(simpleSelector, maxDepth, returnEl){
6945             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6946             maxDepth = maxDepth || 50;
6947             if(typeof maxDepth != "number"){
6948                 stopEl = Roo.getDom(maxDepth);
6949                 maxDepth = 10;
6950             }
6951             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6952                 if(dq.is(p, simpleSelector)){
6953                     return returnEl ? Roo.get(p) : p;
6954                 }
6955                 depth++;
6956                 p = p.parentNode;
6957             }
6958             return null;
6959         },
6960
6961
6962         /**
6963          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6964          * @param {String} selector The simple selector to test
6965          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6966                 search as a number or element (defaults to 10 || document.body)
6967          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6968          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6969          */
6970         findParentNode : function(simpleSelector, maxDepth, returnEl){
6971             var p = Roo.fly(this.dom.parentNode, '_internal');
6972             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6973         },
6974
6975         /**
6976          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6977          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6978          * @param {String} selector The simple selector to test
6979          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6980                 search as a number or element (defaults to 10 || document.body)
6981          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6982          */
6983         up : function(simpleSelector, maxDepth){
6984             return this.findParentNode(simpleSelector, maxDepth, true);
6985         },
6986
6987
6988
6989         /**
6990          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6991          * @param {String} selector The simple selector to test
6992          * @return {Boolean} True if this element matches the selector, else false
6993          */
6994         is : function(simpleSelector){
6995             return Roo.DomQuery.is(this.dom, simpleSelector);
6996         },
6997
6998         /**
6999          * Perform animation on this element.
7000          * @param {Object} args The YUI animation control args
7001          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7002          * @param {Function} onComplete (optional) Function to call when animation completes
7003          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7004          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7005          * @return {Roo.Element} this
7006          */
7007         animate : function(args, duration, onComplete, easing, animType){
7008             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7009             return this;
7010         },
7011
7012         /*
7013          * @private Internal animation call
7014          */
7015         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7016             animType = animType || 'run';
7017             opt = opt || {};
7018             var anim = Roo.lib.Anim[animType](
7019                 this.dom, args,
7020                 (opt.duration || defaultDur) || .35,
7021                 (opt.easing || defaultEase) || 'easeOut',
7022                 function(){
7023                     Roo.callback(cb, this);
7024                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7025                 },
7026                 this
7027             );
7028             opt.anim = anim;
7029             return anim;
7030         },
7031
7032         // private legacy anim prep
7033         preanim : function(a, i){
7034             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7035         },
7036
7037         /**
7038          * Removes worthless text nodes
7039          * @param {Boolean} forceReclean (optional) By default the element
7040          * keeps track if it has been cleaned already so
7041          * you can call this over and over. However, if you update the element and
7042          * need to force a reclean, you can pass true.
7043          */
7044         clean : function(forceReclean){
7045             if(this.isCleaned && forceReclean !== true){
7046                 return this;
7047             }
7048             var ns = /\S/;
7049             var d = this.dom, n = d.firstChild, ni = -1;
7050             while(n){
7051                 var nx = n.nextSibling;
7052                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7053                     d.removeChild(n);
7054                 }else{
7055                     n.nodeIndex = ++ni;
7056                 }
7057                 n = nx;
7058             }
7059             this.isCleaned = true;
7060             return this;
7061         },
7062
7063         // private
7064         calcOffsetsTo : function(el){
7065             el = Roo.get(el);
7066             var d = el.dom;
7067             var restorePos = false;
7068             if(el.getStyle('position') == 'static'){
7069                 el.position('relative');
7070                 restorePos = true;
7071             }
7072             var x = 0, y =0;
7073             var op = this.dom;
7074             while(op && op != d && op.tagName != 'HTML'){
7075                 x+= op.offsetLeft;
7076                 y+= op.offsetTop;
7077                 op = op.offsetParent;
7078             }
7079             if(restorePos){
7080                 el.position('static');
7081             }
7082             return [x, y];
7083         },
7084
7085         /**
7086          * Scrolls this element into view within the passed container.
7087          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7088          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7089          * @return {Roo.Element} this
7090          */
7091         scrollIntoView : function(container, hscroll){
7092             var c = Roo.getDom(container) || document.body;
7093             var el = this.dom;
7094
7095             var o = this.calcOffsetsTo(c),
7096                 l = o[0],
7097                 t = o[1],
7098                 b = t+el.offsetHeight,
7099                 r = l+el.offsetWidth;
7100
7101             var ch = c.clientHeight;
7102             var ct = parseInt(c.scrollTop, 10);
7103             var cl = parseInt(c.scrollLeft, 10);
7104             var cb = ct + ch;
7105             var cr = cl + c.clientWidth;
7106
7107             if(t < ct){
7108                 c.scrollTop = t;
7109             }else if(b > cb){
7110                 c.scrollTop = b-ch;
7111             }
7112
7113             if(hscroll !== false){
7114                 if(l < cl){
7115                     c.scrollLeft = l;
7116                 }else if(r > cr){
7117                     c.scrollLeft = r-c.clientWidth;
7118                 }
7119             }
7120             return this;
7121         },
7122
7123         // private
7124         scrollChildIntoView : function(child, hscroll){
7125             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7126         },
7127
7128         /**
7129          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7130          * the new height may not be available immediately.
7131          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7132          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7133          * @param {Function} onComplete (optional) Function to call when animation completes
7134          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7135          * @return {Roo.Element} this
7136          */
7137         autoHeight : function(animate, duration, onComplete, easing){
7138             var oldHeight = this.getHeight();
7139             this.clip();
7140             this.setHeight(1); // force clipping
7141             setTimeout(function(){
7142                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7143                 if(!animate){
7144                     this.setHeight(height);
7145                     this.unclip();
7146                     if(typeof onComplete == "function"){
7147                         onComplete();
7148                     }
7149                 }else{
7150                     this.setHeight(oldHeight); // restore original height
7151                     this.setHeight(height, animate, duration, function(){
7152                         this.unclip();
7153                         if(typeof onComplete == "function") onComplete();
7154                     }.createDelegate(this), easing);
7155                 }
7156             }.createDelegate(this), 0);
7157             return this;
7158         },
7159
7160         /**
7161          * Returns true if this element is an ancestor of the passed element
7162          * @param {HTMLElement/String} el The element to check
7163          * @return {Boolean} True if this element is an ancestor of el, else false
7164          */
7165         contains : function(el){
7166             if(!el){return false;}
7167             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7168         },
7169
7170         /**
7171          * Checks whether the element is currently visible using both visibility and display properties.
7172          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7173          * @return {Boolean} True if the element is currently visible, else false
7174          */
7175         isVisible : function(deep) {
7176             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7177             if(deep !== true || !vis){
7178                 return vis;
7179             }
7180             var p = this.dom.parentNode;
7181             while(p && p.tagName.toLowerCase() != "body"){
7182                 if(!Roo.fly(p, '_isVisible').isVisible()){
7183                     return false;
7184                 }
7185                 p = p.parentNode;
7186             }
7187             return true;
7188         },
7189
7190         /**
7191          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7192          * @param {String} selector The CSS selector
7193          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7194          * @return {CompositeElement/CompositeElementLite} The composite element
7195          */
7196         select : function(selector, unique){
7197             return El.select(selector, unique, this.dom);
7198         },
7199
7200         /**
7201          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7202          * @param {String} selector The CSS selector
7203          * @return {Array} An array of the matched nodes
7204          */
7205         query : function(selector, unique){
7206             return Roo.DomQuery.select(selector, this.dom);
7207         },
7208
7209         /**
7210          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7211          * @param {String} selector The CSS selector
7212          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7213          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7214          */
7215         child : function(selector, returnDom){
7216             var n = Roo.DomQuery.selectNode(selector, this.dom);
7217             return returnDom ? n : Roo.get(n);
7218         },
7219
7220         /**
7221          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7222          * @param {String} selector The CSS selector
7223          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7224          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7225          */
7226         down : function(selector, returnDom){
7227             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7228             return returnDom ? n : Roo.get(n);
7229         },
7230
7231         /**
7232          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7233          * @param {String} group The group the DD object is member of
7234          * @param {Object} config The DD config object
7235          * @param {Object} overrides An object containing methods to override/implement on the DD object
7236          * @return {Roo.dd.DD} The DD object
7237          */
7238         initDD : function(group, config, overrides){
7239             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7240             return Roo.apply(dd, overrides);
7241         },
7242
7243         /**
7244          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7245          * @param {String} group The group the DDProxy object is member of
7246          * @param {Object} config The DDProxy config object
7247          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7248          * @return {Roo.dd.DDProxy} The DDProxy object
7249          */
7250         initDDProxy : function(group, config, overrides){
7251             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7252             return Roo.apply(dd, overrides);
7253         },
7254
7255         /**
7256          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7257          * @param {String} group The group the DDTarget object is member of
7258          * @param {Object} config The DDTarget config object
7259          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7260          * @return {Roo.dd.DDTarget} The DDTarget object
7261          */
7262         initDDTarget : function(group, config, overrides){
7263             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7264             return Roo.apply(dd, overrides);
7265         },
7266
7267         /**
7268          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7269          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7270          * @param {Boolean} visible Whether the element is visible
7271          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7272          * @return {Roo.Element} this
7273          */
7274          setVisible : function(visible, animate){
7275             if(!animate || !A){
7276                 if(this.visibilityMode == El.DISPLAY){
7277                     this.setDisplayed(visible);
7278                 }else{
7279                     this.fixDisplay();
7280                     this.dom.style.visibility = visible ? "visible" : "hidden";
7281                 }
7282             }else{
7283                 // closure for composites
7284                 var dom = this.dom;
7285                 var visMode = this.visibilityMode;
7286                 if(visible){
7287                     this.setOpacity(.01);
7288                     this.setVisible(true);
7289                 }
7290                 this.anim({opacity: { to: (visible?1:0) }},
7291                       this.preanim(arguments, 1),
7292                       null, .35, 'easeIn', function(){
7293                          if(!visible){
7294                              if(visMode == El.DISPLAY){
7295                                  dom.style.display = "none";
7296                              }else{
7297                                  dom.style.visibility = "hidden";
7298                              }
7299                              Roo.get(dom).setOpacity(1);
7300                          }
7301                      });
7302             }
7303             return this;
7304         },
7305
7306         /**
7307          * Returns true if display is not "none"
7308          * @return {Boolean}
7309          */
7310         isDisplayed : function() {
7311             return this.getStyle("display") != "none";
7312         },
7313
7314         /**
7315          * Toggles the element's visibility or display, depending on visibility mode.
7316          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7317          * @return {Roo.Element} this
7318          */
7319         toggle : function(animate){
7320             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7321             return this;
7322         },
7323
7324         /**
7325          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7326          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7327          * @return {Roo.Element} this
7328          */
7329         setDisplayed : function(value) {
7330             if(typeof value == "boolean"){
7331                value = value ? this.originalDisplay : "none";
7332             }
7333             this.setStyle("display", value);
7334             return this;
7335         },
7336
7337         /**
7338          * Tries to focus the element. Any exceptions are caught and ignored.
7339          * @return {Roo.Element} this
7340          */
7341         focus : function() {
7342             try{
7343                 this.dom.focus();
7344             }catch(e){}
7345             return this;
7346         },
7347
7348         /**
7349          * Tries to blur the element. Any exceptions are caught and ignored.
7350          * @return {Roo.Element} this
7351          */
7352         blur : function() {
7353             try{
7354                 this.dom.blur();
7355             }catch(e){}
7356             return this;
7357         },
7358
7359         /**
7360          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7361          * @param {String/Array} className The CSS class to add, or an array of classes
7362          * @return {Roo.Element} this
7363          */
7364         addClass : function(className){
7365             if(className instanceof Array){
7366                 for(var i = 0, len = className.length; i < len; i++) {
7367                     this.addClass(className[i]);
7368                 }
7369             }else{
7370                 if(className && !this.hasClass(className)){
7371                     this.dom.className = this.dom.className + " " + className;
7372                 }
7373             }
7374             return this;
7375         },
7376
7377         /**
7378          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7379          * @param {String/Array} className The CSS class to add, or an array of classes
7380          * @return {Roo.Element} this
7381          */
7382         radioClass : function(className){
7383             var siblings = this.dom.parentNode.childNodes;
7384             for(var i = 0; i < siblings.length; i++) {
7385                 var s = siblings[i];
7386                 if(s.nodeType == 1){
7387                     Roo.get(s).removeClass(className);
7388                 }
7389             }
7390             this.addClass(className);
7391             return this;
7392         },
7393
7394         /**
7395          * Removes one or more CSS classes from the element.
7396          * @param {String/Array} className The CSS class to remove, or an array of classes
7397          * @return {Roo.Element} this
7398          */
7399         removeClass : function(className){
7400             if(!className || !this.dom.className){
7401                 return this;
7402             }
7403             if(className instanceof Array){
7404                 for(var i = 0, len = className.length; i < len; i++) {
7405                     this.removeClass(className[i]);
7406                 }
7407             }else{
7408                 if(this.hasClass(className)){
7409                     var re = this.classReCache[className];
7410                     if (!re) {
7411                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7412                        this.classReCache[className] = re;
7413                     }
7414                     this.dom.className =
7415                         this.dom.className.replace(re, " ");
7416                 }
7417             }
7418             return this;
7419         },
7420
7421         // private
7422         classReCache: {},
7423
7424         /**
7425          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7426          * @param {String} className The CSS class to toggle
7427          * @return {Roo.Element} this
7428          */
7429         toggleClass : function(className){
7430             if(this.hasClass(className)){
7431                 this.removeClass(className);
7432             }else{
7433                 this.addClass(className);
7434             }
7435             return this;
7436         },
7437
7438         /**
7439          * Checks if the specified CSS class exists on this element's DOM node.
7440          * @param {String} className The CSS class to check for
7441          * @return {Boolean} True if the class exists, else false
7442          */
7443         hasClass : function(className){
7444             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7445         },
7446
7447         /**
7448          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7449          * @param {String} oldClassName The CSS class to replace
7450          * @param {String} newClassName The replacement CSS class
7451          * @return {Roo.Element} this
7452          */
7453         replaceClass : function(oldClassName, newClassName){
7454             this.removeClass(oldClassName);
7455             this.addClass(newClassName);
7456             return this;
7457         },
7458
7459         /**
7460          * Returns an object with properties matching the styles requested.
7461          * For example, el.getStyles('color', 'font-size', 'width') might return
7462          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7463          * @param {String} style1 A style name
7464          * @param {String} style2 A style name
7465          * @param {String} etc.
7466          * @return {Object} The style object
7467          */
7468         getStyles : function(){
7469             var a = arguments, len = a.length, r = {};
7470             for(var i = 0; i < len; i++){
7471                 r[a[i]] = this.getStyle(a[i]);
7472             }
7473             return r;
7474         },
7475
7476         /**
7477          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7478          * @param {String} property The style property whose value is returned.
7479          * @return {String} The current value of the style property for this element.
7480          */
7481         getStyle : function(){
7482             return view && view.getComputedStyle ?
7483                 function(prop){
7484                     var el = this.dom, v, cs, camel;
7485                     if(prop == 'float'){
7486                         prop = "cssFloat";
7487                     }
7488                     if(el.style && (v = el.style[prop])){
7489                         return v;
7490                     }
7491                     if(cs = view.getComputedStyle(el, "")){
7492                         if(!(camel = propCache[prop])){
7493                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7494                         }
7495                         return cs[camel];
7496                     }
7497                     return null;
7498                 } :
7499                 function(prop){
7500                     var el = this.dom, v, cs, camel;
7501                     if(prop == 'opacity'){
7502                         if(typeof el.style.filter == 'string'){
7503                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7504                             if(m){
7505                                 var fv = parseFloat(m[1]);
7506                                 if(!isNaN(fv)){
7507                                     return fv ? fv / 100 : 0;
7508                                 }
7509                             }
7510                         }
7511                         return 1;
7512                     }else if(prop == 'float'){
7513                         prop = "styleFloat";
7514                     }
7515                     if(!(camel = propCache[prop])){
7516                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7517                     }
7518                     if(v = el.style[camel]){
7519                         return v;
7520                     }
7521                     if(cs = el.currentStyle){
7522                         return cs[camel];
7523                     }
7524                     return null;
7525                 };
7526         }(),
7527
7528         /**
7529          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7530          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7531          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7532          * @return {Roo.Element} this
7533          */
7534         setStyle : function(prop, value){
7535             if(typeof prop == "string"){
7536                 
7537                 if (prop == 'float') {
7538                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7539                     return this;
7540                 }
7541                 
7542                 var camel;
7543                 if(!(camel = propCache[prop])){
7544                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7545                 }
7546                 
7547                 if(camel == 'opacity') {
7548                     this.setOpacity(value);
7549                 }else{
7550                     this.dom.style[camel] = value;
7551                 }
7552             }else{
7553                 for(var style in prop){
7554                     if(typeof prop[style] != "function"){
7555                        this.setStyle(style, prop[style]);
7556                     }
7557                 }
7558             }
7559             return this;
7560         },
7561
7562         /**
7563          * More flexible version of {@link #setStyle} for setting style properties.
7564          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7565          * a function which returns such a specification.
7566          * @return {Roo.Element} this
7567          */
7568         applyStyles : function(style){
7569             Roo.DomHelper.applyStyles(this.dom, style);
7570             return this;
7571         },
7572
7573         /**
7574           * Gets the current X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7575           * @return {Number} The X position of the element
7576           */
7577         getX : function(){
7578             return D.getX(this.dom);
7579         },
7580
7581         /**
7582           * Gets the current Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7583           * @return {Number} The Y position of the element
7584           */
7585         getY : function(){
7586             return D.getY(this.dom);
7587         },
7588
7589         /**
7590           * Gets the current position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7591           * @return {Array} The XY position of the element
7592           */
7593         getXY : function(){
7594             return D.getXY(this.dom);
7595         },
7596
7597         /**
7598          * Sets the X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7599          * @param {Number} The X position of the element
7600          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7601          * @return {Roo.Element} this
7602          */
7603         setX : function(x, animate){
7604             if(!animate || !A){
7605                 D.setX(this.dom, x);
7606             }else{
7607                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7608             }
7609             return this;
7610         },
7611
7612         /**
7613          * Sets the Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7614          * @param {Number} The Y position of the element
7615          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7616          * @return {Roo.Element} this
7617          */
7618         setY : function(y, animate){
7619             if(!animate || !A){
7620                 D.setY(this.dom, y);
7621             }else{
7622                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7623             }
7624             return this;
7625         },
7626
7627         /**
7628          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7629          * @param {String} left The left CSS property value
7630          * @return {Roo.Element} this
7631          */
7632         setLeft : function(left){
7633             this.setStyle("left", this.addUnits(left));
7634             return this;
7635         },
7636
7637         /**
7638          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7639          * @param {String} top The top CSS property value
7640          * @return {Roo.Element} this
7641          */
7642         setTop : function(top){
7643             this.setStyle("top", this.addUnits(top));
7644             return this;
7645         },
7646
7647         /**
7648          * Sets the element's CSS right style.
7649          * @param {String} right The right CSS property value
7650          * @return {Roo.Element} this
7651          */
7652         setRight : function(right){
7653             this.setStyle("right", this.addUnits(right));
7654             return this;
7655         },
7656
7657         /**
7658          * Sets the element's CSS bottom style.
7659          * @param {String} bottom The bottom CSS property value
7660          * @return {Roo.Element} this
7661          */
7662         setBottom : function(bottom){
7663             this.setStyle("bottom", this.addUnits(bottom));
7664             return this;
7665         },
7666
7667         /**
7668          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7669          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7670          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7671          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7672          * @return {Roo.Element} this
7673          */
7674         setXY : function(pos, animate){
7675             if(!animate || !A){
7676                 D.setXY(this.dom, pos);
7677             }else{
7678                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7679             }
7680             return this;
7681         },
7682
7683         /**
7684          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7685          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7686          * @param {Number} x X value for new position (coordinates are page-based)
7687          * @param {Number} y Y value for new position (coordinates are page-based)
7688          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7689          * @return {Roo.Element} this
7690          */
7691         setLocation : function(x, y, animate){
7692             this.setXY([x, y], this.preanim(arguments, 2));
7693             return this;
7694         },
7695
7696         /**
7697          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7698          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7699          * @param {Number} x X value for new position (coordinates are page-based)
7700          * @param {Number} y Y value for new position (coordinates are page-based)
7701          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7702          * @return {Roo.Element} this
7703          */
7704         moveTo : function(x, y, animate){
7705             this.setXY([x, y], this.preanim(arguments, 2));
7706             return this;
7707         },
7708
7709         /**
7710          * Returns the region of the given element.
7711          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7712          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7713          */
7714         getRegion : function(){
7715             return D.getRegion(this.dom);
7716         },
7717
7718         /**
7719          * Returns the offset height of the element
7720          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7721          * @return {Number} The element's height
7722          */
7723         getHeight : function(contentHeight){
7724             var h = this.dom.offsetHeight || 0;
7725             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7726         },
7727
7728         /**
7729          * Returns the offset width of the element
7730          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7731          * @return {Number} The element's width
7732          */
7733         getWidth : function(contentWidth){
7734             var w = this.dom.offsetWidth || 0;
7735             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7736         },
7737
7738         /**
7739          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7740          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7741          * if a height has not been set using CSS.
7742          * @return {Number}
7743          */
7744         getComputedHeight : function(){
7745             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7746             if(!h){
7747                 h = parseInt(this.getStyle('height'), 10) || 0;
7748                 if(!this.isBorderBox()){
7749                     h += this.getFrameWidth('tb');
7750                 }
7751             }
7752             return h;
7753         },
7754
7755         /**
7756          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7757          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7758          * if a width has not been set using CSS.
7759          * @return {Number}
7760          */
7761         getComputedWidth : function(){
7762             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7763             if(!w){
7764                 w = parseInt(this.getStyle('width'), 10) || 0;
7765                 if(!this.isBorderBox()){
7766                     w += this.getFrameWidth('lr');
7767                 }
7768             }
7769             return w;
7770         },
7771
7772         /**
7773          * Returns the size of the element.
7774          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7775          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7776          */
7777         getSize : function(contentSize){
7778             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7779         },
7780
7781         /**
7782          * Returns the width and height of the viewport.
7783          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7784          */
7785         getViewSize : function(){
7786             var d = this.dom, doc = document, aw = 0, ah = 0;
7787             if(d == doc || d == doc.body){
7788                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7789             }else{
7790                 return {
7791                     width : d.clientWidth,
7792                     height: d.clientHeight
7793                 };
7794             }
7795         },
7796
7797         /**
7798          * Returns the value of the "value" attribute
7799          * @param {Boolean} asNumber true to parse the value as a number
7800          * @return {String/Number}
7801          */
7802         getValue : function(asNumber){
7803             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7804         },
7805
7806         // private
7807         adjustWidth : function(width){
7808             if(typeof width == "number"){
7809                 if(this.autoBoxAdjust && !this.isBorderBox()){
7810                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7811                 }
7812                 if(width < 0){
7813                     width = 0;
7814                 }
7815             }
7816             return width;
7817         },
7818
7819         // private
7820         adjustHeight : function(height){
7821             if(typeof height == "number"){
7822                if(this.autoBoxAdjust && !this.isBorderBox()){
7823                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7824                }
7825                if(height < 0){
7826                    height = 0;
7827                }
7828             }
7829             return height;
7830         },
7831
7832         /**
7833          * Set the width of the element
7834          * @param {Number} width The new width
7835          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7836          * @return {Roo.Element} this
7837          */
7838         setWidth : function(width, animate){
7839             width = this.adjustWidth(width);
7840             if(!animate || !A){
7841                 this.dom.style.width = this.addUnits(width);
7842             }else{
7843                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7844             }
7845             return this;
7846         },
7847
7848         /**
7849          * Set the height of the element
7850          * @param {Number} height The new height
7851          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7852          * @return {Roo.Element} this
7853          */
7854          setHeight : function(height, animate){
7855             height = this.adjustHeight(height);
7856             if(!animate || !A){
7857                 this.dom.style.height = this.addUnits(height);
7858             }else{
7859                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7860             }
7861             return this;
7862         },
7863
7864         /**
7865          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7866          * @param {Number} width The new width
7867          * @param {Number} height The new height
7868          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7869          * @return {Roo.Element} this
7870          */
7871          setSize : function(width, height, animate){
7872             if(typeof width == "object"){ // in case of object from getSize()
7873                 height = width.height; width = width.width;
7874             }
7875             width = this.adjustWidth(width); height = this.adjustHeight(height);
7876             if(!animate || !A){
7877                 this.dom.style.width = this.addUnits(width);
7878                 this.dom.style.height = this.addUnits(height);
7879             }else{
7880                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7881             }
7882             return this;
7883         },
7884
7885         /**
7886          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7887          * @param {Number} x X value for new position (coordinates are page-based)
7888          * @param {Number} y Y value for new position (coordinates are page-based)
7889          * @param {Number} width The new width
7890          * @param {Number} height The new height
7891          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7892          * @return {Roo.Element} this
7893          */
7894         setBounds : function(x, y, width, height, animate){
7895             if(!animate || !A){
7896                 this.setSize(width, height);
7897                 this.setLocation(x, y);
7898             }else{
7899                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7900                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7901                               this.preanim(arguments, 4), 'motion');
7902             }
7903             return this;
7904         },
7905
7906         /**
7907          * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7908          * @param {Roo.lib.Region} region The region to fill
7909          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910          * @return {Roo.Element} this
7911          */
7912         setRegion : function(region, animate){
7913             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7914             return this;
7915         },
7916
7917         /**
7918          * Appends an event handler
7919          *
7920          * @param {String}   eventName     The type of event to append
7921          * @param {Function} fn        The method the event invokes
7922          * @param {Object} scope       (optional) The scope (this object) of the fn
7923          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7924          */
7925         addListener : function(eventName, fn, scope, options){
7926             if (this.dom) {
7927                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7928             }
7929         },
7930
7931         /**
7932          * Removes an event handler from this element
7933          * @param {String} eventName the type of event to remove
7934          * @param {Function} fn the method the event invokes
7935          * @return {Roo.Element} this
7936          */
7937         removeListener : function(eventName, fn){
7938             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7939             return this;
7940         },
7941
7942         /**
7943          * Removes all previous added listeners from this element
7944          * @return {Roo.Element} this
7945          */
7946         removeAllListeners : function(){
7947             E.purgeElement(this.dom);
7948             return this;
7949         },
7950
7951         relayEvent : function(eventName, observable){
7952             this.on(eventName, function(e){
7953                 observable.fireEvent(eventName, e);
7954             });
7955         },
7956
7957         /**
7958          * Set the opacity of the element
7959          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7960          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961          * @return {Roo.Element} this
7962          */
7963          setOpacity : function(opacity, animate){
7964             if(!animate || !A){
7965                 var s = this.dom.style;
7966                 if(Roo.isIE){
7967                     s.zoom = 1;
7968                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7969                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7970                 }else{
7971                     s.opacity = opacity;
7972                 }
7973             }else{
7974                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7975             }
7976             return this;
7977         },
7978
7979         /**
7980          * Gets the left X coordinate
7981          * @param {Boolean} local True to get the local css position instead of page coordinate
7982          * @return {Number}
7983          */
7984         getLeft : function(local){
7985             if(!local){
7986                 return this.getX();
7987             }else{
7988                 return parseInt(this.getStyle("left"), 10) || 0;
7989             }
7990         },
7991
7992         /**
7993          * Gets the right X coordinate of the element (element X position + element width)
7994          * @param {Boolean} local True to get the local css position instead of page coordinate
7995          * @return {Number}
7996          */
7997         getRight : function(local){
7998             if(!local){
7999                 return this.getX() + this.getWidth();
8000             }else{
8001                 return (this.getLeft(true) + this.getWidth()) || 0;
8002             }
8003         },
8004
8005         /**
8006          * Gets the top Y coordinate
8007          * @param {Boolean} local True to get the local css position instead of page coordinate
8008          * @return {Number}
8009          */
8010         getTop : function(local) {
8011             if(!local){
8012                 return this.getY();
8013             }else{
8014                 return parseInt(this.getStyle("top"), 10) || 0;
8015             }
8016         },
8017
8018         /**
8019          * Gets the bottom Y coordinate of the element (element Y position + element height)
8020          * @param {Boolean} local True to get the local css position instead of page coordinate
8021          * @return {Number}
8022          */
8023         getBottom : function(local){
8024             if(!local){
8025                 return this.getY() + this.getHeight();
8026             }else{
8027                 return (this.getTop(true) + this.getHeight()) || 0;
8028             }
8029         },
8030
8031         /**
8032         * Initializes positioning on this element. If a desired position is not passed, it will make the
8033         * the element positioned relative IF it is not already positioned.
8034         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8035         * @param {Number} zIndex (optional) The zIndex to apply
8036         * @param {Number} x (optional) Set the page X position
8037         * @param {Number} y (optional) Set the page Y position
8038         */
8039         position : function(pos, zIndex, x, y){
8040             if(!pos){
8041                if(this.getStyle('position') == 'static'){
8042                    this.setStyle('position', 'relative');
8043                }
8044             }else{
8045                 this.setStyle("position", pos);
8046             }
8047             if(zIndex){
8048                 this.setStyle("z-index", zIndex);
8049             }
8050             if(x !== undefined && y !== undefined){
8051                 this.setXY([x, y]);
8052             }else if(x !== undefined){
8053                 this.setX(x);
8054             }else if(y !== undefined){
8055                 this.setY(y);
8056             }
8057         },
8058
8059         /**
8060         * Clear positioning back to the default when the document was loaded
8061         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8062         * @return {Roo.Element} this
8063          */
8064         clearPositioning : function(value){
8065             value = value ||'';
8066             this.setStyle({
8067                 "left": value,
8068                 "right": value,
8069                 "top": value,
8070                 "bottom": value,
8071                 "z-index": "",
8072                 "position" : "static"
8073             });
8074             return this;
8075         },
8076
8077         /**
8078         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8079         * snapshot before performing an update and then restoring the element.
8080         * @return {Object}
8081         */
8082         getPositioning : function(){
8083             var l = this.getStyle("left");
8084             var t = this.getStyle("top");
8085             return {
8086                 "position" : this.getStyle("position"),
8087                 "left" : l,
8088                 "right" : l ? "" : this.getStyle("right"),
8089                 "top" : t,
8090                 "bottom" : t ? "" : this.getStyle("bottom"),
8091                 "z-index" : this.getStyle("z-index")
8092             };
8093         },
8094
8095         /**
8096          * Gets the width of the border(s) for the specified side(s)
8097          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8098          * passing lr would get the border (l)eft width + the border (r)ight width.
8099          * @return {Number} The width of the sides passed added together
8100          */
8101         getBorderWidth : function(side){
8102             return this.addStyles(side, El.borders);
8103         },
8104
8105         /**
8106          * Gets the width of the padding(s) for the specified side(s)
8107          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8108          * passing lr would get the padding (l)eft + the padding (r)ight.
8109          * @return {Number} The padding of the sides passed added together
8110          */
8111         getPadding : function(side){
8112             return this.addStyles(side, El.paddings);
8113         },
8114
8115         /**
8116         * Set positioning with an object returned by getPositioning().
8117         * @param {Object} posCfg
8118         * @return {Roo.Element} this
8119          */
8120         setPositioning : function(pc){
8121             this.applyStyles(pc);
8122             if(pc.right == "auto"){
8123                 this.dom.style.right = "";
8124             }
8125             if(pc.bottom == "auto"){
8126                 this.dom.style.bottom = "";
8127             }
8128             return this;
8129         },
8130
8131         // private
8132         fixDisplay : function(){
8133             if(this.getStyle("display") == "none"){
8134                 this.setStyle("visibility", "hidden");
8135                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8136                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8137                     this.setStyle("display", "block");
8138                 }
8139             }
8140         },
8141
8142         /**
8143          * Quick set left and top adding default units
8144          * @param {String} left The left CSS property value
8145          * @param {String} top The top CSS property value
8146          * @return {Roo.Element} this
8147          */
8148          setLeftTop : function(left, top){
8149             this.dom.style.left = this.addUnits(left);
8150             this.dom.style.top = this.addUnits(top);
8151             return this;
8152         },
8153
8154         /**
8155          * Move this element relative to its current position.
8156          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8157          * @param {Number} distance How far to move the element in pixels
8158          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8159          * @return {Roo.Element} this
8160          */
8161          move : function(direction, distance, animate){
8162             var xy = this.getXY();
8163             direction = direction.toLowerCase();
8164             switch(direction){
8165                 case "l":
8166                 case "left":
8167                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8168                     break;
8169                case "r":
8170                case "right":
8171                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8172                     break;
8173                case "t":
8174                case "top":
8175                case "up":
8176                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8177                     break;
8178                case "b":
8179                case "bottom":
8180                case "down":
8181                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8182                     break;
8183             }
8184             return this;
8185         },
8186
8187         /**
8188          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8189          * @return {Roo.Element} this
8190          */
8191         clip : function(){
8192             if(!this.isClipped){
8193                this.isClipped = true;
8194                this.originalClip = {
8195                    "o": this.getStyle("overflow"),
8196                    "x": this.getStyle("overflow-x"),
8197                    "y": this.getStyle("overflow-y")
8198                };
8199                this.setStyle("overflow", "hidden");
8200                this.setStyle("overflow-x", "hidden");
8201                this.setStyle("overflow-y", "hidden");
8202             }
8203             return this;
8204         },
8205
8206         /**
8207          *  Return clipping (overflow) to original clipping before clip() was called
8208          * @return {Roo.Element} this
8209          */
8210         unclip : function(){
8211             if(this.isClipped){
8212                 this.isClipped = false;
8213                 var o = this.originalClip;
8214                 if(o.o){this.setStyle("overflow", o.o);}
8215                 if(o.x){this.setStyle("overflow-x", o.x);}
8216                 if(o.y){this.setStyle("overflow-y", o.y);}
8217             }
8218             return this;
8219         },
8220
8221
8222         /**
8223          * Gets the x,y coordinates specified by the anchor position on the element.
8224          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8225          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8226          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8227          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8228          * @return {Array} [x, y] An array containing the element's x and y coordinates
8229          */
8230         getAnchorXY : function(anchor, local, s){
8231             //Passing a different size is useful for pre-calculating anchors,
8232             //especially for anchored animations that change the el size.
8233
8234             var w, h, vp = false;
8235             if(!s){
8236                 var d = this.dom;
8237                 if(d == document.body || d == document){
8238                     vp = true;
8239                     w = D.getViewWidth(); h = D.getViewHeight();
8240                 }else{
8241                     w = this.getWidth(); h = this.getHeight();
8242                 }
8243             }else{
8244                 w = s.width;  h = s.height;
8245             }
8246             var x = 0, y = 0, r = Math.round;
8247             switch((anchor || "tl").toLowerCase()){
8248                 case "c":
8249                     x = r(w*.5);
8250                     y = r(h*.5);
8251                 break;
8252                 case "t":
8253                     x = r(w*.5);
8254                     y = 0;
8255                 break;
8256                 case "l":
8257                     x = 0;
8258                     y = r(h*.5);
8259                 break;
8260                 case "r":
8261                     x = w;
8262                     y = r(h*.5);
8263                 break;
8264                 case "b":
8265                     x = r(w*.5);
8266                     y = h;
8267                 break;
8268                 case "tl":
8269                     x = 0;
8270                     y = 0;
8271                 break;
8272                 case "bl":
8273                     x = 0;
8274                     y = h;
8275                 break;
8276                 case "br":
8277                     x = w;
8278                     y = h;
8279                 break;
8280                 case "tr":
8281                     x = w;
8282                     y = 0;
8283                 break;
8284             }
8285             if(local === true){
8286                 return [x, y];
8287             }
8288             if(vp){
8289                 var sc = this.getScroll();
8290                 return [x + sc.left, y + sc.top];
8291             }
8292             //Add the element's offset xy
8293             var o = this.getXY();
8294             return [x+o[0], y+o[1]];
8295         },
8296
8297         /**
8298          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8299          * supported position values.
8300          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8301          * @param {String} position The position to align to.
8302          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8303          * @return {Array} [x, y]
8304          */
8305         getAlignToXY : function(el, p, o){
8306             el = Roo.get(el);
8307             var d = this.dom;
8308             if(!el.dom){
8309                 throw "Element.alignTo with an element that doesn't exist";
8310             }
8311             var c = false; //constrain to viewport
8312             var p1 = "", p2 = "";
8313             o = o || [0,0];
8314
8315             if(!p){
8316                 p = "tl-bl";
8317             }else if(p == "?"){
8318                 p = "tl-bl?";
8319             }else if(p.indexOf("-") == -1){
8320                 p = "tl-" + p;
8321             }
8322             p = p.toLowerCase();
8323             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8324             if(!m){
8325                throw "Element.alignTo with an invalid alignment " + p;
8326             }
8327             p1 = m[1]; p2 = m[2]; c = !!m[3];
8328
8329             //Subtract the aligned el's internal xy from the target's offset xy
8330             //plus custom offset to get the aligned el's new offset xy
8331             var a1 = this.getAnchorXY(p1, true);
8332             var a2 = el.getAnchorXY(p2, false);
8333             var x = a2[0] - a1[0] + o[0];
8334             var y = a2[1] - a1[1] + o[1];
8335             if(c){
8336                 //constrain the aligned el to viewport if necessary
8337                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8338                 // 5px of margin for ie
8339                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8340
8341                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8342                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8343                 //otherwise swap the aligned el to the opposite border of the target.
8344                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8345                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8346                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8347                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8348
8349                var doc = document;
8350                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8351                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8352
8353                if((x+w) > dw + scrollX){
8354                     x = swapX ? r.left-w : dw+scrollX-w;
8355                 }
8356                if(x < scrollX){
8357                    x = swapX ? r.right : scrollX;
8358                }
8359                if((y+h) > dh + scrollY){
8360                     y = swapY ? r.top-h : dh+scrollY-h;
8361                 }
8362                if (y < scrollY){
8363                    y = swapY ? r.bottom : scrollY;
8364                }
8365             }
8366             return [x,y];
8367         },
8368
8369         // private
8370         getConstrainToXY : function(){
8371             var os = {top:0, left:0, bottom:0, right: 0};
8372
8373             return function(el, local, offsets, proposedXY){
8374                 el = Roo.get(el);
8375                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8376
8377                 var vw, vh, vx = 0, vy = 0;
8378                 if(el.dom == document.body || el.dom == document){
8379                     vw = Roo.lib.Dom.getViewWidth();
8380                     vh = Roo.lib.Dom.getViewHeight();
8381                 }else{
8382                     vw = el.dom.clientWidth;
8383                     vh = el.dom.clientHeight;
8384                     if(!local){
8385                         var vxy = el.getXY();
8386                         vx = vxy[0];
8387                         vy = vxy[1];
8388                     }
8389                 }
8390
8391                 var s = el.getScroll();
8392
8393                 vx += offsets.left + s.left;
8394                 vy += offsets.top + s.top;
8395
8396                 vw -= offsets.right;
8397                 vh -= offsets.bottom;
8398
8399                 var vr = vx+vw;
8400                 var vb = vy+vh;
8401
8402                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8403                 var x = xy[0], y = xy[1];
8404                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8405
8406                 // only move it if it needs it
8407                 var moved = false;
8408
8409                 // first validate right/bottom
8410                 if((x + w) > vr){
8411                     x = vr - w;
8412                     moved = true;
8413                 }
8414                 if((y + h) > vb){
8415                     y = vb - h;
8416                     moved = true;
8417                 }
8418                 // then make sure top/left isn't negative
8419                 if(x < vx){
8420                     x = vx;
8421                     moved = true;
8422                 }
8423                 if(y < vy){
8424                     y = vy;
8425                     moved = true;
8426                 }
8427                 return moved ? [x, y] : false;
8428             };
8429         }(),
8430
8431         // private
8432         adjustForConstraints : function(xy, parent, offsets){
8433             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8434         },
8435
8436         /**
8437          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8438          * document it aligns it to the viewport.
8439          * The position parameter is optional, and can be specified in any one of the following formats:
8440          * <ul>
8441          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8442          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8443          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8444          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8445          *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8446          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8447          * </ul>
8448          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8449          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8450          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8451          * that specified in order to enforce the viewport constraints.
8452          * Following are all of the supported anchor positions:
8453     <pre>
8454     Value  Description
8455     -----  -----------------------------
8456     tl     The top left corner (default)
8457     t      The center of the top edge
8458     tr     The top right corner
8459     l      The center of the left edge
8460     c      In the center of the element
8461     r      The center of the right edge
8462     bl     The bottom left corner
8463     b      The center of the bottom edge
8464     br     The bottom right corner
8465     </pre>
8466     Example Usage:
8467     <pre><code>
8468     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8469     el.alignTo("other-el");
8470
8471     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8472     el.alignTo("other-el", "tr?");
8473
8474     // align the bottom right corner of el with the center left edge of other-el
8475     el.alignTo("other-el", "br-l?");
8476
8477     // align the center of el with the bottom left corner of other-el and
8478     // adjust the x position by -6 pixels (and the y position by 0)
8479     el.alignTo("other-el", "c-bl", [-6, 0]);
8480     </code></pre>
8481          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8482          * @param {String} position The position to align to.
8483          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8484          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8485          * @return {Roo.Element} this
8486          */
8487         alignTo : function(element, position, offsets, animate){
8488             var xy = this.getAlignToXY(element, position, offsets);
8489             this.setXY(xy, this.preanim(arguments, 3));
8490             return this;
8491         },
8492
8493         /**
8494          * Anchors an element to another element and realigns it when the window is resized.
8495          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8496          * @param {String} position The position to align to.
8497          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8498          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8499          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8500          * is a number, it is used as the buffer delay (defaults to 50ms).
8501          * @param {Function} callback The function to call after the animation finishes
8502          * @return {Roo.Element} this
8503          */
8504         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8505             var action = function(){
8506                 this.alignTo(el, alignment, offsets, animate);
8507                 Roo.callback(callback, this);
8508             };
8509             Roo.EventManager.onWindowResize(action, this);
8510             var tm = typeof monitorScroll;
8511             if(tm != 'undefined'){
8512                 Roo.EventManager.on(window, 'scroll', action, this,
8513                     {buffer: tm == 'number' ? monitorScroll : 50});
8514             }
8515             action.call(this); // align immediately
8516             return this;
8517         },
8518         /**
8519          * Clears any opacity settings from this element. Required in some cases for IE.
8520          * @return {Roo.Element} this
8521          */
8522         clearOpacity : function(){
8523             if (window.ActiveXObject) {
8524                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8525                     this.dom.style.filter = "";
8526                 }
8527             } else {
8528                 this.dom.style.opacity = "";
8529                 this.dom.style["-moz-opacity"] = "";
8530                 this.dom.style["-khtml-opacity"] = "";
8531             }
8532             return this;
8533         },
8534
8535         /**
8536          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8537          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8538          * @return {Roo.Element} this
8539          */
8540         hide : function(animate){
8541             this.setVisible(false, this.preanim(arguments, 0));
8542             return this;
8543         },
8544
8545         /**
8546         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8547         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8548          * @return {Roo.Element} this
8549          */
8550         show : function(animate){
8551             this.setVisible(true, this.preanim(arguments, 0));
8552             return this;
8553         },
8554
8555         /**
8556          * @private Test if size has a unit, otherwise appends the default
8557          */
8558         addUnits : function(size){
8559             return Roo.Element.addUnits(size, this.defaultUnit);
8560         },
8561
8562         /**
8563          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8564          * @return {Roo.Element} this
8565          */
8566         beginMeasure : function(){
8567             var el = this.dom;
8568             if(el.offsetWidth || el.offsetHeight){
8569                 return this; // offsets work already
8570             }
8571             var changed = [];
8572             var p = this.dom, b = document.body; // start with this element
8573             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8574                 var pe = Roo.get(p);
8575                 if(pe.getStyle('display') == 'none'){
8576                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8577                     p.style.visibility = "hidden";
8578                     p.style.display = "block";
8579                 }
8580                 p = p.parentNode;
8581             }
8582             this._measureChanged = changed;
8583             return this;
8584
8585         },
8586
8587         /**
8588          * Restores displays to before beginMeasure was called
8589          * @return {Roo.Element} this
8590          */
8591         endMeasure : function(){
8592             var changed = this._measureChanged;
8593             if(changed){
8594                 for(var i = 0, len = changed.length; i < len; i++) {
8595                     var r = changed[i];
8596                     r.el.style.visibility = r.visibility;
8597                     r.el.style.display = "none";
8598                 }
8599                 this._measureChanged = null;
8600             }
8601             return this;
8602         },
8603
8604         /**
8605         * Update the innerHTML of this element, optionally searching for and processing scripts
8606         * @param {String} html The new HTML
8607         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8608         * @param {Function} callback For async script loading you can be noticed when the update completes
8609         * @return {Roo.Element} this
8610          */
8611         update : function(html, loadScripts, callback){
8612             if(typeof html == "undefined"){
8613                 html = "";
8614             }
8615             if(loadScripts !== true){
8616                 this.dom.innerHTML = html;
8617                 if(typeof callback == "function"){
8618                     callback();
8619                 }
8620                 return this;
8621             }
8622             var id = Roo.id();
8623             var dom = this.dom;
8624
8625             html += '<span id="' + id + '"></span>';
8626
8627             E.onAvailable(id, function(){
8628                 var hd = document.getElementsByTagName("head")[0];
8629                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8630                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8631                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8632
8633                 var match;
8634                 while(match = re.exec(html)){
8635                     var attrs = match[1];
8636                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8637                     if(srcMatch && srcMatch[2]){
8638                        var s = document.createElement("script");
8639                        s.src = srcMatch[2];
8640                        var typeMatch = attrs.match(typeRe);
8641                        if(typeMatch && typeMatch[2]){
8642                            s.type = typeMatch[2];
8643                        }
8644                        hd.appendChild(s);
8645                     }else if(match[2] && match[2].length > 0){
8646                         if(window.execScript) {
8647                            window.execScript(match[2]);
8648                         } else {
8649                             /**
8650                              * eval:var:id
8651                              * eval:var:dom
8652                              * eval:var:html
8653                              * 
8654                              */
8655                            window.eval(match[2]);
8656                         }
8657                     }
8658                 }
8659                 var el = document.getElementById(id);
8660                 if(el){el.parentNode.removeChild(el);}
8661                 if(typeof callback == "function"){
8662                     callback();
8663                 }
8664             });
8665             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8666             return this;
8667         },
8668
8669         /**
8670          * Direct access to the UpdateManager update() method (takes the same parameters).
8671          * @param {String/Function} url The url for this request or a function to call to get the url
8672          * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
8673          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8674          * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8675          * @return {Roo.Element} this
8676          */
8677         load : function(){
8678             var um = this.getUpdateManager();
8679             um.update.apply(um, arguments);
8680             return this;
8681         },
8682
8683         /**
8684         * Gets this element's UpdateManager
8685         * @return {Roo.UpdateManager} The UpdateManager
8686         */
8687         getUpdateManager : function(){
8688             if(!this.updateManager){
8689                 this.updateManager = new Roo.UpdateManager(this);
8690             }
8691             return this.updateManager;
8692         },
8693
8694         /**
8695          * Disables text selection for this element (normalized across browsers)
8696          * @return {Roo.Element} this
8697          */
8698         unselectable : function(){
8699             this.dom.unselectable = "on";
8700             this.swallowEvent("selectstart", true);
8701             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8702             this.addClass("x-unselectable");
8703             return this;
8704         },
8705
8706         /**
8707         * Calculates the x, y to center this element on the screen
8708         * @return {Array} The x, y values [x, y]
8709         */
8710         getCenterXY : function(){
8711             return this.getAlignToXY(document, 'c-c');
8712         },
8713
8714         /**
8715         * Centers the Element in either the viewport, or another Element.
8716         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8717         */
8718         center : function(centerIn){
8719             this.alignTo(centerIn || document, 'c-c');
8720             return this;
8721         },
8722
8723         /**
8724          * Tests various css rules/browsers to determine if this element uses a border box
8725          * @return {Boolean}
8726          */
8727         isBorderBox : function(){
8728             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8729         },
8730
8731         /**
8732          * Return a box {x, y, width, height} that can be used to set another elements
8733          * size/location to match this element.
8734          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8735          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8736          * @return {Object} box An object in the format {x, y, width, height}
8737          */
8738         getBox : function(contentBox, local){
8739             var xy;
8740             if(!local){
8741                 xy = this.getXY();
8742             }else{
8743                 var left = parseInt(this.getStyle("left"), 10) || 0;
8744                 var top = parseInt(this.getStyle("top"), 10) || 0;
8745                 xy = [left, top];
8746             }
8747             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8748             if(!contentBox){
8749                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8750             }else{
8751                 var l = this.getBorderWidth("l")+this.getPadding("l");
8752                 var r = this.getBorderWidth("r")+this.getPadding("r");
8753                 var t = this.getBorderWidth("t")+this.getPadding("t");
8754                 var b = this.getBorderWidth("b")+this.getPadding("b");
8755                 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8756             }
8757             bx.right = bx.x + bx.width;
8758             bx.bottom = bx.y + bx.height;
8759             return bx;
8760         },
8761
8762         /**
8763          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8764          for more information about the sides.
8765          * @param {String} sides
8766          * @return {Number}
8767          */
8768         getFrameWidth : function(sides, onlyContentBox){
8769             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8770         },
8771
8772         /**
8773          * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8774          * @param {Object} box The box to fill {x, y, width, height}
8775          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8776          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8777          * @return {Roo.Element} this
8778          */
8779         setBox : function(box, adjust, animate){
8780             var w = box.width, h = box.height;
8781             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8782                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8783                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8784             }
8785             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8786             return this;
8787         },
8788
8789         /**
8790          * Forces the browser to repaint this element
8791          * @return {Roo.Element} this
8792          */
8793          repaint : function(){
8794             var dom = this.dom;
8795             this.addClass("x-repaint");
8796             setTimeout(function(){
8797                 Roo.get(dom).removeClass("x-repaint");
8798             }, 1);
8799             return this;
8800         },
8801
8802         /**
8803          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8804          * then it returns the calculated width of the sides (see getPadding)
8805          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8806          * @return {Object/Number}
8807          */
8808         getMargins : function(side){
8809             if(!side){
8810                 return {
8811                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8812                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8813                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8814                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8815                 };
8816             }else{
8817                 return this.addStyles(side, El.margins);
8818              }
8819         },
8820
8821         // private
8822         addStyles : function(sides, styles){
8823             var val = 0, v, w;
8824             for(var i = 0, len = sides.length; i < len; i++){
8825                 v = this.getStyle(styles[sides.charAt(i)]);
8826                 if(v){
8827                      w = parseInt(v, 10);
8828                      if(w){ val += w; }
8829                 }
8830             }
8831             return val;
8832         },
8833
8834         /**
8835          * Creates a proxy element of this element
8836          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8837          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8838          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8839          * @return {Roo.Element} The new proxy element
8840          */
8841         createProxy : function(config, renderTo, matchBox){
8842             if(renderTo){
8843                 renderTo = Roo.getDom(renderTo);
8844             }else{
8845                 renderTo = document.body;
8846             }
8847             config = typeof config == "object" ?
8848                 config : {tag : "div", cls: config};
8849             var proxy = Roo.DomHelper.append(renderTo, config, true);
8850             if(matchBox){
8851                proxy.setBox(this.getBox());
8852             }
8853             return proxy;
8854         },
8855
8856         /**
8857          * Puts a mask over this element to disable user interaction. Requires core.css.
8858          * This method can only be applied to elements which accept child nodes.
8859          * @param {String} msg (optional) A message to display in the mask
8860          * @param {String} msgCls (optional) A css class to apply to the msg element
8861          * @return {Element} The mask  element
8862          */
8863         mask : function(msg, msgCls)
8864         {
8865             if(this.getStyle("position") == "static"){
8866                 this.setStyle("position", "relative");
8867             }
8868             if(!this._mask){
8869                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8870             }
8871             this.addClass("x-masked");
8872             this._mask.setDisplayed(true);
8873             
8874             // we wander
8875             var z = 0;
8876             var dom = this.dom
8877             while (dom) {
8878                 if (!isNaN(parseInt(dom.style.zIndex))) {
8879                     z = Math.max(z, parseInt(dom.style.zIndex));
8880                 }
8881                 dom = dom.parentNode;
8882             }
8883             
8884            
8885             if(typeof msg == 'string'){
8886                 if(!this._maskMsg){
8887                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8888                 }
8889                 var mm = this._maskMsg;
8890                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8891                 mm.dom.firstChild.innerHTML = msg;
8892                 mm.setDisplayed(true);
8893                 mm.center(this);
8894                 mm.setStyle('z-index', z + 102);
8895             }
8896             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8897                 this._mask.setHeight(this.getHeight());
8898             }
8899             this._mask.setStyle('z-index', z + 100);
8900             
8901             return this._mask;
8902         },
8903
8904         /**
8905          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8906          * it is cached for reuse.
8907          */
8908         unmask : function(removeEl){
8909             if(this._mask){
8910                 if(removeEl === true){
8911                     this._mask.remove();
8912                     delete this._mask;
8913                     if(this._maskMsg){
8914                         this._maskMsg.remove();
8915                         delete this._maskMsg;
8916                     }
8917                 }else{
8918                     this._mask.setDisplayed(false);
8919                     if(this._maskMsg){
8920                         this._maskMsg.setDisplayed(false);
8921                     }
8922                 }
8923             }
8924             this.removeClass("x-masked");
8925         },
8926
8927         /**
8928          * Returns true if this element is masked
8929          * @return {Boolean}
8930          */
8931         isMasked : function(){
8932             return this._mask && this._mask.isVisible();
8933         },
8934
8935         /**
8936          * Creates an iframe shim for this element to keep selects and other windowed objects from
8937          * showing through.
8938          * @return {Roo.Element} The new shim element
8939          */
8940         createShim : function(){
8941             var el = document.createElement('iframe');
8942             el.frameBorder = 'no';
8943             el.className = 'roo-shim';
8944             if(Roo.isIE && Roo.isSecure){
8945                 el.src = Roo.SSL_SECURE_URL;
8946             }
8947             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8948             shim.autoBoxAdjust = false;
8949             return shim;
8950         },
8951
8952         /**
8953          * Removes this element from the DOM and deletes it from the cache
8954          */
8955         remove : function(){
8956             if(this.dom.parentNode){
8957                 this.dom.parentNode.removeChild(this.dom);
8958             }
8959             delete El.cache[this.dom.id];
8960         },
8961
8962         /**
8963          * Sets up event handlers to add and remove a css class when the mouse is over this element
8964          * @param {String} className
8965          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8966          * mouseout events for children elements
8967          * @return {Roo.Element} this
8968          */
8969         addClassOnOver : function(className, preventFlicker){
8970             this.on("mouseover", function(){
8971                 Roo.fly(this, '_internal').addClass(className);
8972             }, this.dom);
8973             var removeFn = function(e){
8974                 if(preventFlicker !== true || !e.within(this, true)){
8975                     Roo.fly(this, '_internal').removeClass(className);
8976                 }
8977             };
8978             this.on("mouseout", removeFn, this.dom);
8979             return this;
8980         },
8981
8982         /**
8983          * Sets up event handlers to add and remove a css class when this element has the focus
8984          * @param {String} className
8985          * @return {Roo.Element} this
8986          */
8987         addClassOnFocus : function(className){
8988             this.on("focus", function(){
8989                 Roo.fly(this, '_internal').addClass(className);
8990             }, this.dom);
8991             this.on("blur", function(){
8992                 Roo.fly(this, '_internal').removeClass(className);
8993             }, this.dom);
8994             return this;
8995         },
8996         /**
8997          * 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)
8998          * @param {String} className
8999          * @return {Roo.Element} this
9000          */
9001         addClassOnClick : function(className){
9002             var dom = this.dom;
9003             this.on("mousedown", function(){
9004                 Roo.fly(dom, '_internal').addClass(className);
9005                 var d = Roo.get(document);
9006                 var fn = function(){
9007                     Roo.fly(dom, '_internal').removeClass(className);
9008                     d.removeListener("mouseup", fn);
9009                 };
9010                 d.on("mouseup", fn);
9011             });
9012             return this;
9013         },
9014
9015         /**
9016          * Stops the specified event from bubbling and optionally prevents the default action
9017          * @param {String} eventName
9018          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9019          * @return {Roo.Element} this
9020          */
9021         swallowEvent : function(eventName, preventDefault){
9022             var fn = function(e){
9023                 e.stopPropagation();
9024                 if(preventDefault){
9025                     e.preventDefault();
9026                 }
9027             };
9028             if(eventName instanceof Array){
9029                 for(var i = 0, len = eventName.length; i < len; i++){
9030                      this.on(eventName[i], fn);
9031                 }
9032                 return this;
9033             }
9034             this.on(eventName, fn);
9035             return this;
9036         },
9037
9038         /**
9039          * @private
9040          */
9041       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9042
9043         /**
9044          * Sizes this element to its parent element's dimensions performing
9045          * neccessary box adjustments.
9046          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9047          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9048          * @return {Roo.Element} this
9049          */
9050         fitToParent : function(monitorResize, targetParent) {
9051           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9052           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9053           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9054             return;
9055           }
9056           var p = Roo.get(targetParent || this.dom.parentNode);
9057           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9058           if (monitorResize === true) {
9059             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9060             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9061           }
9062           return this;
9063         },
9064
9065         /**
9066          * Gets the next sibling, skipping text nodes
9067          * @return {HTMLElement} The next sibling or null
9068          */
9069         getNextSibling : function(){
9070             var n = this.dom.nextSibling;
9071             while(n && n.nodeType != 1){
9072                 n = n.nextSibling;
9073             }
9074             return n;
9075         },
9076
9077         /**
9078          * Gets the previous sibling, skipping text nodes
9079          * @return {HTMLElement} The previous sibling or null
9080          */
9081         getPrevSibling : function(){
9082             var n = this.dom.previousSibling;
9083             while(n && n.nodeType != 1){
9084                 n = n.previousSibling;
9085             }
9086             return n;
9087         },
9088
9089
9090         /**
9091          * Appends the passed element(s) to this element
9092          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9093          * @return {Roo.Element} this
9094          */
9095         appendChild: function(el){
9096             el = Roo.get(el);
9097             el.appendTo(this);
9098             return this;
9099         },
9100
9101         /**
9102          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9103          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9104          * automatically generated with the specified attributes.
9105          * @param {HTMLElement} insertBefore (optional) a child element of this element
9106          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9107          * @return {Roo.Element} The new child element
9108          */
9109         createChild: function(config, insertBefore, returnDom){
9110             config = config || {tag:'div'};
9111             if(insertBefore){
9112                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9113             }
9114             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9115         },
9116
9117         /**
9118          * Appends this element to the passed element
9119          * @param {String/HTMLElement/Element} el The new parent element
9120          * @return {Roo.Element} this
9121          */
9122         appendTo: function(el){
9123             el = Roo.getDom(el);
9124             el.appendChild(this.dom);
9125             return this;
9126         },
9127
9128         /**
9129          * Inserts this element before the passed element in the DOM
9130          * @param {String/HTMLElement/Element} el The element to insert before
9131          * @return {Roo.Element} this
9132          */
9133         insertBefore: function(el){
9134             el = Roo.getDom(el);
9135             el.parentNode.insertBefore(this.dom, el);
9136             return this;
9137         },
9138
9139         /**
9140          * Inserts this element after the passed element in the DOM
9141          * @param {String/HTMLElement/Element} el The element to insert after
9142          * @return {Roo.Element} this
9143          */
9144         insertAfter: function(el){
9145             el = Roo.getDom(el);
9146             el.parentNode.insertBefore(this.dom, el.nextSibling);
9147             return this;
9148         },
9149
9150         /**
9151          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9152          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9153          * @return {Roo.Element} The new child
9154          */
9155         insertFirst: function(el, returnDom){
9156             el = el || {};
9157             if(typeof el == 'object' && !el.nodeType){ // dh config
9158                 return this.createChild(el, this.dom.firstChild, returnDom);
9159             }else{
9160                 el = Roo.getDom(el);
9161                 this.dom.insertBefore(el, this.dom.firstChild);
9162                 return !returnDom ? Roo.get(el) : el;
9163             }
9164         },
9165
9166         /**
9167          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9168          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9169          * @param {String} where (optional) 'before' or 'after' defaults to before
9170          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9171          * @return {Roo.Element} the inserted Element
9172          */
9173         insertSibling: function(el, where, returnDom){
9174             where = where ? where.toLowerCase() : 'before';
9175             el = el || {};
9176             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9177
9178             if(typeof el == 'object' && !el.nodeType){ // dh config
9179                 if(where == 'after' && !this.dom.nextSibling){
9180                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9181                 }else{
9182                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9183                 }
9184
9185             }else{
9186                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9187                             where == 'before' ? this.dom : this.dom.nextSibling);
9188                 if(!returnDom){
9189                     rt = Roo.get(rt);
9190                 }
9191             }
9192             return rt;
9193         },
9194
9195         /**
9196          * Creates and wraps this element with another element
9197          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9198          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9199          * @return {HTMLElement/Element} The newly created wrapper element
9200          */
9201         wrap: function(config, returnDom){
9202             if(!config){
9203                 config = {tag: "div"};
9204             }
9205             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9206             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9207             return newEl;
9208         },
9209
9210         /**
9211          * Replaces the passed element with this element
9212          * @param {String/HTMLElement/Element} el The element to replace
9213          * @return {Roo.Element} this
9214          */
9215         replace: function(el){
9216             el = Roo.get(el);
9217             this.insertBefore(el);
9218             el.remove();
9219             return this;
9220         },
9221
9222         /**
9223          * Inserts an html fragment into this element
9224          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9225          * @param {String} html The HTML fragment
9226          * @param {Boolean} returnEl True to return an Roo.Element
9227          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9228          */
9229         insertHtml : function(where, html, returnEl){
9230             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9231             return returnEl ? Roo.get(el) : el;
9232         },
9233
9234         /**
9235          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9236          * @param {Object} o The object with the attributes
9237          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9238          * @return {Roo.Element} this
9239          */
9240         set : function(o, useSet){
9241             var el = this.dom;
9242             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9243             for(var attr in o){
9244                 if(attr == "style" || typeof o[attr] == "function") continue;
9245                 if(attr=="cls"){
9246                     el.className = o["cls"];
9247                 }else{
9248                     if(useSet) el.setAttribute(attr, o[attr]);
9249                     else el[attr] = o[attr];
9250                 }
9251             }
9252             if(o.style){
9253                 Roo.DomHelper.applyStyles(el, o.style);
9254             }
9255             return this;
9256         },
9257
9258         /**
9259          * Convenience method for constructing a KeyMap
9260          * @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:
9261          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9262          * @param {Function} fn The function to call
9263          * @param {Object} scope (optional) The scope of the function
9264          * @return {Roo.KeyMap} The KeyMap created
9265          */
9266         addKeyListener : function(key, fn, scope){
9267             var config;
9268             if(typeof key != "object" || key instanceof Array){
9269                 config = {
9270                     key: key,
9271                     fn: fn,
9272                     scope: scope
9273                 };
9274             }else{
9275                 config = {
9276                     key : key.key,
9277                     shift : key.shift,
9278                     ctrl : key.ctrl,
9279                     alt : key.alt,
9280                     fn: fn,
9281                     scope: scope
9282                 };
9283             }
9284             return new Roo.KeyMap(this, config);
9285         },
9286
9287         /**
9288          * Creates a KeyMap for this element
9289          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9290          * @return {Roo.KeyMap} The KeyMap created
9291          */
9292         addKeyMap : function(config){
9293             return new Roo.KeyMap(this, config);
9294         },
9295
9296         /**
9297          * Returns true if this element is scrollable.
9298          * @return {Boolean}
9299          */
9300          isScrollable : function(){
9301             var dom = this.dom;
9302             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9303         },
9304
9305         /**
9306          * 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().
9307          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9308          * @param {Number} value The new scroll value
9309          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9310          * @return {Element} this
9311          */
9312
9313         scrollTo : function(side, value, animate){
9314             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9315             if(!animate || !A){
9316                 this.dom[prop] = value;
9317             }else{
9318                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9319                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9320             }
9321             return this;
9322         },
9323
9324         /**
9325          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9326          * within this element's scrollable range.
9327          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9328          * @param {Number} distance How far to scroll the element in pixels
9329          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9330          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9331          * was scrolled as far as it could go.
9332          */
9333          scroll : function(direction, distance, animate){
9334              if(!this.isScrollable()){
9335                  return;
9336              }
9337              var el = this.dom;
9338              var l = el.scrollLeft, t = el.scrollTop;
9339              var w = el.scrollWidth, h = el.scrollHeight;
9340              var cw = el.clientWidth, ch = el.clientHeight;
9341              direction = direction.toLowerCase();
9342              var scrolled = false;
9343              var a = this.preanim(arguments, 2);
9344              switch(direction){
9345                  case "l":
9346                  case "left":
9347                      if(w - l > cw){
9348                          var v = Math.min(l + distance, w-cw);
9349                          this.scrollTo("left", v, a);
9350                          scrolled = true;
9351                      }
9352                      break;
9353                 case "r":
9354                 case "right":
9355                      if(l > 0){
9356                          var v = Math.max(l - distance, 0);
9357                          this.scrollTo("left", v, a);
9358                          scrolled = true;
9359                      }
9360                      break;
9361                 case "t":
9362                 case "top":
9363                 case "up":
9364                      if(t > 0){
9365                          var v = Math.max(t - distance, 0);
9366                          this.scrollTo("top", v, a);
9367                          scrolled = true;
9368                      }
9369                      break;
9370                 case "b":
9371                 case "bottom":
9372                 case "down":
9373                      if(h - t > ch){
9374                          var v = Math.min(t + distance, h-ch);
9375                          this.scrollTo("top", v, a);
9376                          scrolled = true;
9377                      }
9378                      break;
9379              }
9380              return scrolled;
9381         },
9382
9383         /**
9384          * Translates the passed page coordinates into left/top css values for this element
9385          * @param {Number/Array} x The page x or an array containing [x, y]
9386          * @param {Number} y The page y
9387          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9388          */
9389         translatePoints : function(x, y){
9390             if(typeof x == 'object' || x instanceof Array){
9391                 y = x[1]; x = x[0];
9392             }
9393             var p = this.getStyle('position');
9394             var o = this.getXY();
9395
9396             var l = parseInt(this.getStyle('left'), 10);
9397             var t = parseInt(this.getStyle('top'), 10);
9398
9399             if(isNaN(l)){
9400                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9401             }
9402             if(isNaN(t)){
9403                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9404             }
9405
9406             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9407         },
9408
9409         /**
9410          * Returns the current scroll position of the element.
9411          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9412          */
9413         getScroll : function(){
9414             var d = this.dom, doc = document;
9415             if(d == doc || d == doc.body){
9416                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9417                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9418                 return {left: l, top: t};
9419             }else{
9420                 return {left: d.scrollLeft, top: d.scrollTop};
9421             }
9422         },
9423
9424         /**
9425          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9426          * are convert to standard 6 digit hex color.
9427          * @param {String} attr The css attribute
9428          * @param {String} defaultValue The default value to use when a valid color isn't found
9429          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9430          * YUI color anims.
9431          */
9432         getColor : function(attr, defaultValue, prefix){
9433             var v = this.getStyle(attr);
9434             if(!v || v == "transparent" || v == "inherit") {
9435                 return defaultValue;
9436             }
9437             var color = typeof prefix == "undefined" ? "#" : prefix;
9438             if(v.substr(0, 4) == "rgb("){
9439                 var rvs = v.slice(4, v.length -1).split(",");
9440                 for(var i = 0; i < 3; i++){
9441                     var h = parseInt(rvs[i]).toString(16);
9442                     if(h < 16){
9443                         h = "0" + h;
9444                     }
9445                     color += h;
9446                 }
9447             } else {
9448                 if(v.substr(0, 1) == "#"){
9449                     if(v.length == 4) {
9450                         for(var i = 1; i < 4; i++){
9451                             var c = v.charAt(i);
9452                             color +=  c + c;
9453                         }
9454                     }else if(v.length == 7){
9455                         color += v.substr(1);
9456                     }
9457                 }
9458             }
9459             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9460         },
9461
9462         /**
9463          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9464          * gradient background, rounded corners and a 4-way shadow.
9465          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9466          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9467          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9468          * @return {Roo.Element} this
9469          */
9470         boxWrap : function(cls){
9471             cls = cls || 'x-box';
9472             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9473             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9474             return el;
9475         },
9476
9477         /**
9478          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9479          * @param {String} namespace The namespace in which to look for the attribute
9480          * @param {String} name The attribute name
9481          * @return {String} The attribute value
9482          */
9483         getAttributeNS : Roo.isIE ? function(ns, name){
9484             var d = this.dom;
9485             var type = typeof d[ns+":"+name];
9486             if(type != 'undefined' && type != 'unknown'){
9487                 return d[ns+":"+name];
9488             }
9489             return d[name];
9490         } : function(ns, name){
9491             var d = this.dom;
9492             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9493         }
9494     };
9495
9496     var ep = El.prototype;
9497
9498     /**
9499      * Appends an event handler (Shorthand for addListener)
9500      * @param {String}   eventName     The type of event to append
9501      * @param {Function} fn        The method the event invokes
9502      * @param {Object} scope       (optional) The scope (this object) of the fn
9503      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9504      * @method
9505      */
9506     ep.on = ep.addListener;
9507         // backwards compat
9508     ep.mon = ep.addListener;
9509
9510     /**
9511      * Removes an event handler from this element (shorthand for removeListener)
9512      * @param {String} eventName the type of event to remove
9513      * @param {Function} fn the method the event invokes
9514      * @return {Roo.Element} this
9515      * @method
9516      */
9517     ep.un = ep.removeListener;
9518
9519     /**
9520      * true to automatically adjust width and height settings for box-model issues (default to true)
9521      */
9522     ep.autoBoxAdjust = true;
9523
9524     // private
9525     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9526
9527     // private
9528     El.addUnits = function(v, defaultUnit){
9529         if(v === "" || v == "auto"){
9530             return v;
9531         }
9532         if(v === undefined){
9533             return '';
9534         }
9535         if(typeof v == "number" || !El.unitPattern.test(v)){
9536             return v + (defaultUnit || 'px');
9537         }
9538         return v;
9539     };
9540
9541     // special markup used throughout Roo when box wrapping elements
9542     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>';
9543     /**
9544      * Visibility mode constant - Use visibility to hide element
9545      * @static
9546      * @type Number
9547      */
9548     El.VISIBILITY = 1;
9549     /**
9550      * Visibility mode constant - Use display to hide element
9551      * @static
9552      * @type Number
9553      */
9554     El.DISPLAY = 2;
9555
9556     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9557     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9558     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9559
9560
9561
9562     /**
9563      * @private
9564      */
9565     El.cache = {};
9566
9567     var docEl;
9568
9569     /**
9570      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9571      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9572      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9573      * @return {Element} The Element object
9574      * @static
9575      */
9576     El.get = function(el){
9577         var ex, elm, id;
9578         if(!el){ return null; }
9579         if(typeof el == "string"){ // element id
9580             if(!(elm = document.getElementById(el))){
9581                 return null;
9582             }
9583             if(ex = El.cache[el]){
9584                 ex.dom = elm;
9585             }else{
9586                 ex = El.cache[el] = new El(elm);
9587             }
9588             return ex;
9589         }else if(el.tagName){ // dom element
9590             if(!(id = el.id)){
9591                 id = Roo.id(el);
9592             }
9593             if(ex = El.cache[id]){
9594                 ex.dom = el;
9595             }else{
9596                 ex = El.cache[id] = new El(el);
9597             }
9598             return ex;
9599         }else if(el instanceof El){
9600             if(el != docEl){
9601                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9602                                                               // catch case where it hasn't been appended
9603                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9604             }
9605             return el;
9606         }else if(el.isComposite){
9607             return el;
9608         }else if(el instanceof Array){
9609             return El.select(el);
9610         }else if(el == document){
9611             // create a bogus element object representing the document object
9612             if(!docEl){
9613                 var f = function(){};
9614                 f.prototype = El.prototype;
9615                 docEl = new f();
9616                 docEl.dom = document;
9617             }
9618             return docEl;
9619         }
9620         return null;
9621     };
9622
9623     // private
9624     El.uncache = function(el){
9625         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9626             if(a[i]){
9627                 delete El.cache[a[i].id || a[i]];
9628             }
9629         }
9630     };
9631
9632     // private
9633     // Garbage collection - uncache elements/purge listeners on orphaned elements
9634     // so we don't hold a reference and cause the browser to retain them
9635     El.garbageCollect = function(){
9636         if(!Roo.enableGarbageCollector){
9637             clearInterval(El.collectorThread);
9638             return;
9639         }
9640         for(var eid in El.cache){
9641             var el = El.cache[eid], d = el.dom;
9642             // -------------------------------------------------------
9643             // Determining what is garbage:
9644             // -------------------------------------------------------
9645             // !d
9646             // dom node is null, definitely garbage
9647             // -------------------------------------------------------
9648             // !d.parentNode
9649             // no parentNode == direct orphan, definitely garbage
9650             // -------------------------------------------------------
9651             // !d.offsetParent && !document.getElementById(eid)
9652             // display none elements have no offsetParent so we will
9653             // also try to look it up by it's id. However, check
9654             // offsetParent first so we don't do unneeded lookups.
9655             // This enables collection of elements that are not orphans
9656             // directly, but somewhere up the line they have an orphan
9657             // parent.
9658             // -------------------------------------------------------
9659             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9660                 delete El.cache[eid];
9661                 if(d && Roo.enableListenerCollection){
9662                     E.purgeElement(d);
9663                 }
9664             }
9665         }
9666     }
9667     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9668
9669
9670     // dom is optional
9671     El.Flyweight = function(dom){
9672         this.dom = dom;
9673     };
9674     El.Flyweight.prototype = El.prototype;
9675
9676     El._flyweights = {};
9677     /**
9678      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9679      * the dom node can be overwritten by other code.
9680      * @param {String/HTMLElement} el The dom node or id
9681      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9682      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9683      * @static
9684      * @return {Element} The shared Element object
9685      */
9686     El.fly = function(el, named){
9687         named = named || '_global';
9688         el = Roo.getDom(el);
9689         if(!el){
9690             return null;
9691         }
9692         if(!El._flyweights[named]){
9693             El._flyweights[named] = new El.Flyweight();
9694         }
9695         El._flyweights[named].dom = el;
9696         return El._flyweights[named];
9697     };
9698
9699     /**
9700      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9701      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9702      * Shorthand of {@link Roo.Element#get}
9703      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9704      * @return {Element} The Element object
9705      * @member Roo
9706      * @method get
9707      */
9708     Roo.get = El.get;
9709     /**
9710      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9711      * the dom node can be overwritten by other code.
9712      * Shorthand of {@link Roo.Element#fly}
9713      * @param {String/HTMLElement} el The dom node or id
9714      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9715      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9716      * @static
9717      * @return {Element} The shared Element object
9718      * @member Roo
9719      * @method fly
9720      */
9721     Roo.fly = El.fly;
9722
9723     // speedy lookup for elements never to box adjust
9724     var noBoxAdjust = Roo.isStrict ? {
9725         select:1
9726     } : {
9727         input:1, select:1, textarea:1
9728     };
9729     if(Roo.isIE || Roo.isGecko){
9730         noBoxAdjust['button'] = 1;
9731     }
9732
9733
9734     Roo.EventManager.on(window, 'unload', function(){
9735         delete El.cache;
9736         delete El._flyweights;
9737     });
9738 })();
9739
9740
9741
9742
9743 if(Roo.DomQuery){
9744     Roo.Element.selectorFunction = Roo.DomQuery.select;
9745 }
9746
9747 Roo.Element.select = function(selector, unique, root){
9748     var els;
9749     if(typeof selector == "string"){
9750         els = Roo.Element.selectorFunction(selector, root);
9751     }else if(selector.length !== undefined){
9752         els = selector;
9753     }else{
9754         throw "Invalid selector";
9755     }
9756     if(unique === true){
9757         return new Roo.CompositeElement(els);
9758     }else{
9759         return new Roo.CompositeElementLite(els);
9760     }
9761 };
9762 /**
9763  * Selects elements based on the passed CSS selector to enable working on them as 1.
9764  * @param {String/Array} selector The CSS selector or an array of elements
9765  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9766  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9767  * @return {CompositeElementLite/CompositeElement}
9768  * @member Roo
9769  * @method select
9770  */
9771 Roo.select = Roo.Element.select;
9772
9773
9774
9775
9776
9777
9778
9779
9780
9781
9782
9783
9784
9785
9786 /*
9787  * Based on:
9788  * Ext JS Library 1.1.1
9789  * Copyright(c) 2006-2007, Ext JS, LLC.
9790  *
9791  * Originally Released Under LGPL - original licence link has changed is not relivant.
9792  *
9793  * Fork - LGPL
9794  * <script type="text/javascript">
9795  */
9796
9797
9798
9799 //Notifies Element that fx methods are available
9800 Roo.enableFx = true;
9801
9802 /**
9803  * @class Roo.Fx
9804  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9805  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9806  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9807  * Element effects to work.</p><br/>
9808  *
9809  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9810  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9811  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9812  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9813  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9814  * expected results and should be done with care.</p><br/>
9815  *
9816  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9817  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9818 <pre>
9819 Value  Description
9820 -----  -----------------------------
9821 tl     The top left corner
9822 t      The center of the top edge
9823 tr     The top right corner
9824 l      The center of the left edge
9825 r      The center of the right edge
9826 bl     The bottom left corner
9827 b      The center of the bottom edge
9828 br     The bottom right corner
9829 </pre>
9830  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9831  * below are common options that can be passed to any Fx method.</b>
9832  * @cfg {Function} callback A function called when the effect is finished
9833  * @cfg {Object} scope The scope of the effect function
9834  * @cfg {String} easing A valid Easing value for the effect
9835  * @cfg {String} afterCls A css class to apply after the effect
9836  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9837  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9838  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9839  * effects that end with the element being visually hidden, ignored otherwise)
9840  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9841  * a function which returns such a specification that will be applied to the Element after the effect finishes
9842  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9843  * @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
9844  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9845  */
9846 Roo.Fx = {
9847         /**
9848          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9849          * origin for the slide effect.  This function automatically handles wrapping the element with
9850          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9851          * Usage:
9852          *<pre><code>
9853 // default: slide the element in from the top
9854 el.slideIn();
9855
9856 // custom: slide the element in from the right with a 2-second duration
9857 el.slideIn('r', { duration: 2 });
9858
9859 // common config options shown with default values
9860 el.slideIn('t', {
9861     easing: 'easeOut',
9862     duration: .5
9863 });
9864 </code></pre>
9865          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9866          * @param {Object} options (optional) Object literal with any of the Fx config options
9867          * @return {Roo.Element} The Element
9868          */
9869     slideIn : function(anchor, o){
9870         var el = this.getFxEl();
9871         o = o || {};
9872
9873         el.queueFx(o, function(){
9874
9875             anchor = anchor || "t";
9876
9877             // fix display to visibility
9878             this.fixDisplay();
9879
9880             // restore values after effect
9881             var r = this.getFxRestore();
9882             var b = this.getBox();
9883             // fixed size for slide
9884             this.setSize(b);
9885
9886             // wrap if needed
9887             var wrap = this.fxWrap(r.pos, o, "hidden");
9888
9889             var st = this.dom.style;
9890             st.visibility = "visible";
9891             st.position = "absolute";
9892
9893             // clear out temp styles after slide and unwrap
9894             var after = function(){
9895                 el.fxUnwrap(wrap, r.pos, o);
9896                 st.width = r.width;
9897                 st.height = r.height;
9898                 el.afterFx(o);
9899             };
9900             // time to calc the positions
9901             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9902
9903             switch(anchor.toLowerCase()){
9904                 case "t":
9905                     wrap.setSize(b.width, 0);
9906                     st.left = st.bottom = "0";
9907                     a = {height: bh};
9908                 break;
9909                 case "l":
9910                     wrap.setSize(0, b.height);
9911                     st.right = st.top = "0";
9912                     a = {width: bw};
9913                 break;
9914                 case "r":
9915                     wrap.setSize(0, b.height);
9916                     wrap.setX(b.right);
9917                     st.left = st.top = "0";
9918                     a = {width: bw, points: pt};
9919                 break;
9920                 case "b":
9921                     wrap.setSize(b.width, 0);
9922                     wrap.setY(b.bottom);
9923                     st.left = st.top = "0";
9924                     a = {height: bh, points: pt};
9925                 break;
9926                 case "tl":
9927                     wrap.setSize(0, 0);
9928                     st.right = st.bottom = "0";
9929                     a = {width: bw, height: bh};
9930                 break;
9931                 case "bl":
9932                     wrap.setSize(0, 0);
9933                     wrap.setY(b.y+b.height);
9934                     st.right = st.top = "0";
9935                     a = {width: bw, height: bh, points: pt};
9936                 break;
9937                 case "br":
9938                     wrap.setSize(0, 0);
9939                     wrap.setXY([b.right, b.bottom]);
9940                     st.left = st.top = "0";
9941                     a = {width: bw, height: bh, points: pt};
9942                 break;
9943                 case "tr":
9944                     wrap.setSize(0, 0);
9945                     wrap.setX(b.x+b.width);
9946                     st.left = st.bottom = "0";
9947                     a = {width: bw, height: bh, points: pt};
9948                 break;
9949             }
9950             this.dom.style.visibility = "visible";
9951             wrap.show();
9952
9953             arguments.callee.anim = wrap.fxanim(a,
9954                 o,
9955                 'motion',
9956                 .5,
9957                 'easeOut', after);
9958         });
9959         return this;
9960     },
9961     
9962         /**
9963          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9964          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9965          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9966          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9967          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9968          * Usage:
9969          *<pre><code>
9970 // default: slide the element out to the top
9971 el.slideOut();
9972
9973 // custom: slide the element out to the right with a 2-second duration
9974 el.slideOut('r', { duration: 2 });
9975
9976 // common config options shown with default values
9977 el.slideOut('t', {
9978     easing: 'easeOut',
9979     duration: .5,
9980     remove: false,
9981     useDisplay: false
9982 });
9983 </code></pre>
9984          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9985          * @param {Object} options (optional) Object literal with any of the Fx config options
9986          * @return {Roo.Element} The Element
9987          */
9988     slideOut : function(anchor, o){
9989         var el = this.getFxEl();
9990         o = o || {};
9991
9992         el.queueFx(o, function(){
9993
9994             anchor = anchor || "t";
9995
9996             // restore values after effect
9997             var r = this.getFxRestore();
9998             
9999             var b = this.getBox();
10000             // fixed size for slide
10001             this.setSize(b);
10002
10003             // wrap if needed
10004             var wrap = this.fxWrap(r.pos, o, "visible");
10005
10006             var st = this.dom.style;
10007             st.visibility = "visible";
10008             st.position = "absolute";
10009
10010             wrap.setSize(b);
10011
10012             var after = function(){
10013                 if(o.useDisplay){
10014                     el.setDisplayed(false);
10015                 }else{
10016                     el.hide();
10017                 }
10018
10019                 el.fxUnwrap(wrap, r.pos, o);
10020
10021                 st.width = r.width;
10022                 st.height = r.height;
10023
10024                 el.afterFx(o);
10025             };
10026
10027             var a, zero = {to: 0};
10028             switch(anchor.toLowerCase()){
10029                 case "t":
10030                     st.left = st.bottom = "0";
10031                     a = {height: zero};
10032                 break;
10033                 case "l":
10034                     st.right = st.top = "0";
10035                     a = {width: zero};
10036                 break;
10037                 case "r":
10038                     st.left = st.top = "0";
10039                     a = {width: zero, points: {to:[b.right, b.y]}};
10040                 break;
10041                 case "b":
10042                     st.left = st.top = "0";
10043                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10044                 break;
10045                 case "tl":
10046                     st.right = st.bottom = "0";
10047                     a = {width: zero, height: zero};
10048                 break;
10049                 case "bl":
10050                     st.right = st.top = "0";
10051                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10052                 break;
10053                 case "br":
10054                     st.left = st.top = "0";
10055                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10056                 break;
10057                 case "tr":
10058                     st.left = st.bottom = "0";
10059                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10060                 break;
10061             }
10062
10063             arguments.callee.anim = wrap.fxanim(a,
10064                 o,
10065                 'motion',
10066                 .5,
10067                 "easeOut", after);
10068         });
10069         return this;
10070     },
10071
10072         /**
10073          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10074          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10075          * The element must be removed from the DOM using the 'remove' config option if desired.
10076          * Usage:
10077          *<pre><code>
10078 // default
10079 el.puff();
10080
10081 // common config options shown with default values
10082 el.puff({
10083     easing: 'easeOut',
10084     duration: .5,
10085     remove: false,
10086     useDisplay: false
10087 });
10088 </code></pre>
10089          * @param {Object} options (optional) Object literal with any of the Fx config options
10090          * @return {Roo.Element} The Element
10091          */
10092     puff : function(o){
10093         var el = this.getFxEl();
10094         o = o || {};
10095
10096         el.queueFx(o, function(){
10097             this.clearOpacity();
10098             this.show();
10099
10100             // restore values after effect
10101             var r = this.getFxRestore();
10102             var st = this.dom.style;
10103
10104             var after = function(){
10105                 if(o.useDisplay){
10106                     el.setDisplayed(false);
10107                 }else{
10108                     el.hide();
10109                 }
10110
10111                 el.clearOpacity();
10112
10113                 el.setPositioning(r.pos);
10114                 st.width = r.width;
10115                 st.height = r.height;
10116                 st.fontSize = '';
10117                 el.afterFx(o);
10118             };
10119
10120             var width = this.getWidth();
10121             var height = this.getHeight();
10122
10123             arguments.callee.anim = this.fxanim({
10124                     width : {to: this.adjustWidth(width * 2)},
10125                     height : {to: this.adjustHeight(height * 2)},
10126                     points : {by: [-(width * .5), -(height * .5)]},
10127                     opacity : {to: 0},
10128                     fontSize: {to:200, unit: "%"}
10129                 },
10130                 o,
10131                 'motion',
10132                 .5,
10133                 "easeOut", after);
10134         });
10135         return this;
10136     },
10137
10138         /**
10139          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10140          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10141          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10142          * Usage:
10143          *<pre><code>
10144 // default
10145 el.switchOff();
10146
10147 // all config options shown with default values
10148 el.switchOff({
10149     easing: 'easeIn',
10150     duration: .3,
10151     remove: false,
10152     useDisplay: false
10153 });
10154 </code></pre>
10155          * @param {Object} options (optional) Object literal with any of the Fx config options
10156          * @return {Roo.Element} The Element
10157          */
10158     switchOff : function(o){
10159         var el = this.getFxEl();
10160         o = o || {};
10161
10162         el.queueFx(o, function(){
10163             this.clearOpacity();
10164             this.clip();
10165
10166             // restore values after effect
10167             var r = this.getFxRestore();
10168             var st = this.dom.style;
10169
10170             var after = function(){
10171                 if(o.useDisplay){
10172                     el.setDisplayed(false);
10173                 }else{
10174                     el.hide();
10175                 }
10176
10177                 el.clearOpacity();
10178                 el.setPositioning(r.pos);
10179                 st.width = r.width;
10180                 st.height = r.height;
10181
10182                 el.afterFx(o);
10183             };
10184
10185             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10186                 this.clearOpacity();
10187                 (function(){
10188                     this.fxanim({
10189                         height:{to:1},
10190                         points:{by:[0, this.getHeight() * .5]}
10191                     }, o, 'motion', 0.3, 'easeIn', after);
10192                 }).defer(100, this);
10193             });
10194         });
10195         return this;
10196     },
10197
10198     /**
10199      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10200      * changed using the "attr" config option) and then fading back to the original color. If no original
10201      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10202      * Usage:
10203 <pre><code>
10204 // default: highlight background to yellow
10205 el.highlight();
10206
10207 // custom: highlight foreground text to blue for 2 seconds
10208 el.highlight("0000ff", { attr: 'color', duration: 2 });
10209
10210 // common config options shown with default values
10211 el.highlight("ffff9c", {
10212     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10213     endColor: (current color) or "ffffff",
10214     easing: 'easeIn',
10215     duration: 1
10216 });
10217 </code></pre>
10218      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10219      * @param {Object} options (optional) Object literal with any of the Fx config options
10220      * @return {Roo.Element} The Element
10221      */ 
10222     highlight : function(color, o){
10223         var el = this.getFxEl();
10224         o = o || {};
10225
10226         el.queueFx(o, function(){
10227             color = color || "ffff9c";
10228             attr = o.attr || "backgroundColor";
10229
10230             this.clearOpacity();
10231             this.show();
10232
10233             var origColor = this.getColor(attr);
10234             var restoreColor = this.dom.style[attr];
10235             endColor = (o.endColor || origColor) || "ffffff";
10236
10237             var after = function(){
10238                 el.dom.style[attr] = restoreColor;
10239                 el.afterFx(o);
10240             };
10241
10242             var a = {};
10243             a[attr] = {from: color, to: endColor};
10244             arguments.callee.anim = this.fxanim(a,
10245                 o,
10246                 'color',
10247                 1,
10248                 'easeIn', after);
10249         });
10250         return this;
10251     },
10252
10253    /**
10254     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10255     * Usage:
10256 <pre><code>
10257 // default: a single light blue ripple
10258 el.frame();
10259
10260 // custom: 3 red ripples lasting 3 seconds total
10261 el.frame("ff0000", 3, { duration: 3 });
10262
10263 // common config options shown with default values
10264 el.frame("C3DAF9", 1, {
10265     duration: 1 //duration of entire animation (not each individual ripple)
10266     // Note: Easing is not configurable and will be ignored if included
10267 });
10268 </code></pre>
10269     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10270     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10271     * @param {Object} options (optional) Object literal with any of the Fx config options
10272     * @return {Roo.Element} The Element
10273     */
10274     frame : function(color, count, o){
10275         var el = this.getFxEl();
10276         o = o || {};
10277
10278         el.queueFx(o, function(){
10279             color = color || "#C3DAF9";
10280             if(color.length == 6){
10281                 color = "#" + color;
10282             }
10283             count = count || 1;
10284             duration = o.duration || 1;
10285             this.show();
10286
10287             var b = this.getBox();
10288             var animFn = function(){
10289                 var proxy = this.createProxy({
10290
10291                      style:{
10292                         visbility:"hidden",
10293                         position:"absolute",
10294                         "z-index":"35000", // yee haw
10295                         border:"0px solid " + color
10296                      }
10297                   });
10298                 var scale = Roo.isBorderBox ? 2 : 1;
10299                 proxy.animate({
10300                     top:{from:b.y, to:b.y - 20},
10301                     left:{from:b.x, to:b.x - 20},
10302                     borderWidth:{from:0, to:10},
10303                     opacity:{from:1, to:0},
10304                     height:{from:b.height, to:(b.height + (20*scale))},
10305                     width:{from:b.width, to:(b.width + (20*scale))}
10306                 }, duration, function(){
10307                     proxy.remove();
10308                 });
10309                 if(--count > 0){
10310                      animFn.defer((duration/2)*1000, this);
10311                 }else{
10312                     el.afterFx(o);
10313                 }
10314             };
10315             animFn.call(this);
10316         });
10317         return this;
10318     },
10319
10320    /**
10321     * Creates a pause before any subsequent queued effects begin.  If there are
10322     * no effects queued after the pause it will have no effect.
10323     * Usage:
10324 <pre><code>
10325 el.pause(1);
10326 </code></pre>
10327     * @param {Number} seconds The length of time to pause (in seconds)
10328     * @return {Roo.Element} The Element
10329     */
10330     pause : function(seconds){
10331         var el = this.getFxEl();
10332         var o = {};
10333
10334         el.queueFx(o, function(){
10335             setTimeout(function(){
10336                 el.afterFx(o);
10337             }, seconds * 1000);
10338         });
10339         return this;
10340     },
10341
10342    /**
10343     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10344     * using the "endOpacity" config option.
10345     * Usage:
10346 <pre><code>
10347 // default: fade in from opacity 0 to 100%
10348 el.fadeIn();
10349
10350 // custom: fade in from opacity 0 to 75% over 2 seconds
10351 el.fadeIn({ endOpacity: .75, duration: 2});
10352
10353 // common config options shown with default values
10354 el.fadeIn({
10355     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10356     easing: 'easeOut',
10357     duration: .5
10358 });
10359 </code></pre>
10360     * @param {Object} options (optional) Object literal with any of the Fx config options
10361     * @return {Roo.Element} The Element
10362     */
10363     fadeIn : function(o){
10364         var el = this.getFxEl();
10365         o = o || {};
10366         el.queueFx(o, function(){
10367             this.setOpacity(0);
10368             this.fixDisplay();
10369             this.dom.style.visibility = 'visible';
10370             var to = o.endOpacity || 1;
10371             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10372                 o, null, .5, "easeOut", function(){
10373                 if(to == 1){
10374                     this.clearOpacity();
10375                 }
10376                 el.afterFx(o);
10377             });
10378         });
10379         return this;
10380     },
10381
10382    /**
10383     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10384     * using the "endOpacity" config option.
10385     * Usage:
10386 <pre><code>
10387 // default: fade out from the element's current opacity to 0
10388 el.fadeOut();
10389
10390 // custom: fade out from the element's current opacity to 25% over 2 seconds
10391 el.fadeOut({ endOpacity: .25, duration: 2});
10392
10393 // common config options shown with default values
10394 el.fadeOut({
10395     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10396     easing: 'easeOut',
10397     duration: .5
10398     remove: false,
10399     useDisplay: false
10400 });
10401 </code></pre>
10402     * @param {Object} options (optional) Object literal with any of the Fx config options
10403     * @return {Roo.Element} The Element
10404     */
10405     fadeOut : function(o){
10406         var el = this.getFxEl();
10407         o = o || {};
10408         el.queueFx(o, function(){
10409             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10410                 o, null, .5, "easeOut", function(){
10411                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10412                      this.dom.style.display = "none";
10413                 }else{
10414                      this.dom.style.visibility = "hidden";
10415                 }
10416                 this.clearOpacity();
10417                 el.afterFx(o);
10418             });
10419         });
10420         return this;
10421     },
10422
10423    /**
10424     * Animates the transition of an element's dimensions from a starting height/width
10425     * to an ending height/width.
10426     * Usage:
10427 <pre><code>
10428 // change height and width to 100x100 pixels
10429 el.scale(100, 100);
10430
10431 // common config options shown with default values.  The height and width will default to
10432 // the element's existing values if passed as null.
10433 el.scale(
10434     [element's width],
10435     [element's height], {
10436     easing: 'easeOut',
10437     duration: .35
10438 });
10439 </code></pre>
10440     * @param {Number} width  The new width (pass undefined to keep the original width)
10441     * @param {Number} height  The new height (pass undefined to keep the original height)
10442     * @param {Object} options (optional) Object literal with any of the Fx config options
10443     * @return {Roo.Element} The Element
10444     */
10445     scale : function(w, h, o){
10446         this.shift(Roo.apply({}, o, {
10447             width: w,
10448             height: h
10449         }));
10450         return this;
10451     },
10452
10453    /**
10454     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10455     * Any of these properties not specified in the config object will not be changed.  This effect 
10456     * requires that at least one new dimension, position or opacity setting must be passed in on
10457     * the config object in order for the function to have any effect.
10458     * Usage:
10459 <pre><code>
10460 // slide the element horizontally to x position 200 while changing the height and opacity
10461 el.shift({ x: 200, height: 50, opacity: .8 });
10462
10463 // common config options shown with default values.
10464 el.shift({
10465     width: [element's width],
10466     height: [element's height],
10467     x: [element's x position],
10468     y: [element's y position],
10469     opacity: [element's opacity],
10470     easing: 'easeOut',
10471     duration: .35
10472 });
10473 </code></pre>
10474     * @param {Object} options  Object literal with any of the Fx config options
10475     * @return {Roo.Element} The Element
10476     */
10477     shift : function(o){
10478         var el = this.getFxEl();
10479         o = o || {};
10480         el.queueFx(o, function(){
10481             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10482             if(w !== undefined){
10483                 a.width = {to: this.adjustWidth(w)};
10484             }
10485             if(h !== undefined){
10486                 a.height = {to: this.adjustHeight(h)};
10487             }
10488             if(x !== undefined || y !== undefined){
10489                 a.points = {to: [
10490                     x !== undefined ? x : this.getX(),
10491                     y !== undefined ? y : this.getY()
10492                 ]};
10493             }
10494             if(op !== undefined){
10495                 a.opacity = {to: op};
10496             }
10497             if(o.xy !== undefined){
10498                 a.points = {to: o.xy};
10499             }
10500             arguments.callee.anim = this.fxanim(a,
10501                 o, 'motion', .35, "easeOut", function(){
10502                 el.afterFx(o);
10503             });
10504         });
10505         return this;
10506     },
10507
10508         /**
10509          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10510          * ending point of the effect.
10511          * Usage:
10512          *<pre><code>
10513 // default: slide the element downward while fading out
10514 el.ghost();
10515
10516 // custom: slide the element out to the right with a 2-second duration
10517 el.ghost('r', { duration: 2 });
10518
10519 // common config options shown with default values
10520 el.ghost('b', {
10521     easing: 'easeOut',
10522     duration: .5
10523     remove: false,
10524     useDisplay: false
10525 });
10526 </code></pre>
10527          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10528          * @param {Object} options (optional) Object literal with any of the Fx config options
10529          * @return {Roo.Element} The Element
10530          */
10531     ghost : function(anchor, o){
10532         var el = this.getFxEl();
10533         o = o || {};
10534
10535         el.queueFx(o, function(){
10536             anchor = anchor || "b";
10537
10538             // restore values after effect
10539             var r = this.getFxRestore();
10540             var w = this.getWidth(),
10541                 h = this.getHeight();
10542
10543             var st = this.dom.style;
10544
10545             var after = function(){
10546                 if(o.useDisplay){
10547                     el.setDisplayed(false);
10548                 }else{
10549                     el.hide();
10550                 }
10551
10552                 el.clearOpacity();
10553                 el.setPositioning(r.pos);
10554                 st.width = r.width;
10555                 st.height = r.height;
10556
10557                 el.afterFx(o);
10558             };
10559
10560             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10561             switch(anchor.toLowerCase()){
10562                 case "t":
10563                     pt.by = [0, -h];
10564                 break;
10565                 case "l":
10566                     pt.by = [-w, 0];
10567                 break;
10568                 case "r":
10569                     pt.by = [w, 0];
10570                 break;
10571                 case "b":
10572                     pt.by = [0, h];
10573                 break;
10574                 case "tl":
10575                     pt.by = [-w, -h];
10576                 break;
10577                 case "bl":
10578                     pt.by = [-w, h];
10579                 break;
10580                 case "br":
10581                     pt.by = [w, h];
10582                 break;
10583                 case "tr":
10584                     pt.by = [w, -h];
10585                 break;
10586             }
10587
10588             arguments.callee.anim = this.fxanim(a,
10589                 o,
10590                 'motion',
10591                 .5,
10592                 "easeOut", after);
10593         });
10594         return this;
10595     },
10596
10597         /**
10598          * Ensures that all effects queued after syncFx is called on the element are
10599          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10600          * @return {Roo.Element} The Element
10601          */
10602     syncFx : function(){
10603         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10604             block : false,
10605             concurrent : true,
10606             stopFx : false
10607         });
10608         return this;
10609     },
10610
10611         /**
10612          * Ensures that all effects queued after sequenceFx is called on the element are
10613          * run in sequence.  This is the opposite of {@link #syncFx}.
10614          * @return {Roo.Element} The Element
10615          */
10616     sequenceFx : function(){
10617         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10618             block : false,
10619             concurrent : false,
10620             stopFx : false
10621         });
10622         return this;
10623     },
10624
10625         /* @private */
10626     nextFx : function(){
10627         var ef = this.fxQueue[0];
10628         if(ef){
10629             ef.call(this);
10630         }
10631     },
10632
10633         /**
10634          * Returns true if the element has any effects actively running or queued, else returns false.
10635          * @return {Boolean} True if element has active effects, else false
10636          */
10637     hasActiveFx : function(){
10638         return this.fxQueue && this.fxQueue[0];
10639     },
10640
10641         /**
10642          * Stops any running effects and clears the element's internal effects queue if it contains
10643          * any additional effects that haven't started yet.
10644          * @return {Roo.Element} The Element
10645          */
10646     stopFx : function(){
10647         if(this.hasActiveFx()){
10648             var cur = this.fxQueue[0];
10649             if(cur && cur.anim && cur.anim.isAnimated()){
10650                 this.fxQueue = [cur]; // clear out others
10651                 cur.anim.stop(true);
10652             }
10653         }
10654         return this;
10655     },
10656
10657         /* @private */
10658     beforeFx : function(o){
10659         if(this.hasActiveFx() && !o.concurrent){
10660            if(o.stopFx){
10661                this.stopFx();
10662                return true;
10663            }
10664            return false;
10665         }
10666         return true;
10667     },
10668
10669         /**
10670          * Returns true if the element is currently blocking so that no other effect can be queued
10671          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10672          * used to ensure that an effect initiated by a user action runs to completion prior to the
10673          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10674          * @return {Boolean} True if blocking, else false
10675          */
10676     hasFxBlock : function(){
10677         var q = this.fxQueue;
10678         return q && q[0] && q[0].block;
10679     },
10680
10681         /* @private */
10682     queueFx : function(o, fn){
10683         if(!this.fxQueue){
10684             this.fxQueue = [];
10685         }
10686         if(!this.hasFxBlock()){
10687             Roo.applyIf(o, this.fxDefaults);
10688             if(!o.concurrent){
10689                 var run = this.beforeFx(o);
10690                 fn.block = o.block;
10691                 this.fxQueue.push(fn);
10692                 if(run){
10693                     this.nextFx();
10694                 }
10695             }else{
10696                 fn.call(this);
10697             }
10698         }
10699         return this;
10700     },
10701
10702         /* @private */
10703     fxWrap : function(pos, o, vis){
10704         var wrap;
10705         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10706             var wrapXY;
10707             if(o.fixPosition){
10708                 wrapXY = this.getXY();
10709             }
10710             var div = document.createElement("div");
10711             div.style.visibility = vis;
10712             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10713             wrap.setPositioning(pos);
10714             if(wrap.getStyle("position") == "static"){
10715                 wrap.position("relative");
10716             }
10717             this.clearPositioning('auto');
10718             wrap.clip();
10719             wrap.dom.appendChild(this.dom);
10720             if(wrapXY){
10721                 wrap.setXY(wrapXY);
10722             }
10723         }
10724         return wrap;
10725     },
10726
10727         /* @private */
10728     fxUnwrap : function(wrap, pos, o){
10729         this.clearPositioning();
10730         this.setPositioning(pos);
10731         if(!o.wrap){
10732             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10733             wrap.remove();
10734         }
10735     },
10736
10737         /* @private */
10738     getFxRestore : function(){
10739         var st = this.dom.style;
10740         return {pos: this.getPositioning(), width: st.width, height : st.height};
10741     },
10742
10743         /* @private */
10744     afterFx : function(o){
10745         if(o.afterStyle){
10746             this.applyStyles(o.afterStyle);
10747         }
10748         if(o.afterCls){
10749             this.addClass(o.afterCls);
10750         }
10751         if(o.remove === true){
10752             this.remove();
10753         }
10754         Roo.callback(o.callback, o.scope, [this]);
10755         if(!o.concurrent){
10756             this.fxQueue.shift();
10757             this.nextFx();
10758         }
10759     },
10760
10761         /* @private */
10762     getFxEl : function(){ // support for composite element fx
10763         return Roo.get(this.dom);
10764     },
10765
10766         /* @private */
10767     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10768         animType = animType || 'run';
10769         opt = opt || {};
10770         var anim = Roo.lib.Anim[animType](
10771             this.dom, args,
10772             (opt.duration || defaultDur) || .35,
10773             (opt.easing || defaultEase) || 'easeOut',
10774             function(){
10775                 Roo.callback(cb, this);
10776             },
10777             this
10778         );
10779         opt.anim = anim;
10780         return anim;
10781     }
10782 };
10783
10784 // backwords compat
10785 Roo.Fx.resize = Roo.Fx.scale;
10786
10787 //When included, Roo.Fx is automatically applied to Element so that all basic
10788 //effects are available directly via the Element API
10789 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10790  * Based on:
10791  * Ext JS Library 1.1.1
10792  * Copyright(c) 2006-2007, Ext JS, LLC.
10793  *
10794  * Originally Released Under LGPL - original licence link has changed is not relivant.
10795  *
10796  * Fork - LGPL
10797  * <script type="text/javascript">
10798  */
10799
10800
10801 /**
10802  * @class Roo.CompositeElement
10803  * Standard composite class. Creates a Roo.Element for every element in the collection.
10804  * <br><br>
10805  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10806  * actions will be performed on all the elements in this collection.</b>
10807  * <br><br>
10808  * All methods return <i>this</i> and can be chained.
10809  <pre><code>
10810  var els = Roo.select("#some-el div.some-class", true);
10811  // or select directly from an existing element
10812  var el = Roo.get('some-el');
10813  el.select('div.some-class', true);
10814
10815  els.setWidth(100); // all elements become 100 width
10816  els.hide(true); // all elements fade out and hide
10817  // or
10818  els.setWidth(100).hide(true);
10819  </code></pre>
10820  */
10821 Roo.CompositeElement = function(els){
10822     this.elements = [];
10823     this.addElements(els);
10824 };
10825 Roo.CompositeElement.prototype = {
10826     isComposite: true,
10827     addElements : function(els){
10828         if(!els) return this;
10829         if(typeof els == "string"){
10830             els = Roo.Element.selectorFunction(els);
10831         }
10832         var yels = this.elements;
10833         var index = yels.length-1;
10834         for(var i = 0, len = els.length; i < len; i++) {
10835                 yels[++index] = Roo.get(els[i]);
10836         }
10837         return this;
10838     },
10839
10840     /**
10841     * Clears this composite and adds the elements returned by the passed selector.
10842     * @param {String/Array} els A string CSS selector, an array of elements or an element
10843     * @return {CompositeElement} this
10844     */
10845     fill : function(els){
10846         this.elements = [];
10847         this.add(els);
10848         return this;
10849     },
10850
10851     /**
10852     * Filters this composite to only elements that match the passed selector.
10853     * @param {String} selector A string CSS selector
10854     * @return {CompositeElement} this
10855     */
10856     filter : function(selector){
10857         var els = [];
10858         this.each(function(el){
10859             if(el.is(selector)){
10860                 els[els.length] = el.dom;
10861             }
10862         });
10863         this.fill(els);
10864         return this;
10865     },
10866
10867     invoke : function(fn, args){
10868         var els = this.elements;
10869         for(var i = 0, len = els.length; i < len; i++) {
10870                 Roo.Element.prototype[fn].apply(els[i], args);
10871         }
10872         return this;
10873     },
10874     /**
10875     * Adds elements to this composite.
10876     * @param {String/Array} els A string CSS selector, an array of elements or an element
10877     * @return {CompositeElement} this
10878     */
10879     add : function(els){
10880         if(typeof els == "string"){
10881             this.addElements(Roo.Element.selectorFunction(els));
10882         }else if(els.length !== undefined){
10883             this.addElements(els);
10884         }else{
10885             this.addElements([els]);
10886         }
10887         return this;
10888     },
10889     /**
10890     * Calls the passed function passing (el, this, index) for each element in this composite.
10891     * @param {Function} fn The function to call
10892     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10893     * @return {CompositeElement} this
10894     */
10895     each : function(fn, scope){
10896         var els = this.elements;
10897         for(var i = 0, len = els.length; i < len; i++){
10898             if(fn.call(scope || els[i], els[i], this, i) === false) {
10899                 break;
10900             }
10901         }
10902         return this;
10903     },
10904
10905     /**
10906      * Returns the Element object at the specified index
10907      * @param {Number} index
10908      * @return {Roo.Element}
10909      */
10910     item : function(index){
10911         return this.elements[index] || null;
10912     },
10913
10914     /**
10915      * Returns the first Element
10916      * @return {Roo.Element}
10917      */
10918     first : function(){
10919         return this.item(0);
10920     },
10921
10922     /**
10923      * Returns the last Element
10924      * @return {Roo.Element}
10925      */
10926     last : function(){
10927         return this.item(this.elements.length-1);
10928     },
10929
10930     /**
10931      * Returns the number of elements in this composite
10932      * @return Number
10933      */
10934     getCount : function(){
10935         return this.elements.length;
10936     },
10937
10938     /**
10939      * Returns true if this composite contains the passed element
10940      * @return Boolean
10941      */
10942     contains : function(el){
10943         return this.indexOf(el) !== -1;
10944     },
10945
10946     /**
10947      * Returns true if this composite contains the passed element
10948      * @return Boolean
10949      */
10950     indexOf : function(el){
10951         return this.elements.indexOf(Roo.get(el));
10952     },
10953
10954
10955     /**
10956     * Removes the specified element(s).
10957     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10958     * or an array of any of those.
10959     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10960     * @return {CompositeElement} this
10961     */
10962     removeElement : function(el, removeDom){
10963         if(el instanceof Array){
10964             for(var i = 0, len = el.length; i < len; i++){
10965                 this.removeElement(el[i]);
10966             }
10967             return this;
10968         }
10969         var index = typeof el == 'number' ? el : this.indexOf(el);
10970         if(index !== -1){
10971             if(removeDom){
10972                 var d = this.elements[index];
10973                 if(d.dom){
10974                     d.remove();
10975                 }else{
10976                     d.parentNode.removeChild(d);
10977                 }
10978             }
10979             this.elements.splice(index, 1);
10980         }
10981         return this;
10982     },
10983
10984     /**
10985     * Replaces the specified element with the passed element.
10986     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10987     * to replace.
10988     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10989     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10990     * @return {CompositeElement} this
10991     */
10992     replaceElement : function(el, replacement, domReplace){
10993         var index = typeof el == 'number' ? el : this.indexOf(el);
10994         if(index !== -1){
10995             if(domReplace){
10996                 this.elements[index].replaceWith(replacement);
10997             }else{
10998                 this.elements.splice(index, 1, Roo.get(replacement))
10999             }
11000         }
11001         return this;
11002     },
11003
11004     /**
11005      * Removes all elements.
11006      */
11007     clear : function(){
11008         this.elements = [];
11009     }
11010 };
11011 (function(){
11012     Roo.CompositeElement.createCall = function(proto, fnName){
11013         if(!proto[fnName]){
11014             proto[fnName] = function(){
11015                 return this.invoke(fnName, arguments);
11016             };
11017         }
11018     };
11019     for(var fnName in Roo.Element.prototype){
11020         if(typeof Roo.Element.prototype[fnName] == "function"){
11021             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11022         }
11023     };
11024 })();
11025 /*
11026  * Based on:
11027  * Ext JS Library 1.1.1
11028  * Copyright(c) 2006-2007, Ext JS, LLC.
11029  *
11030  * Originally Released Under LGPL - original licence link has changed is not relivant.
11031  *
11032  * Fork - LGPL
11033  * <script type="text/javascript">
11034  */
11035
11036 /**
11037  * @class Roo.CompositeElementLite
11038  * @extends Roo.CompositeElement
11039  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11040  <pre><code>
11041  var els = Roo.select("#some-el div.some-class");
11042  // or select directly from an existing element
11043  var el = Roo.get('some-el');
11044  el.select('div.some-class');
11045
11046  els.setWidth(100); // all elements become 100 width
11047  els.hide(true); // all elements fade out and hide
11048  // or
11049  els.setWidth(100).hide(true);
11050  </code></pre><br><br>
11051  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11052  * actions will be performed on all the elements in this collection.</b>
11053  */
11054 Roo.CompositeElementLite = function(els){
11055     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11056     this.el = new Roo.Element.Flyweight();
11057 };
11058 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11059     addElements : function(els){
11060         if(els){
11061             if(els instanceof Array){
11062                 this.elements = this.elements.concat(els);
11063             }else{
11064                 var yels = this.elements;
11065                 var index = yels.length-1;
11066                 for(var i = 0, len = els.length; i < len; i++) {
11067                     yels[++index] = els[i];
11068                 }
11069             }
11070         }
11071         return this;
11072     },
11073     invoke : function(fn, args){
11074         var els = this.elements;
11075         var el = this.el;
11076         for(var i = 0, len = els.length; i < len; i++) {
11077             el.dom = els[i];
11078                 Roo.Element.prototype[fn].apply(el, args);
11079         }
11080         return this;
11081     },
11082     /**
11083      * Returns a flyweight Element of the dom element object at the specified index
11084      * @param {Number} index
11085      * @return {Roo.Element}
11086      */
11087     item : function(index){
11088         if(!this.elements[index]){
11089             return null;
11090         }
11091         this.el.dom = this.elements[index];
11092         return this.el;
11093     },
11094
11095     // fixes scope with flyweight
11096     addListener : function(eventName, handler, scope, opt){
11097         var els = this.elements;
11098         for(var i = 0, len = els.length; i < len; i++) {
11099             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11100         }
11101         return this;
11102     },
11103
11104     /**
11105     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11106     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11107     * a reference to the dom node, use el.dom.</b>
11108     * @param {Function} fn The function to call
11109     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11110     * @return {CompositeElement} this
11111     */
11112     each : function(fn, scope){
11113         var els = this.elements;
11114         var el = this.el;
11115         for(var i = 0, len = els.length; i < len; i++){
11116             el.dom = els[i];
11117                 if(fn.call(scope || el, el, this, i) === false){
11118                 break;
11119             }
11120         }
11121         return this;
11122     },
11123
11124     indexOf : function(el){
11125         return this.elements.indexOf(Roo.getDom(el));
11126     },
11127
11128     replaceElement : function(el, replacement, domReplace){
11129         var index = typeof el == 'number' ? el : this.indexOf(el);
11130         if(index !== -1){
11131             replacement = Roo.getDom(replacement);
11132             if(domReplace){
11133                 var d = this.elements[index];
11134                 d.parentNode.insertBefore(replacement, d);
11135                 d.parentNode.removeChild(d);
11136             }
11137             this.elements.splice(index, 1, replacement);
11138         }
11139         return this;
11140     }
11141 });
11142 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11143
11144 /*
11145  * Based on:
11146  * Ext JS Library 1.1.1
11147  * Copyright(c) 2006-2007, Ext JS, LLC.
11148  *
11149  * Originally Released Under LGPL - original licence link has changed is not relivant.
11150  *
11151  * Fork - LGPL
11152  * <script type="text/javascript">
11153  */
11154
11155  
11156
11157 /**
11158  * @class Roo.data.Connection
11159  * @extends Roo.util.Observable
11160  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11161  * either to a configured URL, or to a URL specified at request time.<br><br>
11162  * <p>
11163  * Requests made by this class are asynchronous, and will return immediately. No data from
11164  * the server will be available to the statement immediately following the {@link #request} call.
11165  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11166  * <p>
11167  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11168  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11169  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11170  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11171  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11172  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11173  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11174  * standard DOM methods.
11175  * @constructor
11176  * @param {Object} config a configuration object.
11177  */
11178 Roo.data.Connection = function(config){
11179     Roo.apply(this, config);
11180     this.addEvents({
11181         /**
11182          * @event beforerequest
11183          * Fires before a network request is made to retrieve a data object.
11184          * @param {Connection} conn This Connection object.
11185          * @param {Object} options The options config object passed to the {@link #request} method.
11186          */
11187         "beforerequest" : true,
11188         /**
11189          * @event requestcomplete
11190          * Fires if the request was successfully completed.
11191          * @param {Connection} conn This Connection object.
11192          * @param {Object} response The XHR object containing the response data.
11193          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11194          * @param {Object} options The options config object passed to the {@link #request} method.
11195          */
11196         "requestcomplete" : true,
11197         /**
11198          * @event requestexception
11199          * Fires if an error HTTP status was returned from the server.
11200          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11201          * @param {Connection} conn This Connection object.
11202          * @param {Object} response The XHR object containing the response data.
11203          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11204          * @param {Object} options The options config object passed to the {@link #request} method.
11205          */
11206         "requestexception" : true
11207     });
11208     Roo.data.Connection.superclass.constructor.call(this);
11209 };
11210
11211 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11212     /**
11213      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11214      */
11215     /**
11216      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11217      * extra parameters to each request made by this object. (defaults to undefined)
11218      */
11219     /**
11220      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11221      *  to each request made by this object. (defaults to undefined)
11222      */
11223     /**
11224      * @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)
11225      */
11226     /**
11227      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11228      */
11229     timeout : 30000,
11230     /**
11231      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11232      * @type Boolean
11233      */
11234     autoAbort:false,
11235
11236     /**
11237      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11238      * @type Boolean
11239      */
11240     disableCaching: true,
11241
11242     /**
11243      * Sends an HTTP request to a remote server.
11244      * @param {Object} options An object which may contain the following properties:<ul>
11245      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11246      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11247      * request, a url encoded string or a function to call to get either.</li>
11248      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11249      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11250      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11251      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11252      * <li>options {Object} The parameter to the request call.</li>
11253      * <li>success {Boolean} True if the request succeeded.</li>
11254      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11255      * </ul></li>
11256      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11257      * The callback is passed the following parameters:<ul>
11258      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11259      * <li>options {Object} The parameter to the request call.</li>
11260      * </ul></li>
11261      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11262      * The callback is passed the following parameters:<ul>
11263      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11264      * <li>options {Object} The parameter to the request call.</li>
11265      * </ul></li>
11266      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11267      * for the callback function. Defaults to the browser window.</li>
11268      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11269      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11270      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11271      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11272      * params for the post data. Any params will be appended to the URL.</li>
11273      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11274      * </ul>
11275      * @return {Number} transactionId
11276      */
11277     request : function(o){
11278         if(this.fireEvent("beforerequest", this, o) !== false){
11279             var p = o.params;
11280
11281             if(typeof p == "function"){
11282                 p = p.call(o.scope||window, o);
11283             }
11284             if(typeof p == "object"){
11285                 p = Roo.urlEncode(o.params);
11286             }
11287             if(this.extraParams){
11288                 var extras = Roo.urlEncode(this.extraParams);
11289                 p = p ? (p + '&' + extras) : extras;
11290             }
11291
11292             var url = o.url || this.url;
11293             if(typeof url == 'function'){
11294                 url = url.call(o.scope||window, o);
11295             }
11296
11297             if(o.form){
11298                 var form = Roo.getDom(o.form);
11299                 url = url || form.action;
11300
11301                 var enctype = form.getAttribute("enctype");
11302                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11303                     return this.doFormUpload(o, p, url);
11304                 }
11305                 var f = Roo.lib.Ajax.serializeForm(form);
11306                 p = p ? (p + '&' + f) : f;
11307             }
11308
11309             var hs = o.headers;
11310             if(this.defaultHeaders){
11311                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11312                 if(!o.headers){
11313                     o.headers = hs;
11314                 }
11315             }
11316
11317             var cb = {
11318                 success: this.handleResponse,
11319                 failure: this.handleFailure,
11320                 scope: this,
11321                 argument: {options: o},
11322                 timeout : this.timeout
11323             };
11324
11325             var method = o.method||this.method||(p ? "POST" : "GET");
11326
11327             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11328                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11329             }
11330
11331             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11332                 if(o.autoAbort){
11333                     this.abort();
11334                 }
11335             }else if(this.autoAbort !== false){
11336                 this.abort();
11337             }
11338
11339             if((method == 'GET' && p) || o.xmlData){
11340                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11341                 p = '';
11342             }
11343             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11344             return this.transId;
11345         }else{
11346             Roo.callback(o.callback, o.scope, [o, null, null]);
11347             return null;
11348         }
11349     },
11350
11351     /**
11352      * Determine whether this object has a request outstanding.
11353      * @param {Number} transactionId (Optional) defaults to the last transaction
11354      * @return {Boolean} True if there is an outstanding request.
11355      */
11356     isLoading : function(transId){
11357         if(transId){
11358             return Roo.lib.Ajax.isCallInProgress(transId);
11359         }else{
11360             return this.transId ? true : false;
11361         }
11362     },
11363
11364     /**
11365      * Aborts any outstanding request.
11366      * @param {Number} transactionId (Optional) defaults to the last transaction
11367      */
11368     abort : function(transId){
11369         if(transId || this.isLoading()){
11370             Roo.lib.Ajax.abort(transId || this.transId);
11371         }
11372     },
11373
11374     // private
11375     handleResponse : function(response){
11376         this.transId = false;
11377         var options = response.argument.options;
11378         response.argument = options ? options.argument : null;
11379         this.fireEvent("requestcomplete", this, response, options);
11380         Roo.callback(options.success, options.scope, [response, options]);
11381         Roo.callback(options.callback, options.scope, [options, true, response]);
11382     },
11383
11384     // private
11385     handleFailure : function(response, e){
11386         this.transId = false;
11387         var options = response.argument.options;
11388         response.argument = options ? options.argument : null;
11389         this.fireEvent("requestexception", this, response, options, e);
11390         Roo.callback(options.failure, options.scope, [response, options]);
11391         Roo.callback(options.callback, options.scope, [options, false, response]);
11392     },
11393
11394     // private
11395     doFormUpload : function(o, ps, url){
11396         var id = Roo.id();
11397         var frame = document.createElement('iframe');
11398         frame.id = id;
11399         frame.name = id;
11400         frame.className = 'x-hidden';
11401         if(Roo.isIE){
11402             frame.src = Roo.SSL_SECURE_URL;
11403         }
11404         document.body.appendChild(frame);
11405
11406         if(Roo.isIE){
11407            document.frames[id].name = id;
11408         }
11409
11410         var form = Roo.getDom(o.form);
11411         form.target = id;
11412         form.method = 'POST';
11413         form.enctype = form.encoding = 'multipart/form-data';
11414         if(url){
11415             form.action = url;
11416         }
11417
11418         var hiddens, hd;
11419         if(ps){ // add dynamic params
11420             hiddens = [];
11421             ps = Roo.urlDecode(ps, false);
11422             for(var k in ps){
11423                 if(ps.hasOwnProperty(k)){
11424                     hd = document.createElement('input');
11425                     hd.type = 'hidden';
11426                     hd.name = k;
11427                     hd.value = ps[k];
11428                     form.appendChild(hd);
11429                     hiddens.push(hd);
11430                 }
11431             }
11432         }
11433
11434         function cb(){
11435             var r = {  // bogus response object
11436                 responseText : '',
11437                 responseXML : null
11438             };
11439
11440             r.argument = o ? o.argument : null;
11441
11442             try { //
11443                 var doc;
11444                 if(Roo.isIE){
11445                     doc = frame.contentWindow.document;
11446                 }else {
11447                     doc = (frame.contentDocument || window.frames[id].document);
11448                 }
11449                 if(doc && doc.body){
11450                     r.responseText = doc.body.innerHTML;
11451                 }
11452                 if(doc && doc.XMLDocument){
11453                     r.responseXML = doc.XMLDocument;
11454                 }else {
11455                     r.responseXML = doc;
11456                 }
11457             }
11458             catch(e) {
11459                 // ignore
11460             }
11461
11462             Roo.EventManager.removeListener(frame, 'load', cb, this);
11463
11464             this.fireEvent("requestcomplete", this, r, o);
11465             Roo.callback(o.success, o.scope, [r, o]);
11466             Roo.callback(o.callback, o.scope, [o, true, r]);
11467
11468             setTimeout(function(){document.body.removeChild(frame);}, 100);
11469         }
11470
11471         Roo.EventManager.on(frame, 'load', cb, this);
11472         form.submit();
11473
11474         if(hiddens){ // remove dynamic params
11475             for(var i = 0, len = hiddens.length; i < len; i++){
11476                 form.removeChild(hiddens[i]);
11477             }
11478         }
11479     }
11480 });
11481
11482 /**
11483  * @class Roo.Ajax
11484  * @extends Roo.data.Connection
11485  * Global Ajax request class.
11486  *
11487  * @singleton
11488  */
11489 Roo.Ajax = new Roo.data.Connection({
11490     // fix up the docs
11491    /**
11492      * @cfg {String} url @hide
11493      */
11494     /**
11495      * @cfg {Object} extraParams @hide
11496      */
11497     /**
11498      * @cfg {Object} defaultHeaders @hide
11499      */
11500     /**
11501      * @cfg {String} method (Optional) @hide
11502      */
11503     /**
11504      * @cfg {Number} timeout (Optional) @hide
11505      */
11506     /**
11507      * @cfg {Boolean} autoAbort (Optional) @hide
11508      */
11509
11510     /**
11511      * @cfg {Boolean} disableCaching (Optional) @hide
11512      */
11513
11514     /**
11515      * @property  disableCaching
11516      * True to add a unique cache-buster param to GET requests. (defaults to true)
11517      * @type Boolean
11518      */
11519     /**
11520      * @property  url
11521      * The default URL to be used for requests to the server. (defaults to undefined)
11522      * @type String
11523      */
11524     /**
11525      * @property  extraParams
11526      * An object containing properties which are used as
11527      * extra parameters to each request made by this object. (defaults to undefined)
11528      * @type Object
11529      */
11530     /**
11531      * @property  defaultHeaders
11532      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11533      * @type Object
11534      */
11535     /**
11536      * @property  method
11537      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11538      * @type String
11539      */
11540     /**
11541      * @property  timeout
11542      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11543      * @type Number
11544      */
11545
11546     /**
11547      * @property  autoAbort
11548      * Whether a new request should abort any pending requests. (defaults to false)
11549      * @type Boolean
11550      */
11551     autoAbort : false,
11552
11553     /**
11554      * Serialize the passed form into a url encoded string
11555      * @param {String/HTMLElement} form
11556      * @return {String}
11557      */
11558     serializeForm : function(form){
11559         return Roo.lib.Ajax.serializeForm(form);
11560     }
11561 });/*
11562  * Based on:
11563  * Ext JS Library 1.1.1
11564  * Copyright(c) 2006-2007, Ext JS, LLC.
11565  *
11566  * Originally Released Under LGPL - original licence link has changed is not relivant.
11567  *
11568  * Fork - LGPL
11569  * <script type="text/javascript">
11570  */
11571  
11572 /**
11573  * Global Ajax request class.
11574  * 
11575  * @class Roo.Ajax
11576  * @extends Roo.data.Connection
11577  * @static
11578  * 
11579  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11580  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11581  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11582  * @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)
11583  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11584  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11585  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11586  */
11587 Roo.Ajax = new Roo.data.Connection({
11588     // fix up the docs
11589     /**
11590      * @scope Roo.Ajax
11591      * @type {Boolear} 
11592      */
11593     autoAbort : false,
11594
11595     /**
11596      * Serialize the passed form into a url encoded string
11597      * @scope Roo.Ajax
11598      * @param {String/HTMLElement} form
11599      * @return {String}
11600      */
11601     serializeForm : function(form){
11602         return Roo.lib.Ajax.serializeForm(form);
11603     }
11604 });/*
11605  * Based on:
11606  * Ext JS Library 1.1.1
11607  * Copyright(c) 2006-2007, Ext JS, LLC.
11608  *
11609  * Originally Released Under LGPL - original licence link has changed is not relivant.
11610  *
11611  * Fork - LGPL
11612  * <script type="text/javascript">
11613  */
11614
11615  
11616 /**
11617  * @class Roo.UpdateManager
11618  * @extends Roo.util.Observable
11619  * Provides AJAX-style update for Element object.<br><br>
11620  * Usage:<br>
11621  * <pre><code>
11622  * // Get it from a Roo.Element object
11623  * var el = Roo.get("foo");
11624  * var mgr = el.getUpdateManager();
11625  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11626  * ...
11627  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11628  * <br>
11629  * // or directly (returns the same UpdateManager instance)
11630  * var mgr = new Roo.UpdateManager("myElementId");
11631  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11632  * mgr.on("update", myFcnNeedsToKnow);
11633  * <br>
11634    // short handed call directly from the element object
11635    Roo.get("foo").load({
11636         url: "bar.php",
11637         scripts:true,
11638         params: "for=bar",
11639         text: "Loading Foo..."
11640    });
11641  * </code></pre>
11642  * @constructor
11643  * Create new UpdateManager directly.
11644  * @param {String/HTMLElement/Roo.Element} el The element to update
11645  * @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).
11646  */
11647 Roo.UpdateManager = function(el, forceNew){
11648     el = Roo.get(el);
11649     if(!forceNew && el.updateManager){
11650         return el.updateManager;
11651     }
11652     /**
11653      * The Element object
11654      * @type Roo.Element
11655      */
11656     this.el = el;
11657     /**
11658      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11659      * @type String
11660      */
11661     this.defaultUrl = null;
11662
11663     this.addEvents({
11664         /**
11665          * @event beforeupdate
11666          * Fired before an update is made, return false from your handler and the update is cancelled.
11667          * @param {Roo.Element} el
11668          * @param {String/Object/Function} url
11669          * @param {String/Object} params
11670          */
11671         "beforeupdate": true,
11672         /**
11673          * @event update
11674          * Fired after successful update is made.
11675          * @param {Roo.Element} el
11676          * @param {Object} oResponseObject The response Object
11677          */
11678         "update": true,
11679         /**
11680          * @event failure
11681          * Fired on update failure.
11682          * @param {Roo.Element} el
11683          * @param {Object} oResponseObject The response Object
11684          */
11685         "failure": true
11686     });
11687     var d = Roo.UpdateManager.defaults;
11688     /**
11689      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11690      * @type String
11691      */
11692     this.sslBlankUrl = d.sslBlankUrl;
11693     /**
11694      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11695      * @type Boolean
11696      */
11697     this.disableCaching = d.disableCaching;
11698     /**
11699      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11700      * @type String
11701      */
11702     this.indicatorText = d.indicatorText;
11703     /**
11704      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11705      * @type String
11706      */
11707     this.showLoadIndicator = d.showLoadIndicator;
11708     /**
11709      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11710      * @type Number
11711      */
11712     this.timeout = d.timeout;
11713
11714     /**
11715      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11716      * @type Boolean
11717      */
11718     this.loadScripts = d.loadScripts;
11719
11720     /**
11721      * Transaction object of current executing transaction
11722      */
11723     this.transaction = null;
11724
11725     /**
11726      * @private
11727      */
11728     this.autoRefreshProcId = null;
11729     /**
11730      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11731      * @type Function
11732      */
11733     this.refreshDelegate = this.refresh.createDelegate(this);
11734     /**
11735      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11736      * @type Function
11737      */
11738     this.updateDelegate = this.update.createDelegate(this);
11739     /**
11740      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11741      * @type Function
11742      */
11743     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11744     /**
11745      * @private
11746      */
11747     this.successDelegate = this.processSuccess.createDelegate(this);
11748     /**
11749      * @private
11750      */
11751     this.failureDelegate = this.processFailure.createDelegate(this);
11752
11753     if(!this.renderer){
11754      /**
11755       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11756       */
11757     this.renderer = new Roo.UpdateManager.BasicRenderer();
11758     }
11759     
11760     Roo.UpdateManager.superclass.constructor.call(this);
11761 };
11762
11763 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11764     /**
11765      * Get the Element this UpdateManager is bound to
11766      * @return {Roo.Element} The element
11767      */
11768     getEl : function(){
11769         return this.el;
11770     },
11771     /**
11772      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11773      * @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:
11774 <pre><code>
11775 um.update({<br/>
11776     url: "your-url.php",<br/>
11777     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11778     callback: yourFunction,<br/>
11779     scope: yourObject, //(optional scope)  <br/>
11780     discardUrl: false, <br/>
11781     nocache: false,<br/>
11782     text: "Loading...",<br/>
11783     timeout: 30,<br/>
11784     scripts: false<br/>
11785 });
11786 </code></pre>
11787      * The only required property is url. The optional properties nocache, text and scripts
11788      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11789      * @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}
11790      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11791      * @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.
11792      */
11793     update : function(url, params, callback, discardUrl){
11794         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11795             var method = this.method, cfg;
11796             if(typeof url == "object"){ // must be config object
11797                 cfg = url;
11798                 url = cfg.url;
11799                 params = params || cfg.params;
11800                 callback = callback || cfg.callback;
11801                 discardUrl = discardUrl || cfg.discardUrl;
11802                 if(callback && cfg.scope){
11803                     callback = callback.createDelegate(cfg.scope);
11804                 }
11805                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11806                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11807                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11808                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11809                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11810             }
11811             this.showLoading();
11812             if(!discardUrl){
11813                 this.defaultUrl = url;
11814             }
11815             if(typeof url == "function"){
11816                 url = url.call(this);
11817             }
11818
11819             method = method || (params ? "POST" : "GET");
11820             if(method == "GET"){
11821                 url = this.prepareUrl(url);
11822             }
11823
11824             var o = Roo.apply(cfg ||{}, {
11825                 url : url,
11826                 params: params,
11827                 success: this.successDelegate,
11828                 failure: this.failureDelegate,
11829                 callback: undefined,
11830                 timeout: (this.timeout*1000),
11831                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11832             });
11833
11834             this.transaction = Roo.Ajax.request(o);
11835         }
11836     },
11837
11838     /**
11839      * 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.
11840      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11841      * @param {String/HTMLElement} form The form Id or form element
11842      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11843      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11844      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11845      */
11846     formUpdate : function(form, url, reset, callback){
11847         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11848             if(typeof url == "function"){
11849                 url = url.call(this);
11850             }
11851             form = Roo.getDom(form);
11852             this.transaction = Roo.Ajax.request({
11853                 form: form,
11854                 url:url,
11855                 success: this.successDelegate,
11856                 failure: this.failureDelegate,
11857                 timeout: (this.timeout*1000),
11858                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11859             });
11860             this.showLoading.defer(1, this);
11861         }
11862     },
11863
11864     /**
11865      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11866      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11867      */
11868     refresh : function(callback){
11869         if(this.defaultUrl == null){
11870             return;
11871         }
11872         this.update(this.defaultUrl, null, callback, true);
11873     },
11874
11875     /**
11876      * Set this element to auto refresh.
11877      * @param {Number} interval How often to update (in seconds).
11878      * @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)
11879      * @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}
11880      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11881      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11882      */
11883     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11884         if(refreshNow){
11885             this.update(url || this.defaultUrl, params, callback, true);
11886         }
11887         if(this.autoRefreshProcId){
11888             clearInterval(this.autoRefreshProcId);
11889         }
11890         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11891     },
11892
11893     /**
11894      * Stop auto refresh on this element.
11895      */
11896      stopAutoRefresh : function(){
11897         if(this.autoRefreshProcId){
11898             clearInterval(this.autoRefreshProcId);
11899             delete this.autoRefreshProcId;
11900         }
11901     },
11902
11903     isAutoRefreshing : function(){
11904        return this.autoRefreshProcId ? true : false;
11905     },
11906     /**
11907      * Called to update the element to "Loading" state. Override to perform custom action.
11908      */
11909     showLoading : function(){
11910         if(this.showLoadIndicator){
11911             this.el.update(this.indicatorText);
11912         }
11913     },
11914
11915     /**
11916      * Adds unique parameter to query string if disableCaching = true
11917      * @private
11918      */
11919     prepareUrl : function(url){
11920         if(this.disableCaching){
11921             var append = "_dc=" + (new Date().getTime());
11922             if(url.indexOf("?") !== -1){
11923                 url += "&" + append;
11924             }else{
11925                 url += "?" + append;
11926             }
11927         }
11928         return url;
11929     },
11930
11931     /**
11932      * @private
11933      */
11934     processSuccess : function(response){
11935         this.transaction = null;
11936         if(response.argument.form && response.argument.reset){
11937             try{ // put in try/catch since some older FF releases had problems with this
11938                 response.argument.form.reset();
11939             }catch(e){}
11940         }
11941         if(this.loadScripts){
11942             this.renderer.render(this.el, response, this,
11943                 this.updateComplete.createDelegate(this, [response]));
11944         }else{
11945             this.renderer.render(this.el, response, this);
11946             this.updateComplete(response);
11947         }
11948     },
11949
11950     updateComplete : function(response){
11951         this.fireEvent("update", this.el, response);
11952         if(typeof response.argument.callback == "function"){
11953             response.argument.callback(this.el, true, response);
11954         }
11955     },
11956
11957     /**
11958      * @private
11959      */
11960     processFailure : function(response){
11961         this.transaction = null;
11962         this.fireEvent("failure", this.el, response);
11963         if(typeof response.argument.callback == "function"){
11964             response.argument.callback(this.el, false, response);
11965         }
11966     },
11967
11968     /**
11969      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11970      * @param {Object} renderer The object implementing the render() method
11971      */
11972     setRenderer : function(renderer){
11973         this.renderer = renderer;
11974     },
11975
11976     getRenderer : function(){
11977        return this.renderer;
11978     },
11979
11980     /**
11981      * Set the defaultUrl used for updates
11982      * @param {String/Function} defaultUrl The url or a function to call to get the url
11983      */
11984     setDefaultUrl : function(defaultUrl){
11985         this.defaultUrl = defaultUrl;
11986     },
11987
11988     /**
11989      * Aborts the executing transaction
11990      */
11991     abort : function(){
11992         if(this.transaction){
11993             Roo.Ajax.abort(this.transaction);
11994         }
11995     },
11996
11997     /**
11998      * Returns true if an update is in progress
11999      * @return {Boolean}
12000      */
12001     isUpdating : function(){
12002         if(this.transaction){
12003             return Roo.Ajax.isLoading(this.transaction);
12004         }
12005         return false;
12006     }
12007 });
12008
12009 /**
12010  * @class Roo.UpdateManager.defaults
12011  * @static (not really - but it helps the doc tool)
12012  * The defaults collection enables customizing the default properties of UpdateManager
12013  */
12014    Roo.UpdateManager.defaults = {
12015        /**
12016          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12017          * @type Number
12018          */
12019          timeout : 30,
12020
12021          /**
12022          * True to process scripts by default (Defaults to false).
12023          * @type Boolean
12024          */
12025         loadScripts : false,
12026
12027         /**
12028         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12029         * @type String
12030         */
12031         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12032         /**
12033          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12034          * @type Boolean
12035          */
12036         disableCaching : false,
12037         /**
12038          * Whether to show indicatorText when loading (Defaults to true).
12039          * @type Boolean
12040          */
12041         showLoadIndicator : true,
12042         /**
12043          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12044          * @type String
12045          */
12046         indicatorText : '<div class="loading-indicator">Loading...</div>'
12047    };
12048
12049 /**
12050  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12051  *Usage:
12052  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12053  * @param {String/HTMLElement/Roo.Element} el The element to update
12054  * @param {String} url The url
12055  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12056  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12057  * @static
12058  * @deprecated
12059  * @member Roo.UpdateManager
12060  */
12061 Roo.UpdateManager.updateElement = function(el, url, params, options){
12062     var um = Roo.get(el, true).getUpdateManager();
12063     Roo.apply(um, options);
12064     um.update(url, params, options ? options.callback : null);
12065 };
12066 // alias for backwards compat
12067 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12068 /**
12069  * @class Roo.UpdateManager.BasicRenderer
12070  * Default Content renderer. Updates the elements innerHTML with the responseText.
12071  */
12072 Roo.UpdateManager.BasicRenderer = function(){};
12073
12074 Roo.UpdateManager.BasicRenderer.prototype = {
12075     /**
12076      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12077      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12078      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12079      * @param {Roo.Element} el The element being rendered
12080      * @param {Object} response The YUI Connect response object
12081      * @param {UpdateManager} updateManager The calling update manager
12082      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12083      */
12084      render : function(el, response, updateManager, callback){
12085         el.update(response.responseText, updateManager.loadScripts, callback);
12086     }
12087 };
12088 /*
12089  * Based on:
12090  * Ext JS Library 1.1.1
12091  * Copyright(c) 2006-2007, Ext JS, LLC.
12092  *
12093  * Originally Released Under LGPL - original licence link has changed is not relivant.
12094  *
12095  * Fork - LGPL
12096  * <script type="text/javascript">
12097  */
12098
12099 /**
12100  * @class Roo.util.DelayedTask
12101  * Provides a convenient method of performing setTimeout where a new
12102  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12103  * You can use this class to buffer
12104  * the keypress events for a certain number of milliseconds, and perform only if they stop
12105  * for that amount of time.
12106  * @constructor The parameters to this constructor serve as defaults and are not required.
12107  * @param {Function} fn (optional) The default function to timeout
12108  * @param {Object} scope (optional) The default scope of that timeout
12109  * @param {Array} args (optional) The default Array of arguments
12110  */
12111 Roo.util.DelayedTask = function(fn, scope, args){
12112     var id = null, d, t;
12113
12114     var call = function(){
12115         var now = new Date().getTime();
12116         if(now - t >= d){
12117             clearInterval(id);
12118             id = null;
12119             fn.apply(scope, args || []);
12120         }
12121     };
12122     /**
12123      * Cancels any pending timeout and queues a new one
12124      * @param {Number} delay The milliseconds to delay
12125      * @param {Function} newFn (optional) Overrides function passed to constructor
12126      * @param {Object} newScope (optional) Overrides scope passed to constructor
12127      * @param {Array} newArgs (optional) Overrides args passed to constructor
12128      */
12129     this.delay = function(delay, newFn, newScope, newArgs){
12130         if(id && delay != d){
12131             this.cancel();
12132         }
12133         d = delay;
12134         t = new Date().getTime();
12135         fn = newFn || fn;
12136         scope = newScope || scope;
12137         args = newArgs || args;
12138         if(!id){
12139             id = setInterval(call, d);
12140         }
12141     };
12142
12143     /**
12144      * Cancel the last queued timeout
12145      */
12146     this.cancel = function(){
12147         if(id){
12148             clearInterval(id);
12149             id = null;
12150         }
12151     };
12152 };/*
12153  * Based on:
12154  * Ext JS Library 1.1.1
12155  * Copyright(c) 2006-2007, Ext JS, LLC.
12156  *
12157  * Originally Released Under LGPL - original licence link has changed is not relivant.
12158  *
12159  * Fork - LGPL
12160  * <script type="text/javascript">
12161  */
12162  
12163  
12164 Roo.util.TaskRunner = function(interval){
12165     interval = interval || 10;
12166     var tasks = [], removeQueue = [];
12167     var id = 0;
12168     var running = false;
12169
12170     var stopThread = function(){
12171         running = false;
12172         clearInterval(id);
12173         id = 0;
12174     };
12175
12176     var startThread = function(){
12177         if(!running){
12178             running = true;
12179             id = setInterval(runTasks, interval);
12180         }
12181     };
12182
12183     var removeTask = function(task){
12184         removeQueue.push(task);
12185         if(task.onStop){
12186             task.onStop();
12187         }
12188     };
12189
12190     var runTasks = function(){
12191         if(removeQueue.length > 0){
12192             for(var i = 0, len = removeQueue.length; i < len; i++){
12193                 tasks.remove(removeQueue[i]);
12194             }
12195             removeQueue = [];
12196             if(tasks.length < 1){
12197                 stopThread();
12198                 return;
12199             }
12200         }
12201         var now = new Date().getTime();
12202         for(var i = 0, len = tasks.length; i < len; ++i){
12203             var t = tasks[i];
12204             var itime = now - t.taskRunTime;
12205             if(t.interval <= itime){
12206                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12207                 t.taskRunTime = now;
12208                 if(rt === false || t.taskRunCount === t.repeat){
12209                     removeTask(t);
12210                     return;
12211                 }
12212             }
12213             if(t.duration && t.duration <= (now - t.taskStartTime)){
12214                 removeTask(t);
12215             }
12216         }
12217     };
12218
12219     /**
12220      * Queues a new task.
12221      * @param {Object} task
12222      */
12223     this.start = function(task){
12224         tasks.push(task);
12225         task.taskStartTime = new Date().getTime();
12226         task.taskRunTime = 0;
12227         task.taskRunCount = 0;
12228         startThread();
12229         return task;
12230     };
12231
12232     this.stop = function(task){
12233         removeTask(task);
12234         return task;
12235     };
12236
12237     this.stopAll = function(){
12238         stopThread();
12239         for(var i = 0, len = tasks.length; i < len; i++){
12240             if(tasks[i].onStop){
12241                 tasks[i].onStop();
12242             }
12243         }
12244         tasks = [];
12245         removeQueue = [];
12246     };
12247 };
12248
12249 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12250  * Based on:
12251  * Ext JS Library 1.1.1
12252  * Copyright(c) 2006-2007, Ext JS, LLC.
12253  *
12254  * Originally Released Under LGPL - original licence link has changed is not relivant.
12255  *
12256  * Fork - LGPL
12257  * <script type="text/javascript">
12258  */
12259
12260  
12261 /**
12262  * @class Roo.util.MixedCollection
12263  * @extends Roo.util.Observable
12264  * A Collection class that maintains both numeric indexes and keys and exposes events.
12265  * @constructor
12266  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12267  * collection (defaults to false)
12268  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12269  * and return the key value for that item.  This is used when available to look up the key on items that
12270  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12271  * equivalent to providing an implementation for the {@link #getKey} method.
12272  */
12273 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12274     this.items = [];
12275     this.map = {};
12276     this.keys = [];
12277     this.length = 0;
12278     this.addEvents({
12279         /**
12280          * @event clear
12281          * Fires when the collection is cleared.
12282          */
12283         "clear" : true,
12284         /**
12285          * @event add
12286          * Fires when an item is added to the collection.
12287          * @param {Number} index The index at which the item was added.
12288          * @param {Object} o The item added.
12289          * @param {String} key The key associated with the added item.
12290          */
12291         "add" : true,
12292         /**
12293          * @event replace
12294          * Fires when an item is replaced in the collection.
12295          * @param {String} key he key associated with the new added.
12296          * @param {Object} old The item being replaced.
12297          * @param {Object} new The new item.
12298          */
12299         "replace" : true,
12300         /**
12301          * @event remove
12302          * Fires when an item is removed from the collection.
12303          * @param {Object} o The item being removed.
12304          * @param {String} key (optional) The key associated with the removed item.
12305          */
12306         "remove" : true,
12307         "sort" : true
12308     });
12309     this.allowFunctions = allowFunctions === true;
12310     if(keyFn){
12311         this.getKey = keyFn;
12312     }
12313     Roo.util.MixedCollection.superclass.constructor.call(this);
12314 };
12315
12316 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12317     allowFunctions : false,
12318     
12319 /**
12320  * Adds an item to the collection.
12321  * @param {String} key The key to associate with the item
12322  * @param {Object} o The item to add.
12323  * @return {Object} The item added.
12324  */
12325     add : function(key, o){
12326         if(arguments.length == 1){
12327             o = arguments[0];
12328             key = this.getKey(o);
12329         }
12330         if(typeof key == "undefined" || key === null){
12331             this.length++;
12332             this.items.push(o);
12333             this.keys.push(null);
12334         }else{
12335             var old = this.map[key];
12336             if(old){
12337                 return this.replace(key, o);
12338             }
12339             this.length++;
12340             this.items.push(o);
12341             this.map[key] = o;
12342             this.keys.push(key);
12343         }
12344         this.fireEvent("add", this.length-1, o, key);
12345         return o;
12346     },
12347        
12348 /**
12349   * MixedCollection has a generic way to fetch keys if you implement getKey.
12350 <pre><code>
12351 // normal way
12352 var mc = new Roo.util.MixedCollection();
12353 mc.add(someEl.dom.id, someEl);
12354 mc.add(otherEl.dom.id, otherEl);
12355 //and so on
12356
12357 // using getKey
12358 var mc = new Roo.util.MixedCollection();
12359 mc.getKey = function(el){
12360    return el.dom.id;
12361 };
12362 mc.add(someEl);
12363 mc.add(otherEl);
12364
12365 // or via the constructor
12366 var mc = new Roo.util.MixedCollection(false, function(el){
12367    return el.dom.id;
12368 });
12369 mc.add(someEl);
12370 mc.add(otherEl);
12371 </code></pre>
12372  * @param o {Object} The item for which to find the key.
12373  * @return {Object} The key for the passed item.
12374  */
12375     getKey : function(o){
12376          return o.id; 
12377     },
12378    
12379 /**
12380  * Replaces an item in the collection.
12381  * @param {String} key The key associated with the item to replace, or the item to replace.
12382  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12383  * @return {Object}  The new item.
12384  */
12385     replace : function(key, o){
12386         if(arguments.length == 1){
12387             o = arguments[0];
12388             key = this.getKey(o);
12389         }
12390         var old = this.item(key);
12391         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12392              return this.add(key, o);
12393         }
12394         var index = this.indexOfKey(key);
12395         this.items[index] = o;
12396         this.map[key] = o;
12397         this.fireEvent("replace", key, old, o);
12398         return o;
12399     },
12400    
12401 /**
12402  * Adds all elements of an Array or an Object to the collection.
12403  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12404  * an Array of values, each of which are added to the collection.
12405  */
12406     addAll : function(objs){
12407         if(arguments.length > 1 || objs instanceof Array){
12408             var args = arguments.length > 1 ? arguments : objs;
12409             for(var i = 0, len = args.length; i < len; i++){
12410                 this.add(args[i]);
12411             }
12412         }else{
12413             for(var key in objs){
12414                 if(this.allowFunctions || typeof objs[key] != "function"){
12415                     this.add(key, objs[key]);
12416                 }
12417             }
12418         }
12419     },
12420    
12421 /**
12422  * Executes the specified function once for every item in the collection, passing each
12423  * item as the first and only parameter. returning false from the function will stop the iteration.
12424  * @param {Function} fn The function to execute for each item.
12425  * @param {Object} scope (optional) The scope in which to execute the function.
12426  */
12427     each : function(fn, scope){
12428         var items = [].concat(this.items); // each safe for removal
12429         for(var i = 0, len = items.length; i < len; i++){
12430             if(fn.call(scope || items[i], items[i], i, len) === false){
12431                 break;
12432             }
12433         }
12434     },
12435    
12436 /**
12437  * Executes the specified function once for every key in the collection, passing each
12438  * key, and its associated item as the first two parameters.
12439  * @param {Function} fn The function to execute for each item.
12440  * @param {Object} scope (optional) The scope in which to execute the function.
12441  */
12442     eachKey : function(fn, scope){
12443         for(var i = 0, len = this.keys.length; i < len; i++){
12444             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12445         }
12446     },
12447    
12448 /**
12449  * Returns the first item in the collection which elicits a true return value from the
12450  * passed selection function.
12451  * @param {Function} fn The selection function to execute for each item.
12452  * @param {Object} scope (optional) The scope in which to execute the function.
12453  * @return {Object} The first item in the collection which returned true from the selection function.
12454  */
12455     find : function(fn, scope){
12456         for(var i = 0, len = this.items.length; i < len; i++){
12457             if(fn.call(scope || window, this.items[i], this.keys[i])){
12458                 return this.items[i];
12459             }
12460         }
12461         return null;
12462     },
12463    
12464 /**
12465  * Inserts an item at the specified index in the collection.
12466  * @param {Number} index The index to insert the item at.
12467  * @param {String} key The key to associate with the new item, or the item itself.
12468  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12469  * @return {Object} The item inserted.
12470  */
12471     insert : function(index, key, o){
12472         if(arguments.length == 2){
12473             o = arguments[1];
12474             key = this.getKey(o);
12475         }
12476         if(index >= this.length){
12477             return this.add(key, o);
12478         }
12479         this.length++;
12480         this.items.splice(index, 0, o);
12481         if(typeof key != "undefined" && key != null){
12482             this.map[key] = o;
12483         }
12484         this.keys.splice(index, 0, key);
12485         this.fireEvent("add", index, o, key);
12486         return o;
12487     },
12488    
12489 /**
12490  * Removed an item from the collection.
12491  * @param {Object} o The item to remove.
12492  * @return {Object} The item removed.
12493  */
12494     remove : function(o){
12495         return this.removeAt(this.indexOf(o));
12496     },
12497    
12498 /**
12499  * Remove an item from a specified index in the collection.
12500  * @param {Number} index The index within the collection of the item to remove.
12501  */
12502     removeAt : function(index){
12503         if(index < this.length && index >= 0){
12504             this.length--;
12505             var o = this.items[index];
12506             this.items.splice(index, 1);
12507             var key = this.keys[index];
12508             if(typeof key != "undefined"){
12509                 delete this.map[key];
12510             }
12511             this.keys.splice(index, 1);
12512             this.fireEvent("remove", o, key);
12513         }
12514     },
12515    
12516 /**
12517  * Removed an item associated with the passed key fom the collection.
12518  * @param {String} key The key of the item to remove.
12519  */
12520     removeKey : function(key){
12521         return this.removeAt(this.indexOfKey(key));
12522     },
12523    
12524 /**
12525  * Returns the number of items in the collection.
12526  * @return {Number} the number of items in the collection.
12527  */
12528     getCount : function(){
12529         return this.length; 
12530     },
12531    
12532 /**
12533  * Returns index within the collection of the passed Object.
12534  * @param {Object} o The item to find the index of.
12535  * @return {Number} index of the item.
12536  */
12537     indexOf : function(o){
12538         if(!this.items.indexOf){
12539             for(var i = 0, len = this.items.length; i < len; i++){
12540                 if(this.items[i] == o) return i;
12541             }
12542             return -1;
12543         }else{
12544             return this.items.indexOf(o);
12545         }
12546     },
12547    
12548 /**
12549  * Returns index within the collection of the passed key.
12550  * @param {String} key The key to find the index of.
12551  * @return {Number} index of the key.
12552  */
12553     indexOfKey : function(key){
12554         if(!this.keys.indexOf){
12555             for(var i = 0, len = this.keys.length; i < len; i++){
12556                 if(this.keys[i] == key) return i;
12557             }
12558             return -1;
12559         }else{
12560             return this.keys.indexOf(key);
12561         }
12562     },
12563    
12564 /**
12565  * Returns the item associated with the passed key OR index. Key has priority over index.
12566  * @param {String/Number} key The key or index of the item.
12567  * @return {Object} The item associated with the passed key.
12568  */
12569     item : function(key){
12570         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12571         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12572     },
12573     
12574 /**
12575  * Returns the item at the specified index.
12576  * @param {Number} index The index of the item.
12577  * @return {Object}
12578  */
12579     itemAt : function(index){
12580         return this.items[index];
12581     },
12582     
12583 /**
12584  * Returns the item associated with the passed key.
12585  * @param {String/Number} key The key of the item.
12586  * @return {Object} The item associated with the passed key.
12587  */
12588     key : function(key){
12589         return this.map[key];
12590     },
12591    
12592 /**
12593  * Returns true if the collection contains the passed Object as an item.
12594  * @param {Object} o  The Object to look for in the collection.
12595  * @return {Boolean} True if the collection contains the Object as an item.
12596  */
12597     contains : function(o){
12598         return this.indexOf(o) != -1;
12599     },
12600    
12601 /**
12602  * Returns true if the collection contains the passed Object as a key.
12603  * @param {String} key The key to look for in the collection.
12604  * @return {Boolean} True if the collection contains the Object as a key.
12605  */
12606     containsKey : function(key){
12607         return typeof this.map[key] != "undefined";
12608     },
12609    
12610 /**
12611  * Removes all items from the collection.
12612  */
12613     clear : function(){
12614         this.length = 0;
12615         this.items = [];
12616         this.keys = [];
12617         this.map = {};
12618         this.fireEvent("clear");
12619     },
12620    
12621 /**
12622  * Returns the first item in the collection.
12623  * @return {Object} the first item in the collection..
12624  */
12625     first : function(){
12626         return this.items[0]; 
12627     },
12628    
12629 /**
12630  * Returns the last item in the collection.
12631  * @return {Object} the last item in the collection..
12632  */
12633     last : function(){
12634         return this.items[this.length-1];   
12635     },
12636     
12637     _sort : function(property, dir, fn){
12638         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12639         fn = fn || function(a, b){
12640             return a-b;
12641         };
12642         var c = [], k = this.keys, items = this.items;
12643         for(var i = 0, len = items.length; i < len; i++){
12644             c[c.length] = {key: k[i], value: items[i], index: i};
12645         }
12646         c.sort(function(a, b){
12647             var v = fn(a[property], b[property]) * dsc;
12648             if(v == 0){
12649                 v = (a.index < b.index ? -1 : 1);
12650             }
12651             return v;
12652         });
12653         for(var i = 0, len = c.length; i < len; i++){
12654             items[i] = c[i].value;
12655             k[i] = c[i].key;
12656         }
12657         this.fireEvent("sort", this);
12658     },
12659     
12660     /**
12661      * Sorts this collection with the passed comparison function
12662      * @param {String} direction (optional) "ASC" or "DESC"
12663      * @param {Function} fn (optional) comparison function
12664      */
12665     sort : function(dir, fn){
12666         this._sort("value", dir, fn);
12667     },
12668     
12669     /**
12670      * Sorts this collection by keys
12671      * @param {String} direction (optional) "ASC" or "DESC"
12672      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12673      */
12674     keySort : function(dir, fn){
12675         this._sort("key", dir, fn || function(a, b){
12676             return String(a).toUpperCase()-String(b).toUpperCase();
12677         });
12678     },
12679     
12680     /**
12681      * Returns a range of items in this collection
12682      * @param {Number} startIndex (optional) defaults to 0
12683      * @param {Number} endIndex (optional) default to the last item
12684      * @return {Array} An array of items
12685      */
12686     getRange : function(start, end){
12687         var items = this.items;
12688         if(items.length < 1){
12689             return [];
12690         }
12691         start = start || 0;
12692         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12693         var r = [];
12694         if(start <= end){
12695             for(var i = start; i <= end; i++) {
12696                     r[r.length] = items[i];
12697             }
12698         }else{
12699             for(var i = start; i >= end; i--) {
12700                     r[r.length] = items[i];
12701             }
12702         }
12703         return r;
12704     },
12705         
12706     /**
12707      * Filter the <i>objects</i> in this collection by a specific property. 
12708      * Returns a new collection that has been filtered.
12709      * @param {String} property A property on your objects
12710      * @param {String/RegExp} value Either string that the property values 
12711      * should start with or a RegExp to test against the property
12712      * @return {MixedCollection} The new filtered collection
12713      */
12714     filter : function(property, value){
12715         if(!value.exec){ // not a regex
12716             value = String(value);
12717             if(value.length == 0){
12718                 return this.clone();
12719             }
12720             value = new RegExp("^" + Roo.escapeRe(value), "i");
12721         }
12722         return this.filterBy(function(o){
12723             return o && value.test(o[property]);
12724         });
12725         },
12726     
12727     /**
12728      * Filter by a function. * Returns a new collection that has been filtered.
12729      * The passed function will be called with each 
12730      * object in the collection. If the function returns true, the value is included 
12731      * otherwise it is filtered.
12732      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12733      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12734      * @return {MixedCollection} The new filtered collection
12735      */
12736     filterBy : function(fn, scope){
12737         var r = new Roo.util.MixedCollection();
12738         r.getKey = this.getKey;
12739         var k = this.keys, it = this.items;
12740         for(var i = 0, len = it.length; i < len; i++){
12741             if(fn.call(scope||this, it[i], k[i])){
12742                                 r.add(k[i], it[i]);
12743                         }
12744         }
12745         return r;
12746     },
12747     
12748     /**
12749      * Creates a duplicate of this collection
12750      * @return {MixedCollection}
12751      */
12752     clone : function(){
12753         var r = new Roo.util.MixedCollection();
12754         var k = this.keys, it = this.items;
12755         for(var i = 0, len = it.length; i < len; i++){
12756             r.add(k[i], it[i]);
12757         }
12758         r.getKey = this.getKey;
12759         return r;
12760     }
12761 });
12762 /**
12763  * Returns the item associated with the passed key or index.
12764  * @method
12765  * @param {String/Number} key The key or index of the item.
12766  * @return {Object} The item associated with the passed key.
12767  */
12768 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12769  * Based on:
12770  * Ext JS Library 1.1.1
12771  * Copyright(c) 2006-2007, Ext JS, LLC.
12772  *
12773  * Originally Released Under LGPL - original licence link has changed is not relivant.
12774  *
12775  * Fork - LGPL
12776  * <script type="text/javascript">
12777  */
12778 /**
12779  * @class Roo.util.JSON
12780  * Modified version of Douglas Crockford"s json.js that doesn"t
12781  * mess with the Object prototype 
12782  * http://www.json.org/js.html
12783  * @singleton
12784  */
12785 Roo.util.JSON = new (function(){
12786     var useHasOwn = {}.hasOwnProperty ? true : false;
12787     
12788     // crashes Safari in some instances
12789     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12790     
12791     var pad = function(n) {
12792         return n < 10 ? "0" + n : n;
12793     };
12794     
12795     var m = {
12796         "\b": '\\b',
12797         "\t": '\\t',
12798         "\n": '\\n',
12799         "\f": '\\f',
12800         "\r": '\\r',
12801         '"' : '\\"',
12802         "\\": '\\\\'
12803     };
12804
12805     var encodeString = function(s){
12806         if (/["\\\x00-\x1f]/.test(s)) {
12807             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12808                 var c = m[b];
12809                 if(c){
12810                     return c;
12811                 }
12812                 c = b.charCodeAt();
12813                 return "\\u00" +
12814                     Math.floor(c / 16).toString(16) +
12815                     (c % 16).toString(16);
12816             }) + '"';
12817         }
12818         return '"' + s + '"';
12819     };
12820     
12821     var encodeArray = function(o){
12822         var a = ["["], b, i, l = o.length, v;
12823             for (i = 0; i < l; i += 1) {
12824                 v = o[i];
12825                 switch (typeof v) {
12826                     case "undefined":
12827                     case "function":
12828                     case "unknown":
12829                         break;
12830                     default:
12831                         if (b) {
12832                             a.push(',');
12833                         }
12834                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12835                         b = true;
12836                 }
12837             }
12838             a.push("]");
12839             return a.join("");
12840     };
12841     
12842     var encodeDate = function(o){
12843         return '"' + o.getFullYear() + "-" +
12844                 pad(o.getMonth() + 1) + "-" +
12845                 pad(o.getDate()) + "T" +
12846                 pad(o.getHours()) + ":" +
12847                 pad(o.getMinutes()) + ":" +
12848                 pad(o.getSeconds()) + '"';
12849     };
12850     
12851     /**
12852      * Encodes an Object, Array or other value
12853      * @param {Mixed} o The variable to encode
12854      * @return {String} The JSON string
12855      */
12856     this.encode = function(o)
12857     {
12858         // should this be extended to fully wrap stringify..
12859         
12860         if(typeof o == "undefined" || o === null){
12861             return "null";
12862         }else if(o instanceof Array){
12863             return encodeArray(o);
12864         }else if(o instanceof Date){
12865             return encodeDate(o);
12866         }else if(typeof o == "string"){
12867             return encodeString(o);
12868         }else if(typeof o == "number"){
12869             return isFinite(o) ? String(o) : "null";
12870         }else if(typeof o == "boolean"){
12871             return String(o);
12872         }else {
12873             var a = ["{"], b, i, v;
12874             for (i in o) {
12875                 if(!useHasOwn || o.hasOwnProperty(i)) {
12876                     v = o[i];
12877                     switch (typeof v) {
12878                     case "undefined":
12879                     case "function":
12880                     case "unknown":
12881                         break;
12882                     default:
12883                         if(b){
12884                             a.push(',');
12885                         }
12886                         a.push(this.encode(i), ":",
12887                                 v === null ? "null" : this.encode(v));
12888                         b = true;
12889                     }
12890                 }
12891             }
12892             a.push("}");
12893             return a.join("");
12894         }
12895     };
12896     
12897     /**
12898      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12899      * @param {String} json The JSON string
12900      * @return {Object} The resulting object
12901      */
12902     this.decode = function(json){
12903         
12904         return  /** eval:var:json */ eval("(" + json + ')');
12905     };
12906 })();
12907 /** 
12908  * Shorthand for {@link Roo.util.JSON#encode}
12909  * @member Roo encode 
12910  * @method */
12911 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12912 /** 
12913  * Shorthand for {@link Roo.util.JSON#decode}
12914  * @member Roo decode 
12915  * @method */
12916 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12917 /*
12918  * Based on:
12919  * Ext JS Library 1.1.1
12920  * Copyright(c) 2006-2007, Ext JS, LLC.
12921  *
12922  * Originally Released Under LGPL - original licence link has changed is not relivant.
12923  *
12924  * Fork - LGPL
12925  * <script type="text/javascript">
12926  */
12927  
12928 /**
12929  * @class Roo.util.Format
12930  * Reusable data formatting functions
12931  * @singleton
12932  */
12933 Roo.util.Format = function(){
12934     var trimRe = /^\s+|\s+$/g;
12935     return {
12936         /**
12937          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12938          * @param {String} value The string to truncate
12939          * @param {Number} length The maximum length to allow before truncating
12940          * @return {String} The converted text
12941          */
12942         ellipsis : function(value, len){
12943             if(value && value.length > len){
12944                 return value.substr(0, len-3)+"...";
12945             }
12946             return value;
12947         },
12948
12949         /**
12950          * Checks a reference and converts it to empty string if it is undefined
12951          * @param {Mixed} value Reference to check
12952          * @return {Mixed} Empty string if converted, otherwise the original value
12953          */
12954         undef : function(value){
12955             return typeof value != "undefined" ? value : "";
12956         },
12957
12958         /**
12959          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12960          * @param {String} value The string to encode
12961          * @return {String} The encoded text
12962          */
12963         htmlEncode : function(value){
12964             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12965         },
12966
12967         /**
12968          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12969          * @param {String} value The string to decode
12970          * @return {String} The decoded text
12971          */
12972         htmlDecode : function(value){
12973             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12974         },
12975
12976         /**
12977          * Trims any whitespace from either side of a string
12978          * @param {String} value The text to trim
12979          * @return {String} The trimmed text
12980          */
12981         trim : function(value){
12982             return String(value).replace(trimRe, "");
12983         },
12984
12985         /**
12986          * Returns a substring from within an original string
12987          * @param {String} value The original text
12988          * @param {Number} start The start index of the substring
12989          * @param {Number} length The length of the substring
12990          * @return {String} The substring
12991          */
12992         substr : function(value, start, length){
12993             return String(value).substr(start, length);
12994         },
12995
12996         /**
12997          * Converts a string to all lower case letters
12998          * @param {String} value The text to convert
12999          * @return {String} The converted text
13000          */
13001         lowercase : function(value){
13002             return String(value).toLowerCase();
13003         },
13004
13005         /**
13006          * Converts a string to all upper case letters
13007          * @param {String} value The text to convert
13008          * @return {String} The converted text
13009          */
13010         uppercase : function(value){
13011             return String(value).toUpperCase();
13012         },
13013
13014         /**
13015          * Converts the first character only of a string to upper case
13016          * @param {String} value The text to convert
13017          * @return {String} The converted text
13018          */
13019         capitalize : function(value){
13020             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13021         },
13022
13023         // private
13024         call : function(value, fn){
13025             if(arguments.length > 2){
13026                 var args = Array.prototype.slice.call(arguments, 2);
13027                 args.unshift(value);
13028                  
13029                 return /** eval:var:value */  eval(fn).apply(window, args);
13030             }else{
13031                 /** eval:var:value */
13032                 return /** eval:var:value */ eval(fn).call(window, value);
13033             }
13034         },
13035
13036        
13037         /**
13038          * safer version of Math.toFixed..??/
13039          * @param {Number/String} value The numeric value to format
13040          * @param {Number/String} value Decimal places 
13041          * @return {String} The formatted currency string
13042          */
13043         toFixed : function(v, n)
13044         {
13045             // why not use to fixed - precision is buggered???
13046             if (!n) {
13047                 return Math.round(v-0);
13048             }
13049             var fact = Math.pow(10,n+1);
13050             v = (Math.round((v-0)*fact))/fact;
13051             var z = (''+fact).substring(2);
13052             if (v == Math.floor(v)) {
13053                 return Math.floor(v) + '.' + z;
13054             }
13055             
13056             // now just padd decimals..
13057             var ps = String(v).split('.');
13058             var fd = (ps[1] + z);
13059             var r = fd.substring(0,n); 
13060             var rm = fd.substring(n); 
13061             if (rm < 5) {
13062                 return ps[0] + '.' + r;
13063             }
13064             r*=1; // turn it into a number;
13065             r++;
13066             if (String(r).length != n) {
13067                 ps[0]*=1;
13068                 ps[0]++;
13069                 r = String(r).substring(1); // chop the end off.
13070             }
13071             
13072             return ps[0] + '.' + r;
13073              
13074         },
13075         
13076         /**
13077          * Format a number as US currency
13078          * @param {Number/String} value The numeric value to format
13079          * @return {String} The formatted currency string
13080          */
13081         usMoney : function(v){
13082             v = (Math.round((v-0)*100))/100;
13083             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13084             v = String(v);
13085             var ps = v.split('.');
13086             var whole = ps[0];
13087             var sub = ps[1] ? '.'+ ps[1] : '.00';
13088             var r = /(\d+)(\d{3})/;
13089             while (r.test(whole)) {
13090                 whole = whole.replace(r, '$1' + ',' + '$2');
13091             }
13092             return "$" + whole + sub ;
13093         },
13094         
13095         /**
13096          * Parse a value into a formatted date using the specified format pattern.
13097          * @param {Mixed} value The value to format
13098          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13099          * @return {String} The formatted date string
13100          */
13101         date : function(v, format){
13102             if(!v){
13103                 return "";
13104             }
13105             if(!(v instanceof Date)){
13106                 v = new Date(Date.parse(v));
13107             }
13108             return v.dateFormat(format || "m/d/Y");
13109         },
13110
13111         /**
13112          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13113          * @param {String} format Any valid date format string
13114          * @return {Function} The date formatting function
13115          */
13116         dateRenderer : function(format){
13117             return function(v){
13118                 return Roo.util.Format.date(v, format);  
13119             };
13120         },
13121
13122         // private
13123         stripTagsRE : /<\/?[^>]+>/gi,
13124         
13125         /**
13126          * Strips all HTML tags
13127          * @param {Mixed} value The text from which to strip tags
13128          * @return {String} The stripped text
13129          */
13130         stripTags : function(v){
13131             return !v ? v : String(v).replace(this.stripTagsRE, "");
13132         }
13133     };
13134 }();/*
13135  * Based on:
13136  * Ext JS Library 1.1.1
13137  * Copyright(c) 2006-2007, Ext JS, LLC.
13138  *
13139  * Originally Released Under LGPL - original licence link has changed is not relivant.
13140  *
13141  * Fork - LGPL
13142  * <script type="text/javascript">
13143  */
13144
13145
13146  
13147
13148 /**
13149  * @class Roo.MasterTemplate
13150  * @extends Roo.Template
13151  * Provides a template that can have child templates. The syntax is:
13152 <pre><code>
13153 var t = new Roo.MasterTemplate(
13154         '&lt;select name="{name}"&gt;',
13155                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13156         '&lt;/select&gt;'
13157 );
13158 t.add('options', {value: 'foo', text: 'bar'});
13159 // or you can add multiple child elements in one shot
13160 t.addAll('options', [
13161     {value: 'foo', text: 'bar'},
13162     {value: 'foo2', text: 'bar2'},
13163     {value: 'foo3', text: 'bar3'}
13164 ]);
13165 // then append, applying the master template values
13166 t.append('my-form', {name: 'my-select'});
13167 </code></pre>
13168 * A name attribute for the child template is not required if you have only one child
13169 * template or you want to refer to them by index.
13170  */
13171 Roo.MasterTemplate = function(){
13172     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13173     this.originalHtml = this.html;
13174     var st = {};
13175     var m, re = this.subTemplateRe;
13176     re.lastIndex = 0;
13177     var subIndex = 0;
13178     while(m = re.exec(this.html)){
13179         var name = m[1], content = m[2];
13180         st[subIndex] = {
13181             name: name,
13182             index: subIndex,
13183             buffer: [],
13184             tpl : new Roo.Template(content)
13185         };
13186         if(name){
13187             st[name] = st[subIndex];
13188         }
13189         st[subIndex].tpl.compile();
13190         st[subIndex].tpl.call = this.call.createDelegate(this);
13191         subIndex++;
13192     }
13193     this.subCount = subIndex;
13194     this.subs = st;
13195 };
13196 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13197     /**
13198     * The regular expression used to match sub templates
13199     * @type RegExp
13200     * @property
13201     */
13202     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13203
13204     /**
13205      * Applies the passed values to a child template.
13206      * @param {String/Number} name (optional) The name or index of the child template
13207      * @param {Array/Object} values The values to be applied to the template
13208      * @return {MasterTemplate} this
13209      */
13210      add : function(name, values){
13211         if(arguments.length == 1){
13212             values = arguments[0];
13213             name = 0;
13214         }
13215         var s = this.subs[name];
13216         s.buffer[s.buffer.length] = s.tpl.apply(values);
13217         return this;
13218     },
13219
13220     /**
13221      * Applies all the passed values to a child template.
13222      * @param {String/Number} name (optional) The name or index of the child template
13223      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13224      * @param {Boolean} reset (optional) True to reset the template first
13225      * @return {MasterTemplate} this
13226      */
13227     fill : function(name, values, reset){
13228         var a = arguments;
13229         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13230             values = a[0];
13231             name = 0;
13232             reset = a[1];
13233         }
13234         if(reset){
13235             this.reset();
13236         }
13237         for(var i = 0, len = values.length; i < len; i++){
13238             this.add(name, values[i]);
13239         }
13240         return this;
13241     },
13242
13243     /**
13244      * Resets the template for reuse
13245      * @return {MasterTemplate} this
13246      */
13247      reset : function(){
13248         var s = this.subs;
13249         for(var i = 0; i < this.subCount; i++){
13250             s[i].buffer = [];
13251         }
13252         return this;
13253     },
13254
13255     applyTemplate : function(values){
13256         var s = this.subs;
13257         var replaceIndex = -1;
13258         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13259             return s[++replaceIndex].buffer.join("");
13260         });
13261         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13262     },
13263
13264     apply : function(){
13265         return this.applyTemplate.apply(this, arguments);
13266     },
13267
13268     compile : function(){return this;}
13269 });
13270
13271 /**
13272  * Alias for fill().
13273  * @method
13274  */
13275 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13276  /**
13277  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13278  * var tpl = Roo.MasterTemplate.from('element-id');
13279  * @param {String/HTMLElement} el
13280  * @param {Object} config
13281  * @static
13282  */
13283 Roo.MasterTemplate.from = function(el, config){
13284     el = Roo.getDom(el);
13285     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13286 };/*
13287  * Based on:
13288  * Ext JS Library 1.1.1
13289  * Copyright(c) 2006-2007, Ext JS, LLC.
13290  *
13291  * Originally Released Under LGPL - original licence link has changed is not relivant.
13292  *
13293  * Fork - LGPL
13294  * <script type="text/javascript">
13295  */
13296
13297  
13298 /**
13299  * @class Roo.util.CSS
13300  * Utility class for manipulating CSS rules
13301  * @singleton
13302  */
13303 Roo.util.CSS = function(){
13304         var rules = null;
13305         var doc = document;
13306
13307     var camelRe = /(-[a-z])/gi;
13308     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13309
13310    return {
13311    /**
13312     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13313     * tag and appended to the HEAD of the document.
13314     * @param {String|Object} cssText The text containing the css rules
13315     * @param {String} id An id to add to the stylesheet for later removal
13316     * @return {StyleSheet}
13317     */
13318     createStyleSheet : function(cssText, id){
13319         var ss;
13320         var head = doc.getElementsByTagName("head")[0];
13321         var nrules = doc.createElement("style");
13322         nrules.setAttribute("type", "text/css");
13323         if(id){
13324             nrules.setAttribute("id", id);
13325         }
13326         if (typeof(cssText) != 'string') {
13327             // support object maps..
13328             // not sure if this a good idea.. 
13329             // perhaps it should be merged with the general css handling
13330             // and handle js style props.
13331             var cssTextNew = [];
13332             for(var n in cssText) {
13333                 var citems = [];
13334                 for(var k in cssText[n]) {
13335                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13336                 }
13337                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13338                 
13339             }
13340             cssText = cssTextNew.join("\n");
13341             
13342         }
13343        
13344        
13345        if(Roo.isIE){
13346            head.appendChild(nrules);
13347            ss = nrules.styleSheet;
13348            ss.cssText = cssText;
13349        }else{
13350            try{
13351                 nrules.appendChild(doc.createTextNode(cssText));
13352            }catch(e){
13353                nrules.cssText = cssText; 
13354            }
13355            head.appendChild(nrules);
13356            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13357        }
13358        this.cacheStyleSheet(ss);
13359        return ss;
13360    },
13361
13362    /**
13363     * Removes a style or link tag by id
13364     * @param {String} id The id of the tag
13365     */
13366    removeStyleSheet : function(id){
13367        var existing = doc.getElementById(id);
13368        if(existing){
13369            existing.parentNode.removeChild(existing);
13370        }
13371    },
13372
13373    /**
13374     * Dynamically swaps an existing stylesheet reference for a new one
13375     * @param {String} id The id of an existing link tag to remove
13376     * @param {String} url The href of the new stylesheet to include
13377     */
13378    swapStyleSheet : function(id, url){
13379        this.removeStyleSheet(id);
13380        var ss = doc.createElement("link");
13381        ss.setAttribute("rel", "stylesheet");
13382        ss.setAttribute("type", "text/css");
13383        ss.setAttribute("id", id);
13384        ss.setAttribute("href", url);
13385        doc.getElementsByTagName("head")[0].appendChild(ss);
13386    },
13387    
13388    /**
13389     * Refresh the rule cache if you have dynamically added stylesheets
13390     * @return {Object} An object (hash) of rules indexed by selector
13391     */
13392    refreshCache : function(){
13393        return this.getRules(true);
13394    },
13395
13396    // private
13397    cacheStyleSheet : function(stylesheet){
13398        if(!rules){
13399            rules = {};
13400        }
13401        try{// try catch for cross domain access issue
13402            var ssRules = stylesheet.cssRules || stylesheet.rules;
13403            for(var j = ssRules.length-1; j >= 0; --j){
13404                rules[ssRules[j].selectorText] = ssRules[j];
13405            }
13406        }catch(e){}
13407    },
13408    
13409    /**
13410     * Gets all css rules for the document
13411     * @param {Boolean} refreshCache true to refresh the internal cache
13412     * @return {Object} An object (hash) of rules indexed by selector
13413     */
13414    getRules : function(refreshCache){
13415                 if(rules == null || refreshCache){
13416                         rules = {};
13417                         var ds = doc.styleSheets;
13418                         for(var i =0, len = ds.length; i < len; i++){
13419                             try{
13420                         this.cacheStyleSheet(ds[i]);
13421                     }catch(e){} 
13422                 }
13423                 }
13424                 return rules;
13425         },
13426         
13427         /**
13428     * Gets an an individual CSS rule by selector(s)
13429     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13430     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13431     * @return {CSSRule} The CSS rule or null if one is not found
13432     */
13433    getRule : function(selector, refreshCache){
13434                 var rs = this.getRules(refreshCache);
13435                 if(!(selector instanceof Array)){
13436                     return rs[selector];
13437                 }
13438                 for(var i = 0; i < selector.length; i++){
13439                         if(rs[selector[i]]){
13440                                 return rs[selector[i]];
13441                         }
13442                 }
13443                 return null;
13444         },
13445         
13446         
13447         /**
13448     * Updates a rule property
13449     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13450     * @param {String} property The css property
13451     * @param {String} value The new value for the property
13452     * @return {Boolean} true If a rule was found and updated
13453     */
13454    updateRule : function(selector, property, value){
13455                 if(!(selector instanceof Array)){
13456                         var rule = this.getRule(selector);
13457                         if(rule){
13458                                 rule.style[property.replace(camelRe, camelFn)] = value;
13459                                 return true;
13460                         }
13461                 }else{
13462                         for(var i = 0; i < selector.length; i++){
13463                                 if(this.updateRule(selector[i], property, value)){
13464                                         return true;
13465                                 }
13466                         }
13467                 }
13468                 return false;
13469         }
13470    };   
13471 }();/*
13472  * Based on:
13473  * Ext JS Library 1.1.1
13474  * Copyright(c) 2006-2007, Ext JS, LLC.
13475  *
13476  * Originally Released Under LGPL - original licence link has changed is not relivant.
13477  *
13478  * Fork - LGPL
13479  * <script type="text/javascript">
13480  */
13481
13482  
13483
13484 /**
13485  * @class Roo.util.ClickRepeater
13486  * @extends Roo.util.Observable
13487  * 
13488  * A wrapper class which can be applied to any element. Fires a "click" event while the
13489  * mouse is pressed. The interval between firings may be specified in the config but
13490  * defaults to 10 milliseconds.
13491  * 
13492  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13493  * 
13494  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13495  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13496  * Similar to an autorepeat key delay.
13497  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13498  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13499  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13500  *           "interval" and "delay" are ignored. "immediate" is honored.
13501  * @cfg {Boolean} preventDefault True to prevent the default click event
13502  * @cfg {Boolean} stopDefault True to stop the default click event
13503  * 
13504  * @history
13505  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13506  *     2007-02-02 jvs Renamed to ClickRepeater
13507  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13508  *
13509  *  @constructor
13510  * @param {String/HTMLElement/Element} el The element to listen on
13511  * @param {Object} config
13512  **/
13513 Roo.util.ClickRepeater = function(el, config)
13514 {
13515     this.el = Roo.get(el);
13516     this.el.unselectable();
13517
13518     Roo.apply(this, config);
13519
13520     this.addEvents({
13521     /**
13522      * @event mousedown
13523      * Fires when the mouse button is depressed.
13524      * @param {Roo.util.ClickRepeater} this
13525      */
13526         "mousedown" : true,
13527     /**
13528      * @event click
13529      * Fires on a specified interval during the time the element is pressed.
13530      * @param {Roo.util.ClickRepeater} this
13531      */
13532         "click" : true,
13533     /**
13534      * @event mouseup
13535      * Fires when the mouse key is released.
13536      * @param {Roo.util.ClickRepeater} this
13537      */
13538         "mouseup" : true
13539     });
13540
13541     this.el.on("mousedown", this.handleMouseDown, this);
13542     if(this.preventDefault || this.stopDefault){
13543         this.el.on("click", function(e){
13544             if(this.preventDefault){
13545                 e.preventDefault();
13546             }
13547             if(this.stopDefault){
13548                 e.stopEvent();
13549             }
13550         }, this);
13551     }
13552
13553     // allow inline handler
13554     if(this.handler){
13555         this.on("click", this.handler,  this.scope || this);
13556     }
13557
13558     Roo.util.ClickRepeater.superclass.constructor.call(this);
13559 };
13560
13561 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13562     interval : 20,
13563     delay: 250,
13564     preventDefault : true,
13565     stopDefault : false,
13566     timer : 0,
13567
13568     // private
13569     handleMouseDown : function(){
13570         clearTimeout(this.timer);
13571         this.el.blur();
13572         if(this.pressClass){
13573             this.el.addClass(this.pressClass);
13574         }
13575         this.mousedownTime = new Date();
13576
13577         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13578         this.el.on("mouseout", this.handleMouseOut, this);
13579
13580         this.fireEvent("mousedown", this);
13581         this.fireEvent("click", this);
13582         
13583         this.timer = this.click.defer(this.delay || this.interval, this);
13584     },
13585
13586     // private
13587     click : function(){
13588         this.fireEvent("click", this);
13589         this.timer = this.click.defer(this.getInterval(), this);
13590     },
13591
13592     // private
13593     getInterval: function(){
13594         if(!this.accelerate){
13595             return this.interval;
13596         }
13597         var pressTime = this.mousedownTime.getElapsed();
13598         if(pressTime < 500){
13599             return 400;
13600         }else if(pressTime < 1700){
13601             return 320;
13602         }else if(pressTime < 2600){
13603             return 250;
13604         }else if(pressTime < 3500){
13605             return 180;
13606         }else if(pressTime < 4400){
13607             return 140;
13608         }else if(pressTime < 5300){
13609             return 80;
13610         }else if(pressTime < 6200){
13611             return 50;
13612         }else{
13613             return 10;
13614         }
13615     },
13616
13617     // private
13618     handleMouseOut : function(){
13619         clearTimeout(this.timer);
13620         if(this.pressClass){
13621             this.el.removeClass(this.pressClass);
13622         }
13623         this.el.on("mouseover", this.handleMouseReturn, this);
13624     },
13625
13626     // private
13627     handleMouseReturn : function(){
13628         this.el.un("mouseover", this.handleMouseReturn);
13629         if(this.pressClass){
13630             this.el.addClass(this.pressClass);
13631         }
13632         this.click();
13633     },
13634
13635     // private
13636     handleMouseUp : function(){
13637         clearTimeout(this.timer);
13638         this.el.un("mouseover", this.handleMouseReturn);
13639         this.el.un("mouseout", this.handleMouseOut);
13640         Roo.get(document).un("mouseup", this.handleMouseUp);
13641         this.el.removeClass(this.pressClass);
13642         this.fireEvent("mouseup", this);
13643     }
13644 });/*
13645  * Based on:
13646  * Ext JS Library 1.1.1
13647  * Copyright(c) 2006-2007, Ext JS, LLC.
13648  *
13649  * Originally Released Under LGPL - original licence link has changed is not relivant.
13650  *
13651  * Fork - LGPL
13652  * <script type="text/javascript">
13653  */
13654
13655  
13656 /**
13657  * @class Roo.KeyNav
13658  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13659  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13660  * way to implement custom navigation schemes for any UI component.</p>
13661  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13662  * pageUp, pageDown, del, home, end.  Usage:</p>
13663  <pre><code>
13664 var nav = new Roo.KeyNav("my-element", {
13665     "left" : function(e){
13666         this.moveLeft(e.ctrlKey);
13667     },
13668     "right" : function(e){
13669         this.moveRight(e.ctrlKey);
13670     },
13671     "enter" : function(e){
13672         this.save();
13673     },
13674     scope : this
13675 });
13676 </code></pre>
13677  * @constructor
13678  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13679  * @param {Object} config The config
13680  */
13681 Roo.KeyNav = function(el, config){
13682     this.el = Roo.get(el);
13683     Roo.apply(this, config);
13684     if(!this.disabled){
13685         this.disabled = true;
13686         this.enable();
13687     }
13688 };
13689
13690 Roo.KeyNav.prototype = {
13691     /**
13692      * @cfg {Boolean} disabled
13693      * True to disable this KeyNav instance (defaults to false)
13694      */
13695     disabled : false,
13696     /**
13697      * @cfg {String} defaultEventAction
13698      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13699      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13700      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13701      */
13702     defaultEventAction: "stopEvent",
13703     /**
13704      * @cfg {Boolean} forceKeyDown
13705      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13706      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13707      * handle keydown instead of keypress.
13708      */
13709     forceKeyDown : false,
13710
13711     // private
13712     prepareEvent : function(e){
13713         var k = e.getKey();
13714         var h = this.keyToHandler[k];
13715         //if(h && this[h]){
13716         //    e.stopPropagation();
13717         //}
13718         if(Roo.isSafari && h && k >= 37 && k <= 40){
13719             e.stopEvent();
13720         }
13721     },
13722
13723     // private
13724     relay : function(e){
13725         var k = e.getKey();
13726         var h = this.keyToHandler[k];
13727         if(h && this[h]){
13728             if(this.doRelay(e, this[h], h) !== true){
13729                 e[this.defaultEventAction]();
13730             }
13731         }
13732     },
13733
13734     // private
13735     doRelay : function(e, h, hname){
13736         return h.call(this.scope || this, e);
13737     },
13738
13739     // possible handlers
13740     enter : false,
13741     left : false,
13742     right : false,
13743     up : false,
13744     down : false,
13745     tab : false,
13746     esc : false,
13747     pageUp : false,
13748     pageDown : false,
13749     del : false,
13750     home : false,
13751     end : false,
13752
13753     // quick lookup hash
13754     keyToHandler : {
13755         37 : "left",
13756         39 : "right",
13757         38 : "up",
13758         40 : "down",
13759         33 : "pageUp",
13760         34 : "pageDown",
13761         46 : "del",
13762         36 : "home",
13763         35 : "end",
13764         13 : "enter",
13765         27 : "esc",
13766         9  : "tab"
13767     },
13768
13769         /**
13770          * Enable this KeyNav
13771          */
13772         enable: function(){
13773                 if(this.disabled){
13774             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13775             // the EventObject will normalize Safari automatically
13776             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13777                 this.el.on("keydown", this.relay,  this);
13778             }else{
13779                 this.el.on("keydown", this.prepareEvent,  this);
13780                 this.el.on("keypress", this.relay,  this);
13781             }
13782                     this.disabled = false;
13783                 }
13784         },
13785
13786         /**
13787          * Disable this KeyNav
13788          */
13789         disable: function(){
13790                 if(!this.disabled){
13791                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13792                 this.el.un("keydown", this.relay);
13793             }else{
13794                 this.el.un("keydown", this.prepareEvent);
13795                 this.el.un("keypress", this.relay);
13796             }
13797                     this.disabled = true;
13798                 }
13799         }
13800 };/*
13801  * Based on:
13802  * Ext JS Library 1.1.1
13803  * Copyright(c) 2006-2007, Ext JS, LLC.
13804  *
13805  * Originally Released Under LGPL - original licence link has changed is not relivant.
13806  *
13807  * Fork - LGPL
13808  * <script type="text/javascript">
13809  */
13810
13811  
13812 /**
13813  * @class Roo.KeyMap
13814  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13815  * The constructor accepts the same config object as defined by {@link #addBinding}.
13816  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13817  * combination it will call the function with this signature (if the match is a multi-key
13818  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13819  * A KeyMap can also handle a string representation of keys.<br />
13820  * Usage:
13821  <pre><code>
13822 // map one key by key code
13823 var map = new Roo.KeyMap("my-element", {
13824     key: 13, // or Roo.EventObject.ENTER
13825     fn: myHandler,
13826     scope: myObject
13827 });
13828
13829 // map multiple keys to one action by string
13830 var map = new Roo.KeyMap("my-element", {
13831     key: "a\r\n\t",
13832     fn: myHandler,
13833     scope: myObject
13834 });
13835
13836 // map multiple keys to multiple actions by strings and array of codes
13837 var map = new Roo.KeyMap("my-element", [
13838     {
13839         key: [10,13],
13840         fn: function(){ alert("Return was pressed"); }
13841     }, {
13842         key: "abc",
13843         fn: function(){ alert('a, b or c was pressed'); }
13844     }, {
13845         key: "\t",
13846         ctrl:true,
13847         shift:true,
13848         fn: function(){ alert('Control + shift + tab was pressed.'); }
13849     }
13850 ]);
13851 </code></pre>
13852  * <b>Note: A KeyMap starts enabled</b>
13853  * @constructor
13854  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13855  * @param {Object} config The config (see {@link #addBinding})
13856  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13857  */
13858 Roo.KeyMap = function(el, config, eventName){
13859     this.el  = Roo.get(el);
13860     this.eventName = eventName || "keydown";
13861     this.bindings = [];
13862     if(config){
13863         this.addBinding(config);
13864     }
13865     this.enable();
13866 };
13867
13868 Roo.KeyMap.prototype = {
13869     /**
13870      * True to stop the event from bubbling and prevent the default browser action if the
13871      * key was handled by the KeyMap (defaults to false)
13872      * @type Boolean
13873      */
13874     stopEvent : false,
13875
13876     /**
13877      * Add a new binding to this KeyMap. The following config object properties are supported:
13878      * <pre>
13879 Property    Type             Description
13880 ----------  ---------------  ----------------------------------------------------------------------
13881 key         String/Array     A single keycode or an array of keycodes to handle
13882 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13883 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13884 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13885 fn          Function         The function to call when KeyMap finds the expected key combination
13886 scope       Object           The scope of the callback function
13887 </pre>
13888      *
13889      * Usage:
13890      * <pre><code>
13891 // Create a KeyMap
13892 var map = new Roo.KeyMap(document, {
13893     key: Roo.EventObject.ENTER,
13894     fn: handleKey,
13895     scope: this
13896 });
13897
13898 //Add a new binding to the existing KeyMap later
13899 map.addBinding({
13900     key: 'abc',
13901     shift: true,
13902     fn: handleKey,
13903     scope: this
13904 });
13905 </code></pre>
13906      * @param {Object/Array} config A single KeyMap config or an array of configs
13907      */
13908         addBinding : function(config){
13909         if(config instanceof Array){
13910             for(var i = 0, len = config.length; i < len; i++){
13911                 this.addBinding(config[i]);
13912             }
13913             return;
13914         }
13915         var keyCode = config.key,
13916             shift = config.shift, 
13917             ctrl = config.ctrl, 
13918             alt = config.alt,
13919             fn = config.fn,
13920             scope = config.scope;
13921         if(typeof keyCode == "string"){
13922             var ks = [];
13923             var keyString = keyCode.toUpperCase();
13924             for(var j = 0, len = keyString.length; j < len; j++){
13925                 ks.push(keyString.charCodeAt(j));
13926             }
13927             keyCode = ks;
13928         }
13929         var keyArray = keyCode instanceof Array;
13930         var handler = function(e){
13931             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13932                 var k = e.getKey();
13933                 if(keyArray){
13934                     for(var i = 0, len = keyCode.length; i < len; i++){
13935                         if(keyCode[i] == k){
13936                           if(this.stopEvent){
13937                               e.stopEvent();
13938                           }
13939                           fn.call(scope || window, k, e);
13940                           return;
13941                         }
13942                     }
13943                 }else{
13944                     if(k == keyCode){
13945                         if(this.stopEvent){
13946                            e.stopEvent();
13947                         }
13948                         fn.call(scope || window, k, e);
13949                     }
13950                 }
13951             }
13952         };
13953         this.bindings.push(handler);  
13954         },
13955
13956     /**
13957      * Shorthand for adding a single key listener
13958      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13959      * following options:
13960      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13961      * @param {Function} fn The function to call
13962      * @param {Object} scope (optional) The scope of the function
13963      */
13964     on : function(key, fn, scope){
13965         var keyCode, shift, ctrl, alt;
13966         if(typeof key == "object" && !(key instanceof Array)){
13967             keyCode = key.key;
13968             shift = key.shift;
13969             ctrl = key.ctrl;
13970             alt = key.alt;
13971         }else{
13972             keyCode = key;
13973         }
13974         this.addBinding({
13975             key: keyCode,
13976             shift: shift,
13977             ctrl: ctrl,
13978             alt: alt,
13979             fn: fn,
13980             scope: scope
13981         })
13982     },
13983
13984     // private
13985     handleKeyDown : function(e){
13986             if(this.enabled){ //just in case
13987             var b = this.bindings;
13988             for(var i = 0, len = b.length; i < len; i++){
13989                 b[i].call(this, e);
13990             }
13991             }
13992         },
13993         
13994         /**
13995          * Returns true if this KeyMap is enabled
13996          * @return {Boolean} 
13997          */
13998         isEnabled : function(){
13999             return this.enabled;  
14000         },
14001         
14002         /**
14003          * Enables this KeyMap
14004          */
14005         enable: function(){
14006                 if(!this.enabled){
14007                     this.el.on(this.eventName, this.handleKeyDown, this);
14008                     this.enabled = true;
14009                 }
14010         },
14011
14012         /**
14013          * Disable this KeyMap
14014          */
14015         disable: function(){
14016                 if(this.enabled){
14017                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14018                     this.enabled = false;
14019                 }
14020         }
14021 };/*
14022  * Based on:
14023  * Ext JS Library 1.1.1
14024  * Copyright(c) 2006-2007, Ext JS, LLC.
14025  *
14026  * Originally Released Under LGPL - original licence link has changed is not relivant.
14027  *
14028  * Fork - LGPL
14029  * <script type="text/javascript">
14030  */
14031
14032  
14033 /**
14034  * @class Roo.util.TextMetrics
14035  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14036  * wide, in pixels, a given block of text will be.
14037  * @singleton
14038  */
14039 Roo.util.TextMetrics = function(){
14040     var shared;
14041     return {
14042         /**
14043          * Measures the size of the specified text
14044          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14045          * that can affect the size of the rendered text
14046          * @param {String} text The text to measure
14047          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14048          * in order to accurately measure the text height
14049          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14050          */
14051         measure : function(el, text, fixedWidth){
14052             if(!shared){
14053                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14054             }
14055             shared.bind(el);
14056             shared.setFixedWidth(fixedWidth || 'auto');
14057             return shared.getSize(text);
14058         },
14059
14060         /**
14061          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14062          * the overhead of multiple calls to initialize the style properties on each measurement.
14063          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14064          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14065          * in order to accurately measure the text height
14066          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14067          */
14068         createInstance : function(el, fixedWidth){
14069             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14070         }
14071     };
14072 }();
14073
14074  
14075
14076 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14077     var ml = new Roo.Element(document.createElement('div'));
14078     document.body.appendChild(ml.dom);
14079     ml.position('absolute');
14080     ml.setLeftTop(-1000, -1000);
14081     ml.hide();
14082
14083     if(fixedWidth){
14084         ml.setWidth(fixedWidth);
14085     }
14086      
14087     var instance = {
14088         /**
14089          * Returns the size of the specified text based on the internal element's style and width properties
14090          * @memberOf Roo.util.TextMetrics.Instance#
14091          * @param {String} text The text to measure
14092          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14093          */
14094         getSize : function(text){
14095             ml.update(text);
14096             var s = ml.getSize();
14097             ml.update('');
14098             return s;
14099         },
14100
14101         /**
14102          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14103          * that can affect the size of the rendered text
14104          * @memberOf Roo.util.TextMetrics.Instance#
14105          * @param {String/HTMLElement} el The element, dom node or id
14106          */
14107         bind : function(el){
14108             ml.setStyle(
14109                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14110             );
14111         },
14112
14113         /**
14114          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14115          * to set a fixed width in order to accurately measure the text height.
14116          * @memberOf Roo.util.TextMetrics.Instance#
14117          * @param {Number} width The width to set on the element
14118          */
14119         setFixedWidth : function(width){
14120             ml.setWidth(width);
14121         },
14122
14123         /**
14124          * Returns the measured width of the specified text
14125          * @memberOf Roo.util.TextMetrics.Instance#
14126          * @param {String} text The text to measure
14127          * @return {Number} width The width in pixels
14128          */
14129         getWidth : function(text){
14130             ml.dom.style.width = 'auto';
14131             return this.getSize(text).width;
14132         },
14133
14134         /**
14135          * Returns the measured height of the specified text.  For multiline text, be sure to call
14136          * {@link #setFixedWidth} if necessary.
14137          * @memberOf Roo.util.TextMetrics.Instance#
14138          * @param {String} text The text to measure
14139          * @return {Number} height The height in pixels
14140          */
14141         getHeight : function(text){
14142             return this.getSize(text).height;
14143         }
14144     };
14145
14146     instance.bind(bindTo);
14147
14148     return instance;
14149 };
14150
14151 // backwards compat
14152 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14153  * Based on:
14154  * Ext JS Library 1.1.1
14155  * Copyright(c) 2006-2007, Ext JS, LLC.
14156  *
14157  * Originally Released Under LGPL - original licence link has changed is not relivant.
14158  *
14159  * Fork - LGPL
14160  * <script type="text/javascript">
14161  */
14162
14163 /**
14164  * @class Roo.state.Provider
14165  * Abstract base class for state provider implementations. This class provides methods
14166  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14167  * Provider interface.
14168  */
14169 Roo.state.Provider = function(){
14170     /**
14171      * @event statechange
14172      * Fires when a state change occurs.
14173      * @param {Provider} this This state provider
14174      * @param {String} key The state key which was changed
14175      * @param {String} value The encoded value for the state
14176      */
14177     this.addEvents({
14178         "statechange": true
14179     });
14180     this.state = {};
14181     Roo.state.Provider.superclass.constructor.call(this);
14182 };
14183 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14184     /**
14185      * Returns the current value for a key
14186      * @param {String} name The key name
14187      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14188      * @return {Mixed} The state data
14189      */
14190     get : function(name, defaultValue){
14191         return typeof this.state[name] == "undefined" ?
14192             defaultValue : this.state[name];
14193     },
14194     
14195     /**
14196      * Clears a value from the state
14197      * @param {String} name The key name
14198      */
14199     clear : function(name){
14200         delete this.state[name];
14201         this.fireEvent("statechange", this, name, null);
14202     },
14203     
14204     /**
14205      * Sets the value for a key
14206      * @param {String} name The key name
14207      * @param {Mixed} value The value to set
14208      */
14209     set : function(name, value){
14210         this.state[name] = value;
14211         this.fireEvent("statechange", this, name, value);
14212     },
14213     
14214     /**
14215      * Decodes a string previously encoded with {@link #encodeValue}.
14216      * @param {String} value The value to decode
14217      * @return {Mixed} The decoded value
14218      */
14219     decodeValue : function(cookie){
14220         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14221         var matches = re.exec(unescape(cookie));
14222         if(!matches || !matches[1]) return; // non state cookie
14223         var type = matches[1];
14224         var v = matches[2];
14225         switch(type){
14226             case "n":
14227                 return parseFloat(v);
14228             case "d":
14229                 return new Date(Date.parse(v));
14230             case "b":
14231                 return (v == "1");
14232             case "a":
14233                 var all = [];
14234                 var values = v.split("^");
14235                 for(var i = 0, len = values.length; i < len; i++){
14236                     all.push(this.decodeValue(values[i]));
14237                 }
14238                 return all;
14239            case "o":
14240                 var all = {};
14241                 var values = v.split("^");
14242                 for(var i = 0, len = values.length; i < len; i++){
14243                     var kv = values[i].split("=");
14244                     all[kv[0]] = this.decodeValue(kv[1]);
14245                 }
14246                 return all;
14247            default:
14248                 return v;
14249         }
14250     },
14251     
14252     /**
14253      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14254      * @param {Mixed} value The value to encode
14255      * @return {String} The encoded value
14256      */
14257     encodeValue : function(v){
14258         var enc;
14259         if(typeof v == "number"){
14260             enc = "n:" + v;
14261         }else if(typeof v == "boolean"){
14262             enc = "b:" + (v ? "1" : "0");
14263         }else if(v instanceof Date){
14264             enc = "d:" + v.toGMTString();
14265         }else if(v instanceof Array){
14266             var flat = "";
14267             for(var i = 0, len = v.length; i < len; i++){
14268                 flat += this.encodeValue(v[i]);
14269                 if(i != len-1) flat += "^";
14270             }
14271             enc = "a:" + flat;
14272         }else if(typeof v == "object"){
14273             var flat = "";
14274             for(var key in v){
14275                 if(typeof v[key] != "function"){
14276                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14277                 }
14278             }
14279             enc = "o:" + flat.substring(0, flat.length-1);
14280         }else{
14281             enc = "s:" + v;
14282         }
14283         return escape(enc);        
14284     }
14285 });
14286
14287 /*
14288  * Based on:
14289  * Ext JS Library 1.1.1
14290  * Copyright(c) 2006-2007, Ext JS, LLC.
14291  *
14292  * Originally Released Under LGPL - original licence link has changed is not relivant.
14293  *
14294  * Fork - LGPL
14295  * <script type="text/javascript">
14296  */
14297 /**
14298  * @class Roo.state.Manager
14299  * This is the global state manager. By default all components that are "state aware" check this class
14300  * for state information if you don't pass them a custom state provider. In order for this class
14301  * to be useful, it must be initialized with a provider when your application initializes.
14302  <pre><code>
14303 // in your initialization function
14304 init : function(){
14305    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14306    ...
14307    // supposed you have a {@link Roo.BorderLayout}
14308    var layout = new Roo.BorderLayout(...);
14309    layout.restoreState();
14310    // or a {Roo.BasicDialog}
14311    var dialog = new Roo.BasicDialog(...);
14312    dialog.restoreState();
14313  </code></pre>
14314  * @singleton
14315  */
14316 Roo.state.Manager = function(){
14317     var provider = new Roo.state.Provider();
14318     
14319     return {
14320         /**
14321          * Configures the default state provider for your application
14322          * @param {Provider} stateProvider The state provider to set
14323          */
14324         setProvider : function(stateProvider){
14325             provider = stateProvider;
14326         },
14327         
14328         /**
14329          * Returns the current value for a key
14330          * @param {String} name The key name
14331          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14332          * @return {Mixed} The state data
14333          */
14334         get : function(key, defaultValue){
14335             return provider.get(key, defaultValue);
14336         },
14337         
14338         /**
14339          * Sets the value for a key
14340          * @param {String} name The key name
14341          * @param {Mixed} value The state data
14342          */
14343          set : function(key, value){
14344             provider.set(key, value);
14345         },
14346         
14347         /**
14348          * Clears a value from the state
14349          * @param {String} name The key name
14350          */
14351         clear : function(key){
14352             provider.clear(key);
14353         },
14354         
14355         /**
14356          * Gets the currently configured state provider
14357          * @return {Provider} The state provider
14358          */
14359         getProvider : function(){
14360             return provider;
14361         }
14362     };
14363 }();
14364 /*
14365  * Based on:
14366  * Ext JS Library 1.1.1
14367  * Copyright(c) 2006-2007, Ext JS, LLC.
14368  *
14369  * Originally Released Under LGPL - original licence link has changed is not relivant.
14370  *
14371  * Fork - LGPL
14372  * <script type="text/javascript">
14373  */
14374 /**
14375  * @class Roo.state.CookieProvider
14376  * @extends Roo.state.Provider
14377  * The default Provider implementation which saves state via cookies.
14378  * <br />Usage:
14379  <pre><code>
14380    var cp = new Roo.state.CookieProvider({
14381        path: "/cgi-bin/",
14382        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14383        domain: "roojs.com"
14384    })
14385    Roo.state.Manager.setProvider(cp);
14386  </code></pre>
14387  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14388  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14389  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14390  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14391  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14392  * domain the page is running on including the 'www' like 'www.roojs.com')
14393  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14394  * @constructor
14395  * Create a new CookieProvider
14396  * @param {Object} config The configuration object
14397  */
14398 Roo.state.CookieProvider = function(config){
14399     Roo.state.CookieProvider.superclass.constructor.call(this);
14400     this.path = "/";
14401     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14402     this.domain = null;
14403     this.secure = false;
14404     Roo.apply(this, config);
14405     this.state = this.readCookies();
14406 };
14407
14408 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14409     // private
14410     set : function(name, value){
14411         if(typeof value == "undefined" || value === null){
14412             this.clear(name);
14413             return;
14414         }
14415         this.setCookie(name, value);
14416         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14417     },
14418
14419     // private
14420     clear : function(name){
14421         this.clearCookie(name);
14422         Roo.state.CookieProvider.superclass.clear.call(this, name);
14423     },
14424
14425     // private
14426     readCookies : function(){
14427         var cookies = {};
14428         var c = document.cookie + ";";
14429         var re = /\s?(.*?)=(.*?);/g;
14430         var matches;
14431         while((matches = re.exec(c)) != null){
14432             var name = matches[1];
14433             var value = matches[2];
14434             if(name && name.substring(0,3) == "ys-"){
14435                 cookies[name.substr(3)] = this.decodeValue(value);
14436             }
14437         }
14438         return cookies;
14439     },
14440
14441     // private
14442     setCookie : function(name, value){
14443         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14444            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14445            ((this.path == null) ? "" : ("; path=" + this.path)) +
14446            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14447            ((this.secure == true) ? "; secure" : "");
14448     },
14449
14450     // private
14451     clearCookie : function(name){
14452         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14453            ((this.path == null) ? "" : ("; path=" + this.path)) +
14454            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14455            ((this.secure == true) ? "; secure" : "");
14456     }
14457 });