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