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         isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
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                 Roo.log('extend!!!!');
210                 Roo.log(sb);
211                 Roo.log(sp);
212                 Roo.log(overrides);
213                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
214                     overrides = sp;
215                     sp = sb;
216                     sb = function(){sp.apply(this, arguments);};
217                 }
218                 var F = function(){}, sbp, spp = sp.prototype;
219                 F.prototype = spp;
220                 sbp = sb.prototype = new F();
221                 sbp.constructor=sb;
222                 sb.superclass=spp;
223                 
224                 if(spp.constructor == Object.prototype.constructor){
225                     spp.constructor=sp;
226                    
227                 }
228                 
229                 sb.override = function(o){
230                     Roo.override(sb, o);
231                 };
232                 sbp.override = io;
233                 Roo.override(sb, overrides);
234                 return sb;
235             };
236         }(),
237
238         /**
239          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
240          * Usage:<pre><code>
241 Roo.override(MyClass, {
242     newMethod1: function(){
243         // etc.
244     },
245     newMethod2: function(foo){
246         // etc.
247     }
248 });
249  </code></pre>
250          * @param {Object} origclass The class to override
251          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
252          * containing one or more methods.
253          * @method override
254          */
255         override : function(origclass, overrides){
256             if(overrides){
257                 var p = origclass.prototype;
258                 for(var method in overrides){
259                     p[method] = overrides[method];
260                 }
261             }
262         },
263         /**
264          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
265          * <pre><code>
266 Roo.namespace('Company', 'Company.data');
267 Company.Widget = function() { ... }
268 Company.data.CustomStore = function(config) { ... }
269 </code></pre>
270          * @param {String} namespace1
271          * @param {String} namespace2
272          * @param {String} etc
273          * @method namespace
274          */
275         namespace : function(){
276             var a=arguments, o=null, i, j, d, rt;
277             for (i=0; i<a.length; ++i) {
278                 d=a[i].split(".");
279                 rt = d[0];
280                 /** eval:var:o */
281                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
282                 for (j=1; j<d.length; ++j) {
283                     o[d[j]]=o[d[j]] || {};
284                     o=o[d[j]];
285                 }
286             }
287         },
288         /**
289          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
290          * <pre><code>
291 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
292 Roo.factory(conf, Roo.data);
293 </code></pre>
294          * @param {String} classname
295          * @param {String} namespace (optional)
296          * @method factory
297          */
298          
299         factory : function(c, ns)
300         {
301             // no xtype, no ns or c.xns - or forced off by c.xns
302             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
303                 return c;
304             }
305             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
306             if (c.constructor == ns[c.xtype]) {// already created...
307                 return c;
308             }
309             if (ns[c.xtype]) {
310                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
311                 var ret = new ns[c.xtype](c);
312                 ret.xns = false;
313                 return ret;
314             }
315             c.xns = false; // prevent recursion..
316             return c;
317         },
318          /**
319          * Logs to console if it can.
320          *
321          * @param {String|Object} string
322          * @method log
323          */
324         log : function(s)
325         {
326             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
327                 return; // alerT?
328             }
329             console.log(s);
330             
331         },
332         /**
333          * 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.
334          * @param {Object} o
335          * @return {String}
336          */
337         urlEncode : function(o){
338             if(!o){
339                 return "";
340             }
341             var buf = [];
342             for(var key in o){
343                 var ov = o[key], k = Roo.encodeURIComponent(key);
344                 var type = typeof ov;
345                 if(type == 'undefined'){
346                     buf.push(k, "=&");
347                 }else if(type != "function" && type != "object"){
348                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
349                 }else if(ov instanceof Array){
350                     if (ov.length) {
351                             for(var i = 0, len = ov.length; i < len; i++) {
352                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
353                             }
354                         } else {
355                             buf.push(k, "=&");
356                         }
357                 }
358             }
359             buf.pop();
360             return buf.join("");
361         },
362          /**
363          * Safe version of encodeURIComponent
364          * @param {String} data 
365          * @return {String} 
366          */
367         
368         encodeURIComponent : function (data)
369         {
370             try {
371                 return encodeURIComponent(data);
372             } catch(e) {} // should be an uri encode error.
373             
374             if (data == '' || data == null){
375                return '';
376             }
377             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
378             function nibble_to_hex(nibble){
379                 var chars = '0123456789ABCDEF';
380                 return chars.charAt(nibble);
381             }
382             data = data.toString();
383             var buffer = '';
384             for(var i=0; i<data.length; i++){
385                 var c = data.charCodeAt(i);
386                 var bs = new Array();
387                 if (c > 0x10000){
388                         // 4 bytes
389                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
390                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
391                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
392                     bs[3] = 0x80 | (c & 0x3F);
393                 }else if (c > 0x800){
394                          // 3 bytes
395                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
396                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
397                     bs[2] = 0x80 | (c & 0x3F);
398                 }else if (c > 0x80){
399                        // 2 bytes
400                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
401                     bs[1] = 0x80 | (c & 0x3F);
402                 }else{
403                         // 1 byte
404                     bs[0] = c;
405                 }
406                 for(var j=0; j<bs.length; j++){
407                     var b = bs[j];
408                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
409                             + nibble_to_hex(b &0x0F);
410                     buffer += '%'+hex;
411                }
412             }
413             return buffer;    
414              
415         },
416
417         /**
418          * 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]}.
419          * @param {String} string
420          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
421          * @return {Object} A literal with members
422          */
423         urlDecode : function(string, overwrite){
424             if(!string || !string.length){
425                 return {};
426             }
427             var obj = {};
428             var pairs = string.split('&');
429             var pair, name, value;
430             for(var i = 0, len = pairs.length; i < len; i++){
431                 pair = pairs[i].split('=');
432                 name = decodeURIComponent(pair[0]);
433                 value = decodeURIComponent(pair[1]);
434                 if(overwrite !== true){
435                     if(typeof obj[name] == "undefined"){
436                         obj[name] = value;
437                     }else if(typeof obj[name] == "string"){
438                         obj[name] = [obj[name]];
439                         obj[name].push(value);
440                     }else{
441                         obj[name].push(value);
442                     }
443                 }else{
444                     obj[name] = value;
445                 }
446             }
447             return obj;
448         },
449
450         /**
451          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
452          * passed array is not really an array, your function is called once with it.
453          * The supplied function is called with (Object item, Number index, Array allItems).
454          * @param {Array/NodeList/Mixed} array
455          * @param {Function} fn
456          * @param {Object} scope
457          */
458         each : function(array, fn, scope){
459             if(typeof array.length == "undefined" || typeof array == "string"){
460                 array = [array];
461             }
462             for(var i = 0, len = array.length; i < len; i++){
463                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464             }
465         },
466
467         // deprecated
468         combine : function(){
469             var as = arguments, l = as.length, r = [];
470             for(var i = 0; i < l; i++){
471                 var a = as[i];
472                 if(a instanceof Array){
473                     r = r.concat(a);
474                 }else if(a.length !== undefined && !a.substr){
475                     r = r.concat(Array.prototype.slice.call(a, 0));
476                 }else{
477                     r.push(a);
478                 }
479             }
480             return r;
481         },
482
483         /**
484          * Escapes the passed string for use in a regular expression
485          * @param {String} str
486          * @return {String}
487          */
488         escapeRe : function(s) {
489             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
490         },
491
492         // internal
493         callback : function(cb, scope, args, delay){
494             if(typeof cb == "function"){
495                 if(delay){
496                     cb.defer(delay, scope, args || []);
497                 }else{
498                     cb.apply(scope, args || []);
499                 }
500             }
501         },
502
503         /**
504          * Return the dom node for the passed string (id), dom node, or Roo.Element
505          * @param {String/HTMLElement/Roo.Element} el
506          * @return HTMLElement
507          */
508         getDom : function(el){
509             if(!el){
510                 return null;
511             }
512             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
513         },
514
515         /**
516         * Shorthand for {@link Roo.ComponentMgr#get}
517         * @param {String} id
518         * @return Roo.Component
519         */
520         getCmp : function(id){
521             return Roo.ComponentMgr.get(id);
522         },
523          
524         num : function(v, defaultValue){
525             if(typeof v != 'number'){
526                 return defaultValue;
527             }
528             return v;
529         },
530
531         destroy : function(){
532             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
533                 var as = a[i];
534                 if(as){
535                     if(as.dom){
536                         as.removeAllListeners();
537                         as.remove();
538                         continue;
539                     }
540                     if(typeof as.purgeListeners == 'function'){
541                         as.purgeListeners();
542                     }
543                     if(typeof as.destroy == 'function'){
544                         as.destroy();
545                     }
546                 }
547             }
548         },
549
550         // inpired by a similar function in mootools library
551         /**
552          * Returns the type of object that is passed in. If the object passed in is null or undefined it
553          * return false otherwise it returns one of the following values:<ul>
554          * <li><b>string</b>: If the object passed is a string</li>
555          * <li><b>number</b>: If the object passed is a number</li>
556          * <li><b>boolean</b>: If the object passed is a boolean value</li>
557          * <li><b>function</b>: If the object passed is a function reference</li>
558          * <li><b>object</b>: If the object passed is an object</li>
559          * <li><b>array</b>: If the object passed is an array</li>
560          * <li><b>regexp</b>: If the object passed is a regular expression</li>
561          * <li><b>element</b>: If the object passed is a DOM Element</li>
562          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
563          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
564          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
565          * @param {Mixed} object
566          * @return {String}
567          */
568         type : function(o){
569             if(o === undefined || o === null){
570                 return false;
571             }
572             if(o.htmlElement){
573                 return 'element';
574             }
575             var t = typeof o;
576             if(t == 'object' && o.nodeName) {
577                 switch(o.nodeType) {
578                     case 1: return 'element';
579                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
580                 }
581             }
582             if(t == 'object' || t == 'function') {
583                 switch(o.constructor) {
584                     case Array: return 'array';
585                     case RegExp: return 'regexp';
586                 }
587                 if(typeof o.length == 'number' && typeof o.item == 'function') {
588                     return 'nodelist';
589                 }
590             }
591             return t;
592         },
593
594         /**
595          * Returns true if the passed value is null, undefined or an empty string (optional).
596          * @param {Mixed} value The value to test
597          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
598          * @return {Boolean}
599          */
600         isEmpty : function(v, allowBlank){
601             return v === null || v === undefined || (!allowBlank ? v === '' : false);
602         },
603         
604         /** @type Boolean */
605         isOpera : isOpera,
606         /** @type Boolean */
607         isSafari : isSafari,
608         /** @type Boolean */
609         isIE : isIE,
610         /** @type Boolean */
611         isIE7 : isIE7,
612         /** @type Boolean */
613         isGecko : isGecko,
614         /** @type Boolean */
615         isBorderBox : isBorderBox,
616         /** @type Boolean */
617         isWindows : isWindows,
618         /** @type Boolean */
619         isLinux : isLinux,
620         /** @type Boolean */
621         isMac : isMac,
622         /** @type Boolean */
623         isTouch : isTouch,
624
625         /**
626          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
627          * you may want to set this to true.
628          * @type Boolean
629          */
630         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
631         
632         
633                 
634         /**
635          * Selects a single element as a Roo Element
636          * This is about as close as you can get to jQuery's $('do crazy stuff')
637          * @param {String} selector The selector/xpath query
638          * @param {Node} root (optional) The start of the query (defaults to document).
639          * @return {Roo.Element}
640          */
641         selectNode : function(selector, root) 
642         {
643             var node = Roo.DomQuery.selectNode(selector,root);
644             return node ? Roo.get(node) : new Roo.Element(false);
645         }
646         
647     });
648
649
650 })();
651
652 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
653                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
654 /*
655  * Based on:
656  * Ext JS Library 1.1.1
657  * Copyright(c) 2006-2007, Ext JS, LLC.
658  *
659  * Originally Released Under LGPL - original licence link has changed is not relivant.
660  *
661  * Fork - LGPL
662  * <script type="text/javascript">
663  */
664
665 (function() {    
666     // wrappedn so fnCleanup is not in global scope...
667     if(Roo.isIE) {
668         function fnCleanUp() {
669             var p = Function.prototype;
670             delete p.createSequence;
671             delete p.defer;
672             delete p.createDelegate;
673             delete p.createCallback;
674             delete p.createInterceptor;
675
676             window.detachEvent("onunload", fnCleanUp);
677         }
678         window.attachEvent("onunload", fnCleanUp);
679     }
680 })();
681
682
683 /**
684  * @class Function
685  * These functions are available on every Function object (any JavaScript function).
686  */
687 Roo.apply(Function.prototype, {
688      /**
689      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
690      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
691      * Will create a function that is bound to those 2 args.
692      * @return {Function} The new function
693     */
694     createCallback : function(/*args...*/){
695         // make args available, in function below
696         var args = arguments;
697         var method = this;
698         return function() {
699             return method.apply(window, args);
700         };
701     },
702
703     /**
704      * Creates a delegate (callback) that sets the scope to obj.
705      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
706      * Will create a function that is automatically scoped to this.
707      * @param {Object} obj (optional) The object for which the scope is set
708      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
709      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
710      *                                             if a number the args are inserted at the specified position
711      * @return {Function} The new function
712      */
713     createDelegate : function(obj, args, appendArgs){
714         var method = this;
715         return function() {
716             var callArgs = args || arguments;
717             if(appendArgs === true){
718                 callArgs = Array.prototype.slice.call(arguments, 0);
719                 callArgs = callArgs.concat(args);
720             }else if(typeof appendArgs == "number"){
721                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
722                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
723                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
724             }
725             return method.apply(obj || window, callArgs);
726         };
727     },
728
729     /**
730      * Calls this function after the number of millseconds specified.
731      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
732      * @param {Object} obj (optional) The object for which the scope is set
733      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
734      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
735      *                                             if a number the args are inserted at the specified position
736      * @return {Number} The timeout id that can be used with clearTimeout
737      */
738     defer : function(millis, obj, args, appendArgs){
739         var fn = this.createDelegate(obj, args, appendArgs);
740         if(millis){
741             return setTimeout(fn, millis);
742         }
743         fn();
744         return 0;
745     },
746     /**
747      * Create a combined function call sequence of the original function + the passed function.
748      * The resulting function returns the results of the original function.
749      * The passed fcn is called with the parameters of the original function
750      * @param {Function} fcn The function to sequence
751      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
752      * @return {Function} The new function
753      */
754     createSequence : function(fcn, scope){
755         if(typeof fcn != "function"){
756             return this;
757         }
758         var method = this;
759         return function() {
760             var retval = method.apply(this || window, arguments);
761             fcn.apply(scope || this || window, arguments);
762             return retval;
763         };
764     },
765
766     /**
767      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
768      * The resulting function returns the results of the original function.
769      * The passed fcn is called with the parameters of the original function.
770      * @addon
771      * @param {Function} fcn The function to call before the original
772      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
773      * @return {Function} The new function
774      */
775     createInterceptor : function(fcn, scope){
776         if(typeof fcn != "function"){
777             return this;
778         }
779         var method = this;
780         return function() {
781             fcn.target = this;
782             fcn.method = method;
783             if(fcn.apply(scope || this || window, arguments) === false){
784                 return;
785             }
786             return method.apply(this || window, arguments);
787         };
788     }
789 });
790 /*
791  * Based on:
792  * Ext JS Library 1.1.1
793  * Copyright(c) 2006-2007, Ext JS, LLC.
794  *
795  * Originally Released Under LGPL - original licence link has changed is not relivant.
796  *
797  * Fork - LGPL
798  * <script type="text/javascript">
799  */
800
801 Roo.applyIf(String, {
802     
803     /** @scope String */
804     
805     /**
806      * Escapes the passed string for ' and \
807      * @param {String} string The string to escape
808      * @return {String} The escaped string
809      * @static
810      */
811     escape : function(string) {
812         return string.replace(/('|\\)/g, "\\$1");
813     },
814
815     /**
816      * Pads the left side of a string with a specified character.  This is especially useful
817      * for normalizing number and date strings.  Example usage:
818      * <pre><code>
819 var s = String.leftPad('123', 5, '0');
820 // s now contains the string: '00123'
821 </code></pre>
822      * @param {String} string The original string
823      * @param {Number} size The total length of the output string
824      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
825      * @return {String} The padded string
826      * @static
827      */
828     leftPad : function (val, size, ch) {
829         var result = new String(val);
830         if(ch === null || ch === undefined || ch === '') {
831             ch = " ";
832         }
833         while (result.length < size) {
834             result = ch + result;
835         }
836         return result;
837     },
838
839     /**
840      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
841      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
842      * <pre><code>
843 var cls = 'my-class', text = 'Some text';
844 var s = String.format('<div class="{0}">{1}</div>', cls, text);
845 // s now contains the string: '<div class="my-class">Some text</div>'
846 </code></pre>
847      * @param {String} string The tokenized string to be formatted
848      * @param {String} value1 The value to replace token {0}
849      * @param {String} value2 Etc...
850      * @return {String} The formatted string
851      * @static
852      */
853     format : function(format){
854         var args = Array.prototype.slice.call(arguments, 1);
855         return format.replace(/\{(\d+)\}/g, function(m, i){
856             return Roo.util.Format.htmlEncode(args[i]);
857         });
858     }
859 });
860
861 /**
862  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
863  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
864  * they are already different, the first value passed in is returned.  Note that this method returns the new value
865  * but does not change the current string.
866  * <pre><code>
867 // alternate sort directions
868 sort = sort.toggle('ASC', 'DESC');
869
870 // instead of conditional logic:
871 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
872 </code></pre>
873  * @param {String} value The value to compare to the current string
874  * @param {String} other The new value to use if the string already equals the first value passed in
875  * @return {String} The new value
876  */
877  
878 String.prototype.toggle = function(value, other){
879     return this == value ? other : value;
880 };/*
881  * Based on:
882  * Ext JS Library 1.1.1
883  * Copyright(c) 2006-2007, Ext JS, LLC.
884  *
885  * Originally Released Under LGPL - original licence link has changed is not relivant.
886  *
887  * Fork - LGPL
888  * <script type="text/javascript">
889  */
890
891  /**
892  * @class Number
893  */
894 Roo.applyIf(Number.prototype, {
895     /**
896      * Checks whether or not the current number is within a desired range.  If the number is already within the
897      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
898      * exceeded.  Note that this method returns the constrained value but does not change the current number.
899      * @param {Number} min The minimum number in the range
900      * @param {Number} max The maximum number in the range
901      * @return {Number} The constrained value if outside the range, otherwise the current value
902      */
903     constrain : function(min, max){
904         return Math.min(Math.max(this, min), max);
905     }
906 });/*
907  * Based on:
908  * Ext JS Library 1.1.1
909  * Copyright(c) 2006-2007, Ext JS, LLC.
910  *
911  * Originally Released Under LGPL - original licence link has changed is not relivant.
912  *
913  * Fork - LGPL
914  * <script type="text/javascript">
915  */
916  /**
917  * @class Array
918  */
919 Roo.applyIf(Array.prototype, {
920     /**
921      * Checks whether or not the specified object exists in the array.
922      * @param {Object} o The object to check for
923      * @return {Number} The index of o in the array (or -1 if it is not found)
924      */
925     indexOf : function(o){
926        for (var i = 0, len = this.length; i < len; i++){
927               if(this[i] == o) return i;
928        }
929            return -1;
930     },
931
932     /**
933      * Removes the specified object from the array.  If the object is not found nothing happens.
934      * @param {Object} o The object to remove
935      */
936     remove : function(o){
937        var index = this.indexOf(o);
938        if(index != -1){
939            this.splice(index, 1);
940        }
941     },
942     /**
943      * Map (JS 1.6 compatibility)
944      * @param {Function} function  to call
945      */
946     map : function(fun )
947     {
948         var len = this.length >>> 0;
949         if (typeof fun != "function")
950             throw new TypeError();
951
952         var res = new Array(len);
953         var thisp = arguments[1];
954         for (var i = 0; i < len; i++)
955         {
956             if (i in this)
957                 res[i] = fun.call(thisp, this[i], i, this);
958         }
959
960         return res;
961     }
962     
963 });
964
965
966  /*
967  * Based on:
968  * Ext JS Library 1.1.1
969  * Copyright(c) 2006-2007, Ext JS, LLC.
970  *
971  * Originally Released Under LGPL - original licence link has changed is not relivant.
972  *
973  * Fork - LGPL
974  * <script type="text/javascript">
975  */
976
977 /**
978  * @class Date
979  *
980  * The date parsing and format syntax is a subset of
981  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
982  * supported will provide results equivalent to their PHP versions.
983  *
984  * Following is the list of all currently supported formats:
985  *<pre>
986 Sample date:
987 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
988
989 Format  Output      Description
990 ------  ----------  --------------------------------------------------------------
991   d      10         Day of the month, 2 digits with leading zeros
992   D      Wed        A textual representation of a day, three letters
993   j      10         Day of the month without leading zeros
994   l      Wednesday  A full textual representation of the day of the week
995   S      th         English ordinal day of month suffix, 2 chars (use with j)
996   w      3          Numeric representation of the day of the week
997   z      9          The julian date, or day of the year (0-365)
998   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
999   F      January    A full textual representation of the month
1000   m      01         Numeric representation of a month, with leading zeros
1001   M      Jan        Month name abbreviation, three letters
1002   n      1          Numeric representation of a month, without leading zeros
1003   t      31         Number of days in the given month
1004   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1005   Y      2007       A full numeric representation of a year, 4 digits
1006   y      07         A two digit representation of a year
1007   a      pm         Lowercase Ante meridiem and Post meridiem
1008   A      PM         Uppercase Ante meridiem and Post meridiem
1009   g      3          12-hour format of an hour without leading zeros
1010   G      15         24-hour format of an hour without leading zeros
1011   h      03         12-hour format of an hour with leading zeros
1012   H      15         24-hour format of an hour with leading zeros
1013   i      05         Minutes with leading zeros
1014   s      01         Seconds, with leading zeros
1015   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1016   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1017   T      CST        Timezone setting of the machine running the code
1018   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1019 </pre>
1020  *
1021  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1022  * <pre><code>
1023 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1024 document.write(dt.format('Y-m-d'));                         //2007-01-10
1025 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1026 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
1027  </code></pre>
1028  *
1029  * Here are some standard date/time patterns that you might find helpful.  They
1030  * are not part of the source of Date.js, but to use them you can simply copy this
1031  * block of code into any script that is included after Date.js and they will also become
1032  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1033  * <pre><code>
1034 Date.patterns = {
1035     ISO8601Long:"Y-m-d H:i:s",
1036     ISO8601Short:"Y-m-d",
1037     ShortDate: "n/j/Y",
1038     LongDate: "l, F d, Y",
1039     FullDateTime: "l, F d, Y g:i:s A",
1040     MonthDay: "F d",
1041     ShortTime: "g:i A",
1042     LongTime: "g:i:s A",
1043     SortableDateTime: "Y-m-d\\TH:i:s",
1044     UniversalSortableDateTime: "Y-m-d H:i:sO",
1045     YearMonth: "F, Y"
1046 };
1047 </code></pre>
1048  *
1049  * Example usage:
1050  * <pre><code>
1051 var dt = new Date();
1052 document.write(dt.format(Date.patterns.ShortDate));
1053  </code></pre>
1054  */
1055
1056 /*
1057  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1058  * They generate precompiled functions from date formats instead of parsing and
1059  * processing the pattern every time you format a date.  These functions are available
1060  * on every Date object (any javascript function).
1061  *
1062  * The original article and download are here:
1063  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1064  *
1065  */
1066  
1067  
1068  // was in core
1069 /**
1070  Returns the number of milliseconds between this date and date
1071  @param {Date} date (optional) Defaults to now
1072  @return {Number} The diff in milliseconds
1073  @member Date getElapsed
1074  */
1075 Date.prototype.getElapsed = function(date) {
1076         return Math.abs((date || new Date()).getTime()-this.getTime());
1077 };
1078 // was in date file..
1079
1080
1081 // private
1082 Date.parseFunctions = {count:0};
1083 // private
1084 Date.parseRegexes = [];
1085 // private
1086 Date.formatFunctions = {count:0};
1087
1088 // private
1089 Date.prototype.dateFormat = function(format) {
1090     if (Date.formatFunctions[format] == null) {
1091         Date.createNewFormat(format);
1092     }
1093     var func = Date.formatFunctions[format];
1094     return this[func]();
1095 };
1096
1097
1098 /**
1099  * Formats a date given the supplied format string
1100  * @param {String} format The format string
1101  * @return {String} The formatted date
1102  * @method
1103  */
1104 Date.prototype.format = Date.prototype.dateFormat;
1105
1106 // private
1107 Date.createNewFormat = function(format) {
1108     var funcName = "format" + Date.formatFunctions.count++;
1109     Date.formatFunctions[format] = funcName;
1110     var code = "Date.prototype." + funcName + " = function(){return ";
1111     var special = false;
1112     var ch = '';
1113     for (var i = 0; i < format.length; ++i) {
1114         ch = format.charAt(i);
1115         if (!special && ch == "\\") {
1116             special = true;
1117         }
1118         else if (special) {
1119             special = false;
1120             code += "'" + String.escape(ch) + "' + ";
1121         }
1122         else {
1123             code += Date.getFormatCode(ch);
1124         }
1125     }
1126     /** eval:var:zzzzzzzzzzzzz */
1127     eval(code.substring(0, code.length - 3) + ";}");
1128 };
1129
1130 // private
1131 Date.getFormatCode = function(character) {
1132     switch (character) {
1133     case "d":
1134         return "String.leftPad(this.getDate(), 2, '0') + ";
1135     case "D":
1136         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1137     case "j":
1138         return "this.getDate() + ";
1139     case "l":
1140         return "Date.dayNames[this.getDay()] + ";
1141     case "S":
1142         return "this.getSuffix() + ";
1143     case "w":
1144         return "this.getDay() + ";
1145     case "z":
1146         return "this.getDayOfYear() + ";
1147     case "W":
1148         return "this.getWeekOfYear() + ";
1149     case "F":
1150         return "Date.monthNames[this.getMonth()] + ";
1151     case "m":
1152         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1153     case "M":
1154         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1155     case "n":
1156         return "(this.getMonth() + 1) + ";
1157     case "t":
1158         return "this.getDaysInMonth() + ";
1159     case "L":
1160         return "(this.isLeapYear() ? 1 : 0) + ";
1161     case "Y":
1162         return "this.getFullYear() + ";
1163     case "y":
1164         return "('' + this.getFullYear()).substring(2, 4) + ";
1165     case "a":
1166         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1167     case "A":
1168         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1169     case "g":
1170         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1171     case "G":
1172         return "this.getHours() + ";
1173     case "h":
1174         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1175     case "H":
1176         return "String.leftPad(this.getHours(), 2, '0') + ";
1177     case "i":
1178         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1179     case "s":
1180         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1181     case "O":
1182         return "this.getGMTOffset() + ";
1183     case "P":
1184         return "this.getGMTColonOffset() + ";
1185     case "T":
1186         return "this.getTimezone() + ";
1187     case "Z":
1188         return "(this.getTimezoneOffset() * -60) + ";
1189     default:
1190         return "'" + String.escape(character) + "' + ";
1191     }
1192 };
1193
1194 /**
1195  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1196  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1197  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1198  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1199  * string or the parse operation will fail.
1200  * Example Usage:
1201 <pre><code>
1202 //dt = Fri May 25 2007 (current date)
1203 var dt = new Date();
1204
1205 //dt = Thu May 25 2006 (today's month/day in 2006)
1206 dt = Date.parseDate("2006", "Y");
1207
1208 //dt = Sun Jan 15 2006 (all date parts specified)
1209 dt = Date.parseDate("2006-1-15", "Y-m-d");
1210
1211 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1212 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1213 </code></pre>
1214  * @param {String} input The unparsed date as a string
1215  * @param {String} format The format the date is in
1216  * @return {Date} The parsed date
1217  * @static
1218  */
1219 Date.parseDate = function(input, format) {
1220     if (Date.parseFunctions[format] == null) {
1221         Date.createParser(format);
1222     }
1223     var func = Date.parseFunctions[format];
1224     return Date[func](input);
1225 };
1226 /**
1227  * @private
1228  */
1229 Date.createParser = function(format) {
1230     var funcName = "parse" + Date.parseFunctions.count++;
1231     var regexNum = Date.parseRegexes.length;
1232     var currentGroup = 1;
1233     Date.parseFunctions[format] = funcName;
1234
1235     var code = "Date." + funcName + " = function(input){\n"
1236         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1237         + "var d = new Date();\n"
1238         + "y = d.getFullYear();\n"
1239         + "m = d.getMonth();\n"
1240         + "d = d.getDate();\n"
1241         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1242         + "if (results && results.length > 0) {";
1243     var regex = "";
1244
1245     var special = false;
1246     var ch = '';
1247     for (var i = 0; i < format.length; ++i) {
1248         ch = format.charAt(i);
1249         if (!special && ch == "\\") {
1250             special = true;
1251         }
1252         else if (special) {
1253             special = false;
1254             regex += String.escape(ch);
1255         }
1256         else {
1257             var obj = Date.formatCodeToRegex(ch, currentGroup);
1258             currentGroup += obj.g;
1259             regex += obj.s;
1260             if (obj.g && obj.c) {
1261                 code += obj.c;
1262             }
1263         }
1264     }
1265
1266     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1267         + "{v = new Date(y, m, d, h, i, s);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1269         + "{v = new Date(y, m, d, h, i);}\n"
1270         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1271         + "{v = new Date(y, m, d, h);}\n"
1272         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1273         + "{v = new Date(y, m, d);}\n"
1274         + "else if (y >= 0 && m >= 0)\n"
1275         + "{v = new Date(y, m);}\n"
1276         + "else if (y >= 0)\n"
1277         + "{v = new Date(y);}\n"
1278         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1279         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1280         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1281         + ";}";
1282
1283     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1284     /** eval:var:zzzzzzzzzzzzz */
1285     eval(code);
1286 };
1287
1288 // private
1289 Date.formatCodeToRegex = function(character, currentGroup) {
1290     switch (character) {
1291     case "D":
1292         return {g:0,
1293         c:null,
1294         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1295     case "j":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{1,2})"}; // day of month without leading zeroes
1299     case "d":
1300         return {g:1,
1301             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1302             s:"(\\d{2})"}; // day of month with leading zeroes
1303     case "l":
1304         return {g:0,
1305             c:null,
1306             s:"(?:" + Date.dayNames.join("|") + ")"};
1307     case "S":
1308         return {g:0,
1309             c:null,
1310             s:"(?:st|nd|rd|th)"};
1311     case "w":
1312         return {g:0,
1313             c:null,
1314             s:"\\d"};
1315     case "z":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{1,3})"};
1319     case "W":
1320         return {g:0,
1321             c:null,
1322             s:"(?:\\d{2})"};
1323     case "F":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1326             s:"(" + Date.monthNames.join("|") + ")"};
1327     case "M":
1328         return {g:1,
1329             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1330             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1331     case "n":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1335     case "m":
1336         return {g:1,
1337             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1338             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1339     case "t":
1340         return {g:0,
1341             c:null,
1342             s:"\\d{1,2}"};
1343     case "L":
1344         return {g:0,
1345             c:null,
1346             s:"(?:1|0)"};
1347     case "Y":
1348         return {g:1,
1349             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1350             s:"(\\d{4})"};
1351     case "y":
1352         return {g:1,
1353             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1354                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1355             s:"(\\d{1,2})"};
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 "A":
1363         return {g:1,
1364             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1365                 + "if (h == 12) { h = 0; }\n"
1366                 + "} else { if (h < 12) { h += 12; }}",
1367             s:"(AM|PM)"};
1368     case "g":
1369     case "G":
1370         return {g:1,
1371             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1372             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1373     case "h":
1374     case "H":
1375         return {g:1,
1376             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1378     case "i":
1379         return {g:1,
1380             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "s":
1383         return {g:1,
1384             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385             s:"(\\d{2})"};
1386     case "O":
1387         return {g:1,
1388             c:[
1389                 "o = results[", currentGroup, "];\n",
1390                 "var sn = o.substring(0,1);\n", // get + / - sign
1391                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1392                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1393                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1394                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1395             ].join(""),
1396             s:"([+\-]\\d{2,4})"};
1397     
1398     
1399     case "P":
1400         return {g:1,
1401                 c:[
1402                    "o = results[", currentGroup, "];\n",
1403                    "var sn = o.substring(0,1);\n",
1404                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1405                    "var mn = o.substring(4,6) % 60;\n",
1406                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1407                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1408             ].join(""),
1409             s:"([+\-]\\d{4})"};
1410     case "T":
1411         return {g:0,
1412             c:null,
1413             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1414     case "Z":
1415         return {g:1,
1416             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1417                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1418             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1419     default:
1420         return {g:0,
1421             c:null,
1422             s:String.escape(character)};
1423     }
1424 };
1425
1426 /**
1427  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1428  * @return {String} The abbreviated timezone name (e.g. 'CST')
1429  */
1430 Date.prototype.getTimezone = function() {
1431     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1432 };
1433
1434 /**
1435  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1436  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1437  */
1438 Date.prototype.getGMTOffset = function() {
1439     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1440         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1441         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1442 };
1443
1444 /**
1445  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1446  * @return {String} 2-characters representing hours and 2-characters representing minutes
1447  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1448  */
1449 Date.prototype.getGMTColonOffset = function() {
1450         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1451                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1452                 + ":"
1453                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1454 }
1455
1456 /**
1457  * Get the numeric day number of the year, adjusted for leap year.
1458  * @return {Number} 0 through 364 (365 in leap years)
1459  */
1460 Date.prototype.getDayOfYear = function() {
1461     var num = 0;
1462     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1463     for (var i = 0; i < this.getMonth(); ++i) {
1464         num += Date.daysInMonth[i];
1465     }
1466     return num + this.getDate() - 1;
1467 };
1468
1469 /**
1470  * Get the string representation of the numeric week number of the year
1471  * (equivalent to the format specifier 'W').
1472  * @return {String} '00' through '52'
1473  */
1474 Date.prototype.getWeekOfYear = function() {
1475     // Skip to Thursday of this week
1476     var now = this.getDayOfYear() + (4 - this.getDay());
1477     // Find the first Thursday of the year
1478     var jan1 = new Date(this.getFullYear(), 0, 1);
1479     var then = (7 - jan1.getDay() + 4);
1480     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1481 };
1482
1483 /**
1484  * Whether or not the current date is in a leap year.
1485  * @return {Boolean} True if the current date is in a leap year, else false
1486  */
1487 Date.prototype.isLeapYear = function() {
1488     var year = this.getFullYear();
1489     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1490 };
1491
1492 /**
1493  * Get the first day of the current month, adjusted for leap year.  The returned value
1494  * is the numeric day index within the week (0-6) which can be used in conjunction with
1495  * the {@link #monthNames} array to retrieve the textual day name.
1496  * Example:
1497  *<pre><code>
1498 var dt = new Date('1/10/2007');
1499 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1500 </code></pre>
1501  * @return {Number} The day number (0-6)
1502  */
1503 Date.prototype.getFirstDayOfMonth = function() {
1504     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1505     return (day < 0) ? (day + 7) : day;
1506 };
1507
1508 /**
1509  * Get the last day of the current month, adjusted for leap year.  The returned value
1510  * is the numeric day index within the week (0-6) which can be used in conjunction with
1511  * the {@link #monthNames} array to retrieve the textual day name.
1512  * Example:
1513  *<pre><code>
1514 var dt = new Date('1/10/2007');
1515 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1516 </code></pre>
1517  * @return {Number} The day number (0-6)
1518  */
1519 Date.prototype.getLastDayOfMonth = function() {
1520     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1521     return (day < 0) ? (day + 7) : day;
1522 };
1523
1524
1525 /**
1526  * Get the first date of this date's month
1527  * @return {Date}
1528  */
1529 Date.prototype.getFirstDateOfMonth = function() {
1530     return new Date(this.getFullYear(), this.getMonth(), 1);
1531 };
1532
1533 /**
1534  * Get the last date of this date's month
1535  * @return {Date}
1536  */
1537 Date.prototype.getLastDateOfMonth = function() {
1538     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1539 };
1540 /**
1541  * Get the number of days in the current month, adjusted for leap year.
1542  * @return {Number} The number of days in the month
1543  */
1544 Date.prototype.getDaysInMonth = function() {
1545     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1546     return Date.daysInMonth[this.getMonth()];
1547 };
1548
1549 /**
1550  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1551  * @return {String} 'st, 'nd', 'rd' or 'th'
1552  */
1553 Date.prototype.getSuffix = function() {
1554     switch (this.getDate()) {
1555         case 1:
1556         case 21:
1557         case 31:
1558             return "st";
1559         case 2:
1560         case 22:
1561             return "nd";
1562         case 3:
1563         case 23:
1564             return "rd";
1565         default:
1566             return "th";
1567     }
1568 };
1569
1570 // private
1571 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1572
1573 /**
1574  * An array of textual month names.
1575  * Override these values for international dates, for example...
1576  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1577  * @type Array
1578  * @static
1579  */
1580 Date.monthNames =
1581    ["January",
1582     "February",
1583     "March",
1584     "April",
1585     "May",
1586     "June",
1587     "July",
1588     "August",
1589     "September",
1590     "October",
1591     "November",
1592     "December"];
1593
1594 /**
1595  * An array of textual day names.
1596  * Override these values for international dates, for example...
1597  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1598  * @type Array
1599  * @static
1600  */
1601 Date.dayNames =
1602    ["Sunday",
1603     "Monday",
1604     "Tuesday",
1605     "Wednesday",
1606     "Thursday",
1607     "Friday",
1608     "Saturday"];
1609
1610 // private
1611 Date.y2kYear = 50;
1612 // private
1613 Date.monthNumbers = {
1614     Jan:0,
1615     Feb:1,
1616     Mar:2,
1617     Apr:3,
1618     May:4,
1619     Jun:5,
1620     Jul:6,
1621     Aug:7,
1622     Sep:8,
1623     Oct:9,
1624     Nov:10,
1625     Dec:11};
1626
1627 /**
1628  * Creates and returns a new Date instance with the exact same date value as the called instance.
1629  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1630  * variable will also be changed.  When the intention is to create a new variable that will not
1631  * modify the original instance, you should create a clone.
1632  *
1633  * Example of correctly cloning a date:
1634  * <pre><code>
1635 //wrong way:
1636 var orig = new Date('10/1/2006');
1637 var copy = orig;
1638 copy.setDate(5);
1639 document.write(orig);  //returns 'Thu Oct 05 2006'!
1640
1641 //correct way:
1642 var orig = new Date('10/1/2006');
1643 var copy = orig.clone();
1644 copy.setDate(5);
1645 document.write(orig);  //returns 'Thu Oct 01 2006'
1646 </code></pre>
1647  * @return {Date} The new Date instance
1648  */
1649 Date.prototype.clone = function() {
1650         return new Date(this.getTime());
1651 };
1652
1653 /**
1654  * Clears any time information from this date
1655  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1656  @return {Date} this or the clone
1657  */
1658 Date.prototype.clearTime = function(clone){
1659     if(clone){
1660         return this.clone().clearTime();
1661     }
1662     this.setHours(0);
1663     this.setMinutes(0);
1664     this.setSeconds(0);
1665     this.setMilliseconds(0);
1666     return this;
1667 };
1668
1669 // private
1670 // safari setMonth is broken
1671 if(Roo.isSafari){
1672     Date.brokenSetMonth = Date.prototype.setMonth;
1673         Date.prototype.setMonth = function(num){
1674                 if(num <= -1){
1675                         var n = Math.ceil(-num);
1676                         var back_year = Math.ceil(n/12);
1677                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1678                         this.setFullYear(this.getFullYear() - back_year);
1679                         return Date.brokenSetMonth.call(this, month);
1680                 } else {
1681                         return Date.brokenSetMonth.apply(this, arguments);
1682                 }
1683         };
1684 }
1685
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.MILLI = "ms";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.SECOND = "s";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.MINUTE = "mi";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.HOUR = "h";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.DAY = "d";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.MONTH = "mo";
1710 /** Date interval constant 
1711 * @static 
1712 * @type String */
1713 Date.YEAR = "y";
1714
1715 /**
1716  * Provides a convenient method of performing basic date arithmetic.  This method
1717  * does not modify the Date instance being called - it creates and returns
1718  * a new Date instance containing the resulting date value.
1719  *
1720  * Examples:
1721  * <pre><code>
1722 //Basic usage:
1723 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1724 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1725
1726 //Negative values will subtract correctly:
1727 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1728 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1729
1730 //You can even chain several calls together in one line!
1731 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1732 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1733  </code></pre>
1734  *
1735  * @param {String} interval   A valid date interval enum value
1736  * @param {Number} value      The amount to add to the current date
1737  * @return {Date} The new Date instance
1738  */
1739 Date.prototype.add = function(interval, value){
1740   var d = this.clone();
1741   if (!interval || value === 0) return d;
1742   switch(interval.toLowerCase()){
1743     case Date.MILLI:
1744       d.setMilliseconds(this.getMilliseconds() + value);
1745       break;
1746     case Date.SECOND:
1747       d.setSeconds(this.getSeconds() + value);
1748       break;
1749     case Date.MINUTE:
1750       d.setMinutes(this.getMinutes() + value);
1751       break;
1752     case Date.HOUR:
1753       d.setHours(this.getHours() + value);
1754       break;
1755     case Date.DAY:
1756       d.setDate(this.getDate() + value);
1757       break;
1758     case Date.MONTH:
1759       var day = this.getDate();
1760       if(day > 28){
1761           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1762       }
1763       d.setDate(day);
1764       d.setMonth(this.getMonth() + value);
1765       break;
1766     case Date.YEAR:
1767       d.setFullYear(this.getFullYear() + value);
1768       break;
1769   }
1770   return d;
1771 };
1772 /*
1773  * Based on:
1774  * Ext JS Library 1.1.1
1775  * Copyright(c) 2006-2007, Ext JS, LLC.
1776  *
1777  * Originally Released Under LGPL - original licence link has changed is not relivant.
1778  *
1779  * Fork - LGPL
1780  * <script type="text/javascript">
1781  */
1782
1783 /**
1784  * @class Roo.lib.Dom
1785  * @static
1786  * 
1787  * Dom utils (from YIU afaik)
1788  * 
1789  **/
1790 Roo.lib.Dom = {
1791     /**
1792      * Get the view width
1793      * @param {Boolean} full True will get the full document, otherwise it's the view width
1794      * @return {Number} The width
1795      */
1796      
1797     getViewWidth : function(full) {
1798         return full ? this.getDocumentWidth() : this.getViewportWidth();
1799     },
1800     /**
1801      * Get the view height
1802      * @param {Boolean} full True will get the full document, otherwise it's the view height
1803      * @return {Number} The height
1804      */
1805     getViewHeight : function(full) {
1806         return full ? this.getDocumentHeight() : this.getViewportHeight();
1807     },
1808
1809     getDocumentHeight: function() {
1810         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1811         return Math.max(scrollHeight, this.getViewportHeight());
1812     },
1813
1814     getDocumentWidth: function() {
1815         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1816         return Math.max(scrollWidth, this.getViewportWidth());
1817     },
1818
1819     getViewportHeight: function() {
1820         var height = self.innerHeight;
1821         var mode = document.compatMode;
1822
1823         if ((mode || Roo.isIE) && !Roo.isOpera) {
1824             height = (mode == "CSS1Compat") ?
1825                      document.documentElement.clientHeight :
1826                      document.body.clientHeight;
1827         }
1828
1829         return height;
1830     },
1831
1832     getViewportWidth: function() {
1833         var width = self.innerWidth;
1834         var mode = document.compatMode;
1835
1836         if (mode || Roo.isIE) {
1837             width = (mode == "CSS1Compat") ?
1838                     document.documentElement.clientWidth :
1839                     document.body.clientWidth;
1840         }
1841         return width;
1842     },
1843
1844     isAncestor : function(p, c) {
1845         p = Roo.getDom(p);
1846         c = Roo.getDom(c);
1847         if (!p || !c) {
1848             return false;
1849         }
1850
1851         if (p.contains && !Roo.isSafari) {
1852             return p.contains(c);
1853         } else if (p.compareDocumentPosition) {
1854             return !!(p.compareDocumentPosition(c) & 16);
1855         } else {
1856             var parent = c.parentNode;
1857             while (parent) {
1858                 if (parent == p) {
1859                     return true;
1860                 }
1861                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1862                     return false;
1863                 }
1864                 parent = parent.parentNode;
1865             }
1866             return false;
1867         }
1868     },
1869
1870     getRegion : function(el) {
1871         return Roo.lib.Region.getRegion(el);
1872     },
1873
1874     getY : function(el) {
1875         return this.getXY(el)[1];
1876     },
1877
1878     getX : function(el) {
1879         return this.getXY(el)[0];
1880     },
1881
1882     getXY : function(el) {
1883         var p, pe, b, scroll, bd = document.body;
1884         el = Roo.getDom(el);
1885         var fly = Roo.lib.AnimBase.fly;
1886         if (el.getBoundingClientRect) {
1887             b = el.getBoundingClientRect();
1888             scroll = fly(document).getScroll();
1889             return [b.left + scroll.left, b.top + scroll.top];
1890         }
1891         var x = 0, y = 0;
1892
1893         p = el;
1894
1895         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1896
1897         while (p) {
1898
1899             x += p.offsetLeft;
1900             y += p.offsetTop;
1901
1902             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1903                 hasAbsolute = true;
1904             }
1905
1906             if (Roo.isGecko) {
1907                 pe = fly(p);
1908
1909                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1910                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1911
1912
1913                 x += bl;
1914                 y += bt;
1915
1916
1917                 if (p != el && pe.getStyle('overflow') != 'visible') {
1918                     x += bl;
1919                     y += bt;
1920                 }
1921             }
1922             p = p.offsetParent;
1923         }
1924
1925         if (Roo.isSafari && hasAbsolute) {
1926             x -= bd.offsetLeft;
1927             y -= bd.offsetTop;
1928         }
1929
1930         if (Roo.isGecko && !hasAbsolute) {
1931             var dbd = fly(bd);
1932             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1933             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1934         }
1935
1936         p = el.parentNode;
1937         while (p && p != bd) {
1938             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1939                 x -= p.scrollLeft;
1940                 y -= p.scrollTop;
1941             }
1942             p = p.parentNode;
1943         }
1944         return [x, y];
1945     },
1946  
1947   
1948
1949
1950     setXY : function(el, xy) {
1951         el = Roo.fly(el, '_setXY');
1952         el.position();
1953         var pts = el.translatePoints(xy);
1954         if (xy[0] !== false) {
1955             el.dom.style.left = pts.left + "px";
1956         }
1957         if (xy[1] !== false) {
1958             el.dom.style.top = pts.top + "px";
1959         }
1960     },
1961
1962     setX : function(el, x) {
1963         this.setXY(el, [x, false]);
1964     },
1965
1966     setY : function(el, y) {
1967         this.setXY(el, [false, y]);
1968     }
1969 };
1970 /*
1971  * Portions of this file are based on pieces of Yahoo User Interface Library
1972  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1973  * YUI licensed under the BSD License:
1974  * http://developer.yahoo.net/yui/license.txt
1975  * <script type="text/javascript">
1976  *
1977  */
1978
1979 Roo.lib.Event = function() {
1980     var loadComplete = false;
1981     var listeners = [];
1982     var unloadListeners = [];
1983     var retryCount = 0;
1984     var onAvailStack = [];
1985     var counter = 0;
1986     var lastError = null;
1987
1988     return {
1989         POLL_RETRYS: 200,
1990         POLL_INTERVAL: 20,
1991         EL: 0,
1992         TYPE: 1,
1993         FN: 2,
1994         WFN: 3,
1995         OBJ: 3,
1996         ADJ_SCOPE: 4,
1997         _interval: null,
1998
1999         startInterval: function() {
2000             if (!this._interval) {
2001                 var self = this;
2002                 var callback = function() {
2003                     self._tryPreloadAttach();
2004                 };
2005                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006
2007             }
2008         },
2009
2010         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2011             onAvailStack.push({ id:         p_id,
2012                 fn:         p_fn,
2013                 obj:        p_obj,
2014                 override:   p_override,
2015                 checkReady: false    });
2016
2017             retryCount = this.POLL_RETRYS;
2018             this.startInterval();
2019         },
2020
2021
2022         addListener: function(el, eventName, fn) {
2023             el = Roo.getDom(el);
2024             if (!el || !fn) {
2025                 return false;
2026             }
2027
2028             if ("unload" == eventName) {
2029                 unloadListeners[unloadListeners.length] =
2030                 [el, eventName, fn];
2031                 return true;
2032             }
2033
2034             var wrappedFn = function(e) {
2035                 return fn(Roo.lib.Event.getEvent(e));
2036             };
2037
2038             var li = [el, eventName, fn, wrappedFn];
2039
2040             var index = listeners.length;
2041             listeners[index] = li;
2042
2043             this.doAdd(el, eventName, wrappedFn, false);
2044             return true;
2045
2046         },
2047
2048
2049         removeListener: function(el, eventName, fn) {
2050             var i, len;
2051
2052             el = Roo.getDom(el);
2053
2054             if(!fn) {
2055                 return this.purgeElement(el, false, eventName);
2056             }
2057
2058
2059             if ("unload" == eventName) {
2060
2061                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2062                     var li = unloadListeners[i];
2063                     if (li &&
2064                         li[0] == el &&
2065                         li[1] == eventName &&
2066                         li[2] == fn) {
2067                         unloadListeners.splice(i, 1);
2068                         return true;
2069                     }
2070                 }
2071
2072                 return false;
2073             }
2074
2075             var cacheItem = null;
2076
2077
2078             var index = arguments[3];
2079
2080             if ("undefined" == typeof index) {
2081                 index = this._getCacheIndex(el, eventName, fn);
2082             }
2083
2084             if (index >= 0) {
2085                 cacheItem = listeners[index];
2086             }
2087
2088             if (!el || !cacheItem) {
2089                 return false;
2090             }
2091
2092             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2093
2094             delete listeners[index][this.WFN];
2095             delete listeners[index][this.FN];
2096             listeners.splice(index, 1);
2097
2098             return true;
2099
2100         },
2101
2102
2103         getTarget: function(ev, resolveTextNode) {
2104             ev = ev.browserEvent || ev;
2105             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2106             var t = ev.target || ev.srcElement;
2107             return this.resolveTextNode(t);
2108         },
2109
2110
2111         resolveTextNode: function(node) {
2112             if (Roo.isSafari && node && 3 == node.nodeType) {
2113                 return node.parentNode;
2114             } else {
2115                 return node;
2116             }
2117         },
2118
2119
2120         getPageX: function(ev) {
2121             ev = ev.browserEvent || ev;
2122             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2123             var x = ev.pageX;
2124             if (!x && 0 !== x) {
2125                 x = ev.clientX || 0;
2126
2127                 if (Roo.isIE) {
2128                     x += this.getScroll()[1];
2129                 }
2130             }
2131
2132             return x;
2133         },
2134
2135
2136         getPageY: function(ev) {
2137             ev = ev.browserEvent || ev;
2138             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2139             var y = ev.pageY;
2140             if (!y && 0 !== y) {
2141                 y = ev.clientY || 0;
2142
2143                 if (Roo.isIE) {
2144                     y += this.getScroll()[0];
2145                 }
2146             }
2147
2148
2149             return y;
2150         },
2151
2152
2153         getXY: function(ev) {
2154             ev = ev.browserEvent || ev;
2155             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2156             return [this.getPageX(ev), this.getPageY(ev)];
2157         },
2158
2159
2160         getRelatedTarget: function(ev) {
2161             ev = ev.browserEvent || ev;
2162             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2163             var t = ev.relatedTarget;
2164             if (!t) {
2165                 if (ev.type == "mouseout") {
2166                     t = ev.toElement;
2167                 } else if (ev.type == "mouseover") {
2168                     t = ev.fromElement;
2169                 }
2170             }
2171
2172             return this.resolveTextNode(t);
2173         },
2174
2175
2176         getTime: function(ev) {
2177             ev = ev.browserEvent || ev;
2178             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2179             if (!ev.time) {
2180                 var t = new Date().getTime();
2181                 try {
2182                     ev.time = t;
2183                 } catch(ex) {
2184                     this.lastError = ex;
2185                     return t;
2186                 }
2187             }
2188
2189             return ev.time;
2190         },
2191
2192
2193         stopEvent: function(ev) {
2194             this.stopPropagation(ev);
2195             this.preventDefault(ev);
2196         },
2197
2198
2199         stopPropagation: function(ev) {
2200             ev = ev.browserEvent || ev;
2201             if (ev.stopPropagation) {
2202                 ev.stopPropagation();
2203             } else {
2204                 ev.cancelBubble = true;
2205             }
2206         },
2207
2208
2209         preventDefault: function(ev) {
2210             ev = ev.browserEvent || ev;
2211             if(ev.preventDefault) {
2212                 ev.preventDefault();
2213             } else {
2214                 ev.returnValue = false;
2215             }
2216         },
2217
2218
2219         getEvent: function(e) {
2220             var ev = e || window.event;
2221             if (!ev) {
2222                 var c = this.getEvent.caller;
2223                 while (c) {
2224                     ev = c.arguments[0];
2225                     if (ev && Event == ev.constructor) {
2226                         break;
2227                     }
2228                     c = c.caller;
2229                 }
2230             }
2231             return ev;
2232         },
2233
2234
2235         getCharCode: function(ev) {
2236             ev = ev.browserEvent || ev;
2237             return ev.charCode || ev.keyCode || 0;
2238         },
2239
2240
2241         _getCacheIndex: function(el, eventName, fn) {
2242             for (var i = 0,len = listeners.length; i < len; ++i) {
2243                 var li = listeners[i];
2244                 if (li &&
2245                     li[this.FN] == fn &&
2246                     li[this.EL] == el &&
2247                     li[this.TYPE] == eventName) {
2248                     return i;
2249                 }
2250             }
2251
2252             return -1;
2253         },
2254
2255
2256         elCache: {},
2257
2258
2259         getEl: function(id) {
2260             return document.getElementById(id);
2261         },
2262
2263
2264         clearCache: function() {
2265         },
2266
2267
2268         _load: function(e) {
2269             loadComplete = true;
2270             var EU = Roo.lib.Event;
2271
2272
2273             if (Roo.isIE) {
2274                 EU.doRemove(window, "load", EU._load);
2275             }
2276         },
2277
2278
2279         _tryPreloadAttach: function() {
2280
2281             if (this.locked) {
2282                 return false;
2283             }
2284
2285             this.locked = true;
2286
2287
2288             var tryAgain = !loadComplete;
2289             if (!tryAgain) {
2290                 tryAgain = (retryCount > 0);
2291             }
2292
2293
2294             var notAvail = [];
2295             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2296                 var item = onAvailStack[i];
2297                 if (item) {
2298                     var el = this.getEl(item.id);
2299
2300                     if (el) {
2301                         if (!item.checkReady ||
2302                             loadComplete ||
2303                             el.nextSibling ||
2304                             (document && document.body)) {
2305
2306                             var scope = el;
2307                             if (item.override) {
2308                                 if (item.override === true) {
2309                                     scope = item.obj;
2310                                 } else {
2311                                     scope = item.override;
2312                                 }
2313                             }
2314                             item.fn.call(scope, item.obj);
2315                             onAvailStack[i] = null;
2316                         }
2317                     } else {
2318                         notAvail.push(item);
2319                     }
2320                 }
2321             }
2322
2323             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2324
2325             if (tryAgain) {
2326
2327                 this.startInterval();
2328             } else {
2329                 clearInterval(this._interval);
2330                 this._interval = null;
2331             }
2332
2333             this.locked = false;
2334
2335             return true;
2336
2337         },
2338
2339
2340         purgeElement: function(el, recurse, eventName) {
2341             var elListeners = this.getListeners(el, eventName);
2342             if (elListeners) {
2343                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2344                     var l = elListeners[i];
2345                     this.removeListener(el, l.type, l.fn);
2346                 }
2347             }
2348
2349             if (recurse && el && el.childNodes) {
2350                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2351                     this.purgeElement(el.childNodes[i], recurse, eventName);
2352                 }
2353             }
2354         },
2355
2356
2357         getListeners: function(el, eventName) {
2358             var results = [], searchLists;
2359             if (!eventName) {
2360                 searchLists = [listeners, unloadListeners];
2361             } else if (eventName == "unload") {
2362                 searchLists = [unloadListeners];
2363             } else {
2364                 searchLists = [listeners];
2365             }
2366
2367             for (var j = 0; j < searchLists.length; ++j) {
2368                 var searchList = searchLists[j];
2369                 if (searchList && searchList.length > 0) {
2370                     for (var i = 0,len = searchList.length; i < len; ++i) {
2371                         var l = searchList[i];
2372                         if (l && l[this.EL] === el &&
2373                             (!eventName || eventName === l[this.TYPE])) {
2374                             results.push({
2375                                 type:   l[this.TYPE],
2376                                 fn:     l[this.FN],
2377                                 obj:    l[this.OBJ],
2378                                 adjust: l[this.ADJ_SCOPE],
2379                                 index:  i
2380                             });
2381                         }
2382                     }
2383                 }
2384             }
2385
2386             return (results.length) ? results : null;
2387         },
2388
2389
2390         _unload: function(e) {
2391
2392             var EU = Roo.lib.Event, i, j, l, len, index;
2393
2394             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2395                 l = unloadListeners[i];
2396                 if (l) {
2397                     var scope = window;
2398                     if (l[EU.ADJ_SCOPE]) {
2399                         if (l[EU.ADJ_SCOPE] === true) {
2400                             scope = l[EU.OBJ];
2401                         } else {
2402                             scope = l[EU.ADJ_SCOPE];
2403                         }
2404                     }
2405                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2406                     unloadListeners[i] = null;
2407                     l = null;
2408                     scope = null;
2409                 }
2410             }
2411
2412             unloadListeners = null;
2413
2414             if (listeners && listeners.length > 0) {
2415                 j = listeners.length;
2416                 while (j) {
2417                     index = j - 1;
2418                     l = listeners[index];
2419                     if (l) {
2420                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2421                                 l[EU.FN], index);
2422                     }
2423                     j = j - 1;
2424                 }
2425                 l = null;
2426
2427                 EU.clearCache();
2428             }
2429
2430             EU.doRemove(window, "unload", EU._unload);
2431
2432         },
2433
2434
2435         getScroll: function() {
2436             var dd = document.documentElement, db = document.body;
2437             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2438                 return [dd.scrollTop, dd.scrollLeft];
2439             } else if (db) {
2440                 return [db.scrollTop, db.scrollLeft];
2441             } else {
2442                 return [0, 0];
2443             }
2444         },
2445
2446
2447         doAdd: function () {
2448             if (window.addEventListener) {
2449                 return function(el, eventName, fn, capture) {
2450                     el.addEventListener(eventName, fn, (capture));
2451                 };
2452             } else if (window.attachEvent) {
2453                 return function(el, eventName, fn, capture) {
2454                     el.attachEvent("on" + eventName, fn);
2455                 };
2456             } else {
2457                 return function() {
2458                 };
2459             }
2460         }(),
2461
2462
2463         doRemove: function() {
2464             if (window.removeEventListener) {
2465                 return function (el, eventName, fn, capture) {
2466                     el.removeEventListener(eventName, fn, (capture));
2467                 };
2468             } else if (window.detachEvent) {
2469                 return function (el, eventName, fn) {
2470                     el.detachEvent("on" + eventName, fn);
2471                 };
2472             } else {
2473                 return function() {
2474                 };
2475             }
2476         }()
2477     };
2478     
2479 }();
2480 (function() {     
2481    
2482     var E = Roo.lib.Event;
2483     E.on = E.addListener;
2484     E.un = E.removeListener;
2485
2486     if (document && document.body) {
2487         E._load();
2488     } else {
2489         E.doAdd(window, "load", E._load);
2490     }
2491     E.doAdd(window, "unload", E._unload);
2492     E._tryPreloadAttach();
2493 })();
2494
2495 /*
2496  * Portions of this file are based on pieces of Yahoo User Interface Library
2497  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2498  * YUI licensed under the BSD License:
2499  * http://developer.yahoo.net/yui/license.txt
2500  * <script type="text/javascript">
2501  *
2502  */
2503
2504 (function() {
2505     /**
2506      * @class Roo.lib.Ajax
2507      *
2508      */
2509     Roo.lib.Ajax = {
2510         /**
2511          * @static 
2512          */
2513         request : function(method, uri, cb, data, options) {
2514             if(options){
2515                 var hs = options.headers;
2516                 if(hs){
2517                     for(var h in hs){
2518                         if(hs.hasOwnProperty(h)){
2519                             this.initHeader(h, hs[h], false);
2520                         }
2521                     }
2522                 }
2523                 if(options.xmlData){
2524                     this.initHeader('Content-Type', 'text/xml', false);
2525                     method = 'POST';
2526                     data = options.xmlData;
2527                 }
2528             }
2529
2530             return this.asyncRequest(method, uri, cb, data);
2531         },
2532
2533         serializeForm : function(form) {
2534             if(typeof form == 'string') {
2535                 form = (document.getElementById(form) || document.forms[form]);
2536             }
2537
2538             var el, name, val, disabled, data = '', hasSubmit = false;
2539             for (var i = 0; i < form.elements.length; i++) {
2540                 el = form.elements[i];
2541                 disabled = form.elements[i].disabled;
2542                 name = form.elements[i].name;
2543                 val = form.elements[i].value;
2544
2545                 if (!disabled && name){
2546                     switch (el.type)
2547                             {
2548                         case 'select-one':
2549                         case 'select-multiple':
2550                             for (var j = 0; j < el.options.length; j++) {
2551                                 if (el.options[j].selected) {
2552                                     if (Roo.isIE) {
2553                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2554                                     }
2555                                     else {
2556                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2557                                     }
2558                                 }
2559                             }
2560                             break;
2561                         case 'radio':
2562                         case 'checkbox':
2563                             if (el.checked) {
2564                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2565                             }
2566                             break;
2567                         case 'file':
2568
2569                         case undefined:
2570
2571                         case 'reset':
2572
2573                         case 'button':
2574
2575                             break;
2576                         case 'submit':
2577                             if(hasSubmit == false) {
2578                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579                                 hasSubmit = true;
2580                             }
2581                             break;
2582                         default:
2583                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584                             break;
2585                     }
2586                 }
2587             }
2588             data = data.substr(0, data.length - 1);
2589             return data;
2590         },
2591
2592         headers:{},
2593
2594         hasHeaders:false,
2595
2596         useDefaultHeader:true,
2597
2598         defaultPostHeader:'application/x-www-form-urlencoded',
2599
2600         useDefaultXhrHeader:true,
2601
2602         defaultXhrHeader:'XMLHttpRequest',
2603
2604         hasDefaultHeaders:true,
2605
2606         defaultHeaders:{},
2607
2608         poll:{},
2609
2610         timeout:{},
2611
2612         pollInterval:50,
2613
2614         transactionId:0,
2615
2616         setProgId:function(id)
2617         {
2618             this.activeX.unshift(id);
2619         },
2620
2621         setDefaultPostHeader:function(b)
2622         {
2623             this.useDefaultHeader = b;
2624         },
2625
2626         setDefaultXhrHeader:function(b)
2627         {
2628             this.useDefaultXhrHeader = b;
2629         },
2630
2631         setPollingInterval:function(i)
2632         {
2633             if (typeof i == 'number' && isFinite(i)) {
2634                 this.pollInterval = i;
2635             }
2636         },
2637
2638         createXhrObject:function(transactionId)
2639         {
2640             var obj,http;
2641             try
2642             {
2643
2644                 http = new XMLHttpRequest();
2645
2646                 obj = { conn:http, tId:transactionId };
2647             }
2648             catch(e)
2649             {
2650                 for (var i = 0; i < this.activeX.length; ++i) {
2651                     try
2652                     {
2653
2654                         http = new ActiveXObject(this.activeX[i]);
2655
2656                         obj = { conn:http, tId:transactionId };
2657                         break;
2658                     }
2659                     catch(e) {
2660                     }
2661                 }
2662             }
2663             finally
2664             {
2665                 return obj;
2666             }
2667         },
2668
2669         getConnectionObject:function()
2670         {
2671             var o;
2672             var tId = this.transactionId;
2673
2674             try
2675             {
2676                 o = this.createXhrObject(tId);
2677                 if (o) {
2678                     this.transactionId++;
2679                 }
2680             }
2681             catch(e) {
2682             }
2683             finally
2684             {
2685                 return o;
2686             }
2687         },
2688
2689         asyncRequest:function(method, uri, callback, postData)
2690         {
2691             var o = this.getConnectionObject();
2692
2693             if (!o) {
2694                 return null;
2695             }
2696             else {
2697                 o.conn.open(method, uri, true);
2698
2699                 if (this.useDefaultXhrHeader) {
2700                     if (!this.defaultHeaders['X-Requested-With']) {
2701                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2702                     }
2703                 }
2704
2705                 if(postData && this.useDefaultHeader){
2706                     this.initHeader('Content-Type', this.defaultPostHeader);
2707                 }
2708
2709                  if (this.hasDefaultHeaders || this.hasHeaders) {
2710                     this.setHeader(o);
2711                 }
2712
2713                 this.handleReadyState(o, callback);
2714                 o.conn.send(postData || null);
2715
2716                 return o;
2717             }
2718         },
2719
2720         handleReadyState:function(o, callback)
2721         {
2722             var oConn = this;
2723
2724             if (callback && callback.timeout) {
2725                 
2726                 this.timeout[o.tId] = window.setTimeout(function() {
2727                     oConn.abort(o, callback, true);
2728                 }, callback.timeout);
2729             }
2730
2731             this.poll[o.tId] = window.setInterval(
2732                     function() {
2733                         if (o.conn && o.conn.readyState == 4) {
2734                             window.clearInterval(oConn.poll[o.tId]);
2735                             delete oConn.poll[o.tId];
2736
2737                             if(callback && callback.timeout) {
2738                                 window.clearTimeout(oConn.timeout[o.tId]);
2739                                 delete oConn.timeout[o.tId];
2740                             }
2741
2742                             oConn.handleTransactionResponse(o, callback);
2743                         }
2744                     }
2745                     , this.pollInterval);
2746         },
2747
2748         handleTransactionResponse:function(o, callback, isAbort)
2749         {
2750
2751             if (!callback) {
2752                 this.releaseObject(o);
2753                 return;
2754             }
2755
2756             var httpStatus, responseObject;
2757
2758             try
2759             {
2760                 if (o.conn.status !== undefined && o.conn.status != 0) {
2761                     httpStatus = o.conn.status;
2762                 }
2763                 else {
2764                     httpStatus = 13030;
2765                 }
2766             }
2767             catch(e) {
2768
2769
2770                 httpStatus = 13030;
2771             }
2772
2773             if (httpStatus >= 200 && httpStatus < 300) {
2774                 responseObject = this.createResponseObject(o, callback.argument);
2775                 if (callback.success) {
2776                     if (!callback.scope) {
2777                         callback.success(responseObject);
2778                     }
2779                     else {
2780
2781
2782                         callback.success.apply(callback.scope, [responseObject]);
2783                     }
2784                 }
2785             }
2786             else {
2787                 switch (httpStatus) {
2788
2789                     case 12002:
2790                     case 12029:
2791                     case 12030:
2792                     case 12031:
2793                     case 12152:
2794                     case 13030:
2795                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2796                         if (callback.failure) {
2797                             if (!callback.scope) {
2798                                 callback.failure(responseObject);
2799                             }
2800                             else {
2801                                 callback.failure.apply(callback.scope, [responseObject]);
2802                             }
2803                         }
2804                         break;
2805                     default:
2806                         responseObject = this.createResponseObject(o, callback.argument);
2807                         if (callback.failure) {
2808                             if (!callback.scope) {
2809                                 callback.failure(responseObject);
2810                             }
2811                             else {
2812                                 callback.failure.apply(callback.scope, [responseObject]);
2813                             }
2814                         }
2815                 }
2816             }
2817
2818             this.releaseObject(o);
2819             responseObject = null;
2820         },
2821
2822         createResponseObject:function(o, callbackArg)
2823         {
2824             var obj = {};
2825             var headerObj = {};
2826
2827             try
2828             {
2829                 var headerStr = o.conn.getAllResponseHeaders();
2830                 var header = headerStr.split('\n');
2831                 for (var i = 0; i < header.length; i++) {
2832                     var delimitPos = header[i].indexOf(':');
2833                     if (delimitPos != -1) {
2834                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2835                     }
2836                 }
2837             }
2838             catch(e) {
2839             }
2840
2841             obj.tId = o.tId;
2842             obj.status = o.conn.status;
2843             obj.statusText = o.conn.statusText;
2844             obj.getResponseHeader = headerObj;
2845             obj.getAllResponseHeaders = headerStr;
2846             obj.responseText = o.conn.responseText;
2847             obj.responseXML = o.conn.responseXML;
2848
2849             if (typeof callbackArg !== undefined) {
2850                 obj.argument = callbackArg;
2851             }
2852
2853             return obj;
2854         },
2855
2856         createExceptionObject:function(tId, callbackArg, isAbort)
2857         {
2858             var COMM_CODE = 0;
2859             var COMM_ERROR = 'communication failure';
2860             var ABORT_CODE = -1;
2861             var ABORT_ERROR = 'transaction aborted';
2862
2863             var obj = {};
2864
2865             obj.tId = tId;
2866             if (isAbort) {
2867                 obj.status = ABORT_CODE;
2868                 obj.statusText = ABORT_ERROR;
2869             }
2870             else {
2871                 obj.status = COMM_CODE;
2872                 obj.statusText = COMM_ERROR;
2873             }
2874
2875             if (callbackArg) {
2876                 obj.argument = callbackArg;
2877             }
2878
2879             return obj;
2880         },
2881
2882         initHeader:function(label, value, isDefault)
2883         {
2884             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2885
2886             if (headerObj[label] === undefined) {
2887                 headerObj[label] = value;
2888             }
2889             else {
2890
2891
2892                 headerObj[label] = value + "," + headerObj[label];
2893             }
2894
2895             if (isDefault) {
2896                 this.hasDefaultHeaders = true;
2897             }
2898             else {
2899                 this.hasHeaders = true;
2900             }
2901         },
2902
2903
2904         setHeader:function(o)
2905         {
2906             if (this.hasDefaultHeaders) {
2907                 for (var prop in this.defaultHeaders) {
2908                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2909                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910                     }
2911                 }
2912             }
2913
2914             if (this.hasHeaders) {
2915                 for (var prop in this.headers) {
2916                     if (this.headers.hasOwnProperty(prop)) {
2917                         o.conn.setRequestHeader(prop, this.headers[prop]);
2918                     }
2919                 }
2920                 this.headers = {};
2921                 this.hasHeaders = false;
2922             }
2923         },
2924
2925         resetDefaultHeaders:function() {
2926             delete this.defaultHeaders;
2927             this.defaultHeaders = {};
2928             this.hasDefaultHeaders = false;
2929         },
2930
2931         abort:function(o, callback, isTimeout)
2932         {
2933             if(this.isCallInProgress(o)) {
2934                 o.conn.abort();
2935                 window.clearInterval(this.poll[o.tId]);
2936                 delete this.poll[o.tId];
2937                 if (isTimeout) {
2938                     delete this.timeout[o.tId];
2939                 }
2940
2941                 this.handleTransactionResponse(o, callback, true);
2942
2943                 return true;
2944             }
2945             else {
2946                 return false;
2947             }
2948         },
2949
2950
2951         isCallInProgress:function(o)
2952         {
2953             if (o && o.conn) {
2954                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2955             }
2956             else {
2957
2958                 return false;
2959             }
2960         },
2961
2962
2963         releaseObject:function(o)
2964         {
2965
2966             o.conn = null;
2967
2968             o = null;
2969         },
2970
2971         activeX:[
2972         'MSXML2.XMLHTTP.3.0',
2973         'MSXML2.XMLHTTP',
2974         'Microsoft.XMLHTTP'
2975         ]
2976
2977
2978     };
2979 })();/*
2980  * Portions of this file are based on pieces of Yahoo User Interface Library
2981  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2982  * YUI licensed under the BSD License:
2983  * http://developer.yahoo.net/yui/license.txt
2984  * <script type="text/javascript">
2985  *
2986  */
2987
2988 Roo.lib.Region = function(t, r, b, l) {
2989     this.top = t;
2990     this[1] = t;
2991     this.right = r;
2992     this.bottom = b;
2993     this.left = l;
2994     this[0] = l;
2995 };
2996
2997
2998 Roo.lib.Region.prototype = {
2999     contains : function(region) {
3000         return ( region.left >= this.left &&
3001                  region.right <= this.right &&
3002                  region.top >= this.top &&
3003                  region.bottom <= this.bottom    );
3004
3005     },
3006
3007     getArea : function() {
3008         return ( (this.bottom - this.top) * (this.right - this.left) );
3009     },
3010
3011     intersect : function(region) {
3012         var t = Math.max(this.top, region.top);
3013         var r = Math.min(this.right, region.right);
3014         var b = Math.min(this.bottom, region.bottom);
3015         var l = Math.max(this.left, region.left);
3016
3017         if (b >= t && r >= l) {
3018             return new Roo.lib.Region(t, r, b, l);
3019         } else {
3020             return null;
3021         }
3022     },
3023     union : function(region) {
3024         var t = Math.min(this.top, region.top);
3025         var r = Math.max(this.right, region.right);
3026         var b = Math.max(this.bottom, region.bottom);
3027         var l = Math.min(this.left, region.left);
3028
3029         return new Roo.lib.Region(t, r, b, l);
3030     },
3031
3032     adjust : function(t, l, b, r) {
3033         this.top += t;
3034         this.left += l;
3035         this.right += r;
3036         this.bottom += b;
3037         return this;
3038     }
3039 };
3040
3041 Roo.lib.Region.getRegion = function(el) {
3042     var p = Roo.lib.Dom.getXY(el);
3043
3044     var t = p[1];
3045     var r = p[0] + el.offsetWidth;
3046     var b = p[1] + el.offsetHeight;
3047     var l = p[0];
3048
3049     return new Roo.lib.Region(t, r, b, l);
3050 };
3051 /*
3052  * Portions of this file are based on pieces of Yahoo User Interface Library
3053  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3054  * YUI licensed under the BSD License:
3055  * http://developer.yahoo.net/yui/license.txt
3056  * <script type="text/javascript">
3057  *
3058  */
3059 //@@dep Roo.lib.Region
3060
3061
3062 Roo.lib.Point = function(x, y) {
3063     if (x instanceof Array) {
3064         y = x[1];
3065         x = x[0];
3066     }
3067     this.x = this.right = this.left = this[0] = x;
3068     this.y = this.top = this.bottom = this[1] = y;
3069 };
3070
3071 Roo.lib.Point.prototype = new Roo.lib.Region();
3072 /*
3073  * Portions of this file are based on pieces of Yahoo User Interface Library
3074  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3075  * YUI licensed under the BSD License:
3076  * http://developer.yahoo.net/yui/license.txt
3077  * <script type="text/javascript">
3078  *
3079  */
3080  
3081 (function() {   
3082
3083     Roo.lib.Anim = {
3084         scroll : function(el, args, duration, easing, cb, scope) {
3085             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3086         },
3087
3088         motion : function(el, args, duration, easing, cb, scope) {
3089             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3090         },
3091
3092         color : function(el, args, duration, easing, cb, scope) {
3093             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3094         },
3095
3096         run : function(el, args, duration, easing, cb, scope, type) {
3097             type = type || Roo.lib.AnimBase;
3098             if (typeof easing == "string") {
3099                 easing = Roo.lib.Easing[easing];
3100             }
3101             var anim = new type(el, args, duration, easing);
3102             anim.animateX(function() {
3103                 Roo.callback(cb, scope);
3104             });
3105             return anim;
3106         }
3107     };
3108 })();/*
3109  * Portions of this file are based on pieces of Yahoo User Interface Library
3110  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3111  * YUI licensed under the BSD License:
3112  * http://developer.yahoo.net/yui/license.txt
3113  * <script type="text/javascript">
3114  *
3115  */
3116
3117 (function() {    
3118     var libFlyweight;
3119     
3120     function fly(el) {
3121         if (!libFlyweight) {
3122             libFlyweight = new Roo.Element.Flyweight();
3123         }
3124         libFlyweight.dom = el;
3125         return libFlyweight;
3126     }
3127
3128     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3129     
3130    
3131     
3132     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3133         if (el) {
3134             this.init(el, attributes, duration, method);
3135         }
3136     };
3137
3138     Roo.lib.AnimBase.fly = fly;
3139     
3140     
3141     
3142     Roo.lib.AnimBase.prototype = {
3143
3144         toString: function() {
3145             var el = this.getEl();
3146             var id = el.id || el.tagName;
3147             return ("Anim " + id);
3148         },
3149
3150         patterns: {
3151             noNegatives:        /width|height|opacity|padding/i,
3152             offsetAttribute:  /^((width|height)|(top|left))$/,
3153             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3154             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3155         },
3156
3157
3158         doMethod: function(attr, start, end) {
3159             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3160         },
3161
3162
3163         setAttribute: function(attr, val, unit) {
3164             if (this.patterns.noNegatives.test(attr)) {
3165                 val = (val > 0) ? val : 0;
3166             }
3167
3168             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3169         },
3170
3171
3172         getAttribute: function(attr) {
3173             var el = this.getEl();
3174             var val = fly(el).getStyle(attr);
3175
3176             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3177                 return parseFloat(val);
3178             }
3179
3180             var a = this.patterns.offsetAttribute.exec(attr) || [];
3181             var pos = !!( a[3] );
3182             var box = !!( a[2] );
3183
3184
3185             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3186                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3187             } else {
3188                 val = 0;
3189             }
3190
3191             return val;
3192         },
3193
3194
3195         getDefaultUnit: function(attr) {
3196             if (this.patterns.defaultUnit.test(attr)) {
3197                 return 'px';
3198             }
3199
3200             return '';
3201         },
3202
3203         animateX : function(callback, scope) {
3204             var f = function() {
3205                 this.onComplete.removeListener(f);
3206                 if (typeof callback == "function") {
3207                     callback.call(scope || this, this);
3208                 }
3209             };
3210             this.onComplete.addListener(f, this);
3211             this.animate();
3212         },
3213
3214
3215         setRuntimeAttribute: function(attr) {
3216             var start;
3217             var end;
3218             var attributes = this.attributes;
3219
3220             this.runtimeAttributes[attr] = {};
3221
3222             var isset = function(prop) {
3223                 return (typeof prop !== 'undefined');
3224             };
3225
3226             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3227                 return false;
3228             }
3229
3230             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3231
3232
3233             if (isset(attributes[attr]['to'])) {
3234                 end = attributes[attr]['to'];
3235             } else if (isset(attributes[attr]['by'])) {
3236                 if (start.constructor == Array) {
3237                     end = [];
3238                     for (var i = 0, len = start.length; i < len; ++i) {
3239                         end[i] = start[i] + attributes[attr]['by'][i];
3240                     }
3241                 } else {
3242                     end = start + attributes[attr]['by'];
3243                 }
3244             }
3245
3246             this.runtimeAttributes[attr].start = start;
3247             this.runtimeAttributes[attr].end = end;
3248
3249
3250             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3251         },
3252
3253
3254         init: function(el, attributes, duration, method) {
3255
3256             var isAnimated = false;
3257
3258
3259             var startTime = null;
3260
3261
3262             var actualFrames = 0;
3263
3264
3265             el = Roo.getDom(el);
3266
3267
3268             this.attributes = attributes || {};
3269
3270
3271             this.duration = duration || 1;
3272
3273
3274             this.method = method || Roo.lib.Easing.easeNone;
3275
3276
3277             this.useSeconds = true;
3278
3279
3280             this.currentFrame = 0;
3281
3282
3283             this.totalFrames = Roo.lib.AnimMgr.fps;
3284
3285
3286             this.getEl = function() {
3287                 return el;
3288             };
3289
3290
3291             this.isAnimated = function() {
3292                 return isAnimated;
3293             };
3294
3295
3296             this.getStartTime = function() {
3297                 return startTime;
3298             };
3299
3300             this.runtimeAttributes = {};
3301
3302
3303             this.animate = function() {
3304                 if (this.isAnimated()) {
3305                     return false;
3306                 }
3307
3308                 this.currentFrame = 0;
3309
3310                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3311
3312                 Roo.lib.AnimMgr.registerElement(this);
3313             };
3314
3315
3316             this.stop = function(finish) {
3317                 if (finish) {
3318                     this.currentFrame = this.totalFrames;
3319                     this._onTween.fire();
3320                 }
3321                 Roo.lib.AnimMgr.stop(this);
3322             };
3323
3324             var onStart = function() {
3325                 this.onStart.fire();
3326
3327                 this.runtimeAttributes = {};
3328                 for (var attr in this.attributes) {
3329                     this.setRuntimeAttribute(attr);
3330                 }
3331
3332                 isAnimated = true;
3333                 actualFrames = 0;
3334                 startTime = new Date();
3335             };
3336
3337
3338             var onTween = function() {
3339                 var data = {
3340                     duration: new Date() - this.getStartTime(),
3341                     currentFrame: this.currentFrame
3342                 };
3343
3344                 data.toString = function() {
3345                     return (
3346                             'duration: ' + data.duration +
3347                             ', currentFrame: ' + data.currentFrame
3348                             );
3349                 };
3350
3351                 this.onTween.fire(data);
3352
3353                 var runtimeAttributes = this.runtimeAttributes;
3354
3355                 for (var attr in runtimeAttributes) {
3356                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3357                 }
3358
3359                 actualFrames += 1;
3360             };
3361
3362             var onComplete = function() {
3363                 var actual_duration = (new Date() - startTime) / 1000 ;
3364
3365                 var data = {
3366                     duration: actual_duration,
3367                     frames: actualFrames,
3368                     fps: actualFrames / actual_duration
3369                 };
3370
3371                 data.toString = function() {
3372                     return (
3373                             'duration: ' + data.duration +
3374                             ', frames: ' + data.frames +
3375                             ', fps: ' + data.fps
3376                             );
3377                 };
3378
3379                 isAnimated = false;
3380                 actualFrames = 0;
3381                 this.onComplete.fire(data);
3382             };
3383
3384
3385             this._onStart = new Roo.util.Event(this);
3386             this.onStart = new Roo.util.Event(this);
3387             this.onTween = new Roo.util.Event(this);
3388             this._onTween = new Roo.util.Event(this);
3389             this.onComplete = new Roo.util.Event(this);
3390             this._onComplete = new Roo.util.Event(this);
3391             this._onStart.addListener(onStart);
3392             this._onTween.addListener(onTween);
3393             this._onComplete.addListener(onComplete);
3394         }
3395     };
3396 })();
3397 /*
3398  * Portions of this file are based on pieces of Yahoo User Interface Library
3399  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3400  * YUI licensed under the BSD License:
3401  * http://developer.yahoo.net/yui/license.txt
3402  * <script type="text/javascript">
3403  *
3404  */
3405
3406 Roo.lib.AnimMgr = new function() {
3407
3408     var thread = null;
3409
3410
3411     var queue = [];
3412
3413
3414     var tweenCount = 0;
3415
3416
3417     this.fps = 1000;
3418
3419
3420     this.delay = 1;
3421
3422
3423     this.registerElement = function(tween) {
3424         queue[queue.length] = tween;
3425         tweenCount += 1;
3426         tween._onStart.fire();
3427         this.start();
3428     };
3429
3430
3431     this.unRegister = function(tween, index) {
3432         tween._onComplete.fire();
3433         index = index || getIndex(tween);
3434         if (index != -1) {
3435             queue.splice(index, 1);
3436         }
3437
3438         tweenCount -= 1;
3439         if (tweenCount <= 0) {
3440             this.stop();
3441         }
3442     };
3443
3444
3445     this.start = function() {
3446         if (thread === null) {
3447             thread = setInterval(this.run, this.delay);
3448         }
3449     };
3450
3451
3452     this.stop = function(tween) {
3453         if (!tween) {
3454             clearInterval(thread);
3455
3456             for (var i = 0, len = queue.length; i < len; ++i) {
3457                 if (queue[0].isAnimated()) {
3458                     this.unRegister(queue[0], 0);
3459                 }
3460             }
3461
3462             queue = [];
3463             thread = null;
3464             tweenCount = 0;
3465         }
3466         else {
3467             this.unRegister(tween);
3468         }
3469     };
3470
3471
3472     this.run = function() {
3473         for (var i = 0, len = queue.length; i < len; ++i) {
3474             var tween = queue[i];
3475             if (!tween || !tween.isAnimated()) {
3476                 continue;
3477             }
3478
3479             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3480             {
3481                 tween.currentFrame += 1;
3482
3483                 if (tween.useSeconds) {
3484                     correctFrame(tween);
3485                 }
3486                 tween._onTween.fire();
3487             }
3488             else {
3489                 Roo.lib.AnimMgr.stop(tween, i);
3490             }
3491         }
3492     };
3493
3494     var getIndex = function(anim) {
3495         for (var i = 0, len = queue.length; i < len; ++i) {
3496             if (queue[i] == anim) {
3497                 return i;
3498             }
3499         }
3500         return -1;
3501     };
3502
3503
3504     var correctFrame = function(tween) {
3505         var frames = tween.totalFrames;
3506         var frame = tween.currentFrame;
3507         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3508         var elapsed = (new Date() - tween.getStartTime());
3509         var tweak = 0;
3510
3511         if (elapsed < tween.duration * 1000) {
3512             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3513         } else {
3514             tweak = frames - (frame + 1);
3515         }
3516         if (tweak > 0 && isFinite(tweak)) {
3517             if (tween.currentFrame + tweak >= frames) {
3518                 tweak = frames - (frame + 1);
3519             }
3520
3521             tween.currentFrame += tweak;
3522         }
3523     };
3524 };
3525
3526     /*
3527  * Portions of this file are based on pieces of Yahoo User Interface Library
3528  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3529  * YUI licensed under the BSD License:
3530  * http://developer.yahoo.net/yui/license.txt
3531  * <script type="text/javascript">
3532  *
3533  */
3534 Roo.lib.Bezier = new function() {
3535
3536         this.getPosition = function(points, t) {
3537             var n = points.length;
3538             var tmp = [];
3539
3540             for (var i = 0; i < n; ++i) {
3541                 tmp[i] = [points[i][0], points[i][1]];
3542             }
3543
3544             for (var j = 1; j < n; ++j) {
3545                 for (i = 0; i < n - j; ++i) {
3546                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3547                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3548                 }
3549             }
3550
3551             return [ tmp[0][0], tmp[0][1] ];
3552
3553         };
3554     };/*
3555  * Portions of this file are based on pieces of Yahoo User Interface Library
3556  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557  * YUI licensed under the BSD License:
3558  * http://developer.yahoo.net/yui/license.txt
3559  * <script type="text/javascript">
3560  *
3561  */
3562 (function() {
3563
3564     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3565         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3566     };
3567
3568     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3569
3570     var fly = Roo.lib.AnimBase.fly;
3571     var Y = Roo.lib;
3572     var superclass = Y.ColorAnim.superclass;
3573     var proto = Y.ColorAnim.prototype;
3574
3575     proto.toString = function() {
3576         var el = this.getEl();
3577         var id = el.id || el.tagName;
3578         return ("ColorAnim " + id);
3579     };
3580
3581     proto.patterns.color = /color$/i;
3582     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3583     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3584     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3585     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3586
3587
3588     proto.parseColor = function(s) {
3589         if (s.length == 3) {
3590             return s;
3591         }
3592
3593         var c = this.patterns.hex.exec(s);
3594         if (c && c.length == 4) {
3595             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3596         }
3597
3598         c = this.patterns.rgb.exec(s);
3599         if (c && c.length == 4) {
3600             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3601         }
3602
3603         c = this.patterns.hex3.exec(s);
3604         if (c && c.length == 4) {
3605             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606         }
3607
3608         return null;
3609     };
3610     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3611     proto.getAttribute = function(attr) {
3612         var el = this.getEl();
3613         if (this.patterns.color.test(attr)) {
3614             var val = fly(el).getStyle(attr);
3615
3616             if (this.patterns.transparent.test(val)) {
3617                 var parent = el.parentNode;
3618                 val = fly(parent).getStyle(attr);
3619
3620                 while (parent && this.patterns.transparent.test(val)) {
3621                     parent = parent.parentNode;
3622                     val = fly(parent).getStyle(attr);
3623                     if (parent.tagName.toUpperCase() == 'HTML') {
3624                         val = '#fff';
3625                     }
3626                 }
3627             }
3628         } else {
3629             val = superclass.getAttribute.call(this, attr);
3630         }
3631
3632         return val;
3633     };
3634     proto.getAttribute = function(attr) {
3635         var el = this.getEl();
3636         if (this.patterns.color.test(attr)) {
3637             var val = fly(el).getStyle(attr);
3638
3639             if (this.patterns.transparent.test(val)) {
3640                 var parent = el.parentNode;
3641                 val = fly(parent).getStyle(attr);
3642
3643                 while (parent && this.patterns.transparent.test(val)) {
3644                     parent = parent.parentNode;
3645                     val = fly(parent).getStyle(attr);
3646                     if (parent.tagName.toUpperCase() == 'HTML') {
3647                         val = '#fff';
3648                     }
3649                 }
3650             }
3651         } else {
3652             val = superclass.getAttribute.call(this, attr);
3653         }
3654
3655         return val;
3656     };
3657
3658     proto.doMethod = function(attr, start, end) {
3659         var val;
3660
3661         if (this.patterns.color.test(attr)) {
3662             val = [];
3663             for (var i = 0, len = start.length; i < len; ++i) {
3664                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3665             }
3666
3667             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3668         }
3669         else {
3670             val = superclass.doMethod.call(this, attr, start, end);
3671         }
3672
3673         return val;
3674     };
3675
3676     proto.setRuntimeAttribute = function(attr) {
3677         superclass.setRuntimeAttribute.call(this, attr);
3678
3679         if (this.patterns.color.test(attr)) {
3680             var attributes = this.attributes;
3681             var start = this.parseColor(this.runtimeAttributes[attr].start);
3682             var end = this.parseColor(this.runtimeAttributes[attr].end);
3683
3684             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3685                 end = this.parseColor(attributes[attr].by);
3686
3687                 for (var i = 0, len = start.length; i < len; ++i) {
3688                     end[i] = start[i] + end[i];
3689                 }
3690             }
3691
3692             this.runtimeAttributes[attr].start = start;
3693             this.runtimeAttributes[attr].end = end;
3694         }
3695     };
3696 })();
3697
3698 /*
3699  * Portions of this file are based on pieces of Yahoo User Interface Library
3700  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3701  * YUI licensed under the BSD License:
3702  * http://developer.yahoo.net/yui/license.txt
3703  * <script type="text/javascript">
3704  *
3705  */
3706 Roo.lib.Easing = {
3707
3708
3709     easeNone: function (t, b, c, d) {
3710         return c * t / d + b;
3711     },
3712
3713
3714     easeIn: function (t, b, c, d) {
3715         return c * (t /= d) * t + b;
3716     },
3717
3718
3719     easeOut: function (t, b, c, d) {
3720         return -c * (t /= d) * (t - 2) + b;
3721     },
3722
3723
3724     easeBoth: function (t, b, c, d) {
3725         if ((t /= d / 2) < 1) {
3726             return c / 2 * t * t + b;
3727         }
3728
3729         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3730     },
3731
3732
3733     easeInStrong: function (t, b, c, d) {
3734         return c * (t /= d) * t * t * t + b;
3735     },
3736
3737
3738     easeOutStrong: function (t, b, c, d) {
3739         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3740     },
3741
3742
3743     easeBothStrong: function (t, b, c, d) {
3744         if ((t /= d / 2) < 1) {
3745             return c / 2 * t * t * t * t + b;
3746         }
3747
3748         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749     },
3750
3751
3752
3753     elasticIn: function (t, b, c, d, a, p) {
3754         if (t == 0) {
3755             return b;
3756         }
3757         if ((t /= d) == 1) {
3758             return b + c;
3759         }
3760         if (!p) {
3761             p = d * .3;
3762         }
3763
3764         if (!a || a < Math.abs(c)) {
3765             a = c;
3766             var s = p / 4;
3767         }
3768         else {
3769             var s = p / (2 * Math.PI) * Math.asin(c / a);
3770         }
3771
3772         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3773     },
3774
3775
3776     elasticOut: function (t, b, c, d, a, p) {
3777         if (t == 0) {
3778             return b;
3779         }
3780         if ((t /= d) == 1) {
3781             return b + c;
3782         }
3783         if (!p) {
3784             p = d * .3;
3785         }
3786
3787         if (!a || a < Math.abs(c)) {
3788             a = c;
3789             var s = p / 4;
3790         }
3791         else {
3792             var s = p / (2 * Math.PI) * Math.asin(c / a);
3793         }
3794
3795         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3796     },
3797
3798
3799     elasticBoth: function (t, b, c, d, a, p) {
3800         if (t == 0) {
3801             return b;
3802         }
3803
3804         if ((t /= d / 2) == 2) {
3805             return b + c;
3806         }
3807
3808         if (!p) {
3809             p = d * (.3 * 1.5);
3810         }
3811
3812         if (!a || a < Math.abs(c)) {
3813             a = c;
3814             var s = p / 4;
3815         }
3816         else {
3817             var s = p / (2 * Math.PI) * Math.asin(c / a);
3818         }
3819
3820         if (t < 1) {
3821             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3822                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3823         }
3824         return a * Math.pow(2, -10 * (t -= 1)) *
3825                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826     },
3827
3828
3829
3830     backIn: function (t, b, c, d, s) {
3831         if (typeof s == 'undefined') {
3832             s = 1.70158;
3833         }
3834         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3835     },
3836
3837
3838     backOut: function (t, b, c, d, s) {
3839         if (typeof s == 'undefined') {
3840             s = 1.70158;
3841         }
3842         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3843     },
3844
3845
3846     backBoth: function (t, b, c, d, s) {
3847         if (typeof s == 'undefined') {
3848             s = 1.70158;
3849         }
3850
3851         if ((t /= d / 2 ) < 1) {
3852             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3853         }
3854         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3855     },
3856
3857
3858     bounceIn: function (t, b, c, d) {
3859         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3860     },
3861
3862
3863     bounceOut: function (t, b, c, d) {
3864         if ((t /= d) < (1 / 2.75)) {
3865             return c * (7.5625 * t * t) + b;
3866         } else if (t < (2 / 2.75)) {
3867             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3868         } else if (t < (2.5 / 2.75)) {
3869             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3870         }
3871         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3872     },
3873
3874
3875     bounceBoth: function (t, b, c, d) {
3876         if (t < d / 2) {
3877             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3878         }
3879         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3880     }
3881 };/*
3882  * Portions of this file are based on pieces of Yahoo User Interface Library
3883  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3884  * YUI licensed under the BSD License:
3885  * http://developer.yahoo.net/yui/license.txt
3886  * <script type="text/javascript">
3887  *
3888  */
3889     (function() {
3890         Roo.lib.Motion = function(el, attributes, duration, method) {
3891             if (el) {
3892                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3893             }
3894         };
3895
3896         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3897
3898
3899         var Y = Roo.lib;
3900         var superclass = Y.Motion.superclass;
3901         var proto = Y.Motion.prototype;
3902
3903         proto.toString = function() {
3904             var el = this.getEl();
3905             var id = el.id || el.tagName;
3906             return ("Motion " + id);
3907         };
3908
3909         proto.patterns.points = /^points$/i;
3910
3911         proto.setAttribute = function(attr, val, unit) {
3912             if (this.patterns.points.test(attr)) {
3913                 unit = unit || 'px';
3914                 superclass.setAttribute.call(this, 'left', val[0], unit);
3915                 superclass.setAttribute.call(this, 'top', val[1], unit);
3916             } else {
3917                 superclass.setAttribute.call(this, attr, val, unit);
3918             }
3919         };
3920
3921         proto.getAttribute = function(attr) {
3922             if (this.patterns.points.test(attr)) {
3923                 var val = [
3924                         superclass.getAttribute.call(this, 'left'),
3925                         superclass.getAttribute.call(this, 'top')
3926                         ];
3927             } else {
3928                 val = superclass.getAttribute.call(this, attr);
3929             }
3930
3931             return val;
3932         };
3933
3934         proto.doMethod = function(attr, start, end) {
3935             var val = null;
3936
3937             if (this.patterns.points.test(attr)) {
3938                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3939                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3940             } else {
3941                 val = superclass.doMethod.call(this, attr, start, end);
3942             }
3943             return val;
3944         };
3945
3946         proto.setRuntimeAttribute = function(attr) {
3947             if (this.patterns.points.test(attr)) {
3948                 var el = this.getEl();
3949                 var attributes = this.attributes;
3950                 var start;
3951                 var control = attributes['points']['control'] || [];
3952                 var end;
3953                 var i, len;
3954
3955                 if (control.length > 0 && !(control[0] instanceof Array)) {
3956                     control = [control];
3957                 } else {
3958                     var tmp = [];
3959                     for (i = 0,len = control.length; i < len; ++i) {
3960                         tmp[i] = control[i];
3961                     }
3962                     control = tmp;
3963                 }
3964
3965                 Roo.fly(el).position();
3966
3967                 if (isset(attributes['points']['from'])) {
3968                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3969                 }
3970                 else {
3971                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3972                 }
3973
3974                 start = this.getAttribute('points');
3975
3976
3977                 if (isset(attributes['points']['to'])) {
3978                     end = translateValues.call(this, attributes['points']['to'], start);
3979
3980                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3981                     for (i = 0,len = control.length; i < len; ++i) {
3982                         control[i] = translateValues.call(this, control[i], start);
3983                     }
3984
3985
3986                 } else if (isset(attributes['points']['by'])) {
3987                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3988
3989                     for (i = 0,len = control.length; i < len; ++i) {
3990                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3991                     }
3992                 }
3993
3994                 this.runtimeAttributes[attr] = [start];
3995
3996                 if (control.length > 0) {
3997                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3998                 }
3999
4000                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4001             }
4002             else {
4003                 superclass.setRuntimeAttribute.call(this, attr);
4004             }
4005         };
4006
4007         var translateValues = function(val, start) {
4008             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010
4011             return val;
4012         };
4013
4014         var isset = function(prop) {
4015             return (typeof prop !== 'undefined');
4016         };
4017     })();
4018 /*
4019  * Portions of this file are based on pieces of Yahoo User Interface Library
4020  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4021  * YUI licensed under the BSD License:
4022  * http://developer.yahoo.net/yui/license.txt
4023  * <script type="text/javascript">
4024  *
4025  */
4026     (function() {
4027         Roo.lib.Scroll = function(el, attributes, duration, method) {
4028             if (el) {
4029                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4030             }
4031         };
4032
4033         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4034
4035
4036         var Y = Roo.lib;
4037         var superclass = Y.Scroll.superclass;
4038         var proto = Y.Scroll.prototype;
4039
4040         proto.toString = function() {
4041             var el = this.getEl();
4042             var id = el.id || el.tagName;
4043             return ("Scroll " + id);
4044         };
4045
4046         proto.doMethod = function(attr, start, end) {
4047             var val = null;
4048
4049             if (attr == 'scroll') {
4050                 val = [
4051                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4052                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4053                         ];
4054
4055             } else {
4056                 val = superclass.doMethod.call(this, attr, start, end);
4057             }
4058             return val;
4059         };
4060
4061         proto.getAttribute = function(attr) {
4062             var val = null;
4063             var el = this.getEl();
4064
4065             if (attr == 'scroll') {
4066                 val = [ el.scrollLeft, el.scrollTop ];
4067             } else {
4068                 val = superclass.getAttribute.call(this, attr);
4069             }
4070
4071             return val;
4072         };
4073
4074         proto.setAttribute = function(attr, val, unit) {
4075             var el = this.getEl();
4076
4077             if (attr == 'scroll') {
4078                 el.scrollLeft = val[0];
4079                 el.scrollTop = val[1];
4080             } else {
4081                 superclass.setAttribute.call(this, attr, val, unit);
4082             }
4083         };
4084     })();
4085 /*
4086  * Based on:
4087  * Ext JS Library 1.1.1
4088  * Copyright(c) 2006-2007, Ext JS, LLC.
4089  *
4090  * Originally Released Under LGPL - original licence link has changed is not relivant.
4091  *
4092  * Fork - LGPL
4093  * <script type="text/javascript">
4094  */
4095
4096
4097 // nasty IE9 hack - what a pile of crap that is..
4098
4099  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4100     Range.prototype.createContextualFragment = function (html) {
4101         var doc = window.document;
4102         var container = doc.createElement("div");
4103         container.innerHTML = html;
4104         var frag = doc.createDocumentFragment(), n;
4105         while ((n = container.firstChild)) {
4106             frag.appendChild(n);
4107         }
4108         return frag;
4109     };
4110 }
4111
4112 /**
4113  * @class Roo.DomHelper
4114  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4115  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4116  * @singleton
4117  */
4118 Roo.DomHelper = function(){
4119     var tempTableEl = null;
4120     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4121     var tableRe = /^table|tbody|tr|td$/i;
4122     var xmlns = {};
4123     // build as innerHTML where available
4124     /** @ignore */
4125     var createHtml = function(o){
4126         if(typeof o == 'string'){
4127             return o;
4128         }
4129         var b = "";
4130         if(!o.tag){
4131             o.tag = "div";
4132         }
4133         b += "<" + o.tag;
4134         for(var attr in o){
4135             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4136             if(attr == "style"){
4137                 var s = o["style"];
4138                 if(typeof s == "function"){
4139                     s = s.call();
4140                 }
4141                 if(typeof s == "string"){
4142                     b += ' style="' + s + '"';
4143                 }else if(typeof s == "object"){
4144                     b += ' style="';
4145                     for(var key in s){
4146                         if(typeof s[key] != "function"){
4147                             b += key + ":" + s[key] + ";";
4148                         }
4149                     }
4150                     b += '"';
4151                 }
4152             }else{
4153                 if(attr == "cls"){
4154                     b += ' class="' + o["cls"] + '"';
4155                 }else if(attr == "htmlFor"){
4156                     b += ' for="' + o["htmlFor"] + '"';
4157                 }else{
4158                     b += " " + attr + '="' + o[attr] + '"';
4159                 }
4160             }
4161         }
4162         if(emptyTags.test(o.tag)){
4163             b += "/>";
4164         }else{
4165             b += ">";
4166             var cn = o.children || o.cn;
4167             if(cn){
4168                 //http://bugs.kde.org/show_bug.cgi?id=71506
4169                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4170                     for(var i = 0, len = cn.length; i < len; i++) {
4171                         b += createHtml(cn[i], b);
4172                     }
4173                 }else{
4174                     b += createHtml(cn, b);
4175                 }
4176             }
4177             if(o.html){
4178                 b += o.html;
4179             }
4180             b += "</" + o.tag + ">";
4181         }
4182         return b;
4183     };
4184
4185     // build as dom
4186     /** @ignore */
4187     var createDom = function(o, parentNode){
4188          
4189         // defininition craeted..
4190         var ns = false;
4191         if (o.ns && o.ns != 'html') {
4192                
4193             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4194                 xmlns[o.ns] = o.xmlns;
4195                 ns = o.xmlns;
4196             }
4197             if (typeof(xmlns[o.ns]) == 'undefined') {
4198                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4199             }
4200             ns = xmlns[o.ns];
4201         }
4202         
4203         
4204         if (typeof(o) == 'string') {
4205             return parentNode.appendChild(document.createTextNode(o));
4206         }
4207         o.tag = o.tag || div;
4208         if (o.ns && Roo.isIE) {
4209             ns = false;
4210             o.tag = o.ns + ':' + o.tag;
4211             
4212         }
4213         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4214         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4215         for(var attr in o){
4216             
4217             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4218                     attr == "style" || typeof o[attr] == "function") continue;
4219                     
4220             if(attr=="cls" && Roo.isIE){
4221                 el.className = o["cls"];
4222             }else{
4223                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4224                 else el[attr] = o[attr];
4225             }
4226         }
4227         Roo.DomHelper.applyStyles(el, o.style);
4228         var cn = o.children || o.cn;
4229         if(cn){
4230             //http://bugs.kde.org/show_bug.cgi?id=71506
4231              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4232                 for(var i = 0, len = cn.length; i < len; i++) {
4233                     createDom(cn[i], el);
4234                 }
4235             }else{
4236                 createDom(cn, el);
4237             }
4238         }
4239         if(o.html){
4240             el.innerHTML = o.html;
4241         }
4242         if(parentNode){
4243            parentNode.appendChild(el);
4244         }
4245         return el;
4246     };
4247
4248     var ieTable = function(depth, s, h, e){
4249         tempTableEl.innerHTML = [s, h, e].join('');
4250         var i = -1, el = tempTableEl;
4251         while(++i < depth){
4252             el = el.firstChild;
4253         }
4254         return el;
4255     };
4256
4257     // kill repeat to save bytes
4258     var ts = '<table>',
4259         te = '</table>',
4260         tbs = ts+'<tbody>',
4261         tbe = '</tbody>'+te,
4262         trs = tbs + '<tr>',
4263         tre = '</tr>'+tbe;
4264
4265     /**
4266      * @ignore
4267      * Nasty code for IE's broken table implementation
4268      */
4269     var insertIntoTable = function(tag, where, el, html){
4270         if(!tempTableEl){
4271             tempTableEl = document.createElement('div');
4272         }
4273         var node;
4274         var before = null;
4275         if(tag == 'td'){
4276             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4277                 return;
4278             }
4279             if(where == 'beforebegin'){
4280                 before = el;
4281                 el = el.parentNode;
4282             } else{
4283                 before = el.nextSibling;
4284                 el = el.parentNode;
4285             }
4286             node = ieTable(4, trs, html, tre);
4287         }
4288         else if(tag == 'tr'){
4289             if(where == 'beforebegin'){
4290                 before = el;
4291                 el = el.parentNode;
4292                 node = ieTable(3, tbs, html, tbe);
4293             } else if(where == 'afterend'){
4294                 before = el.nextSibling;
4295                 el = el.parentNode;
4296                 node = ieTable(3, tbs, html, tbe);
4297             } else{ // INTO a TR
4298                 if(where == 'afterbegin'){
4299                     before = el.firstChild;
4300                 }
4301                 node = ieTable(4, trs, html, tre);
4302             }
4303         } else if(tag == 'tbody'){
4304             if(where == 'beforebegin'){
4305                 before = el;
4306                 el = el.parentNode;
4307                 node = ieTable(2, ts, html, te);
4308             } else if(where == 'afterend'){
4309                 before = el.nextSibling;
4310                 el = el.parentNode;
4311                 node = ieTable(2, ts, html, te);
4312             } else{
4313                 if(where == 'afterbegin'){
4314                     before = el.firstChild;
4315                 }
4316                 node = ieTable(3, tbs, html, tbe);
4317             }
4318         } else{ // TABLE
4319             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4320                 return;
4321             }
4322             if(where == 'afterbegin'){
4323                 before = el.firstChild;
4324             }
4325             node = ieTable(2, ts, html, te);
4326         }
4327         el.insertBefore(node, before);
4328         return node;
4329     };
4330
4331     return {
4332     /** True to force the use of DOM instead of html fragments @type Boolean */
4333     useDom : false,
4334
4335     /**
4336      * Returns the markup for the passed Element(s) config
4337      * @param {Object} o The Dom object spec (and children)
4338      * @return {String}
4339      */
4340     markup : function(o){
4341         return createHtml(o);
4342     },
4343
4344     /**
4345      * Applies a style specification to an element
4346      * @param {String/HTMLElement} el The element to apply styles to
4347      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4348      * a function which returns such a specification.
4349      */
4350     applyStyles : function(el, styles){
4351         if(styles){
4352            el = Roo.fly(el);
4353            if(typeof styles == "string"){
4354                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4355                var matches;
4356                while ((matches = re.exec(styles)) != null){
4357                    el.setStyle(matches[1], matches[2]);
4358                }
4359            }else if (typeof styles == "object"){
4360                for (var style in styles){
4361                   el.setStyle(style, styles[style]);
4362                }
4363            }else if (typeof styles == "function"){
4364                 Roo.DomHelper.applyStyles(el, styles.call());
4365            }
4366         }
4367     },
4368
4369     /**
4370      * Inserts an HTML fragment into the Dom
4371      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4372      * @param {HTMLElement} el The context element
4373      * @param {String} html The HTML fragmenet
4374      * @return {HTMLElement} The new node
4375      */
4376     insertHtml : function(where, el, html){
4377         where = where.toLowerCase();
4378         if(el.insertAdjacentHTML){
4379             if(tableRe.test(el.tagName)){
4380                 var rs;
4381                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4382                     return rs;
4383                 }
4384             }
4385             switch(where){
4386                 case "beforebegin":
4387                     el.insertAdjacentHTML('BeforeBegin', html);
4388                     return el.previousSibling;
4389                 case "afterbegin":
4390                     el.insertAdjacentHTML('AfterBegin', html);
4391                     return el.firstChild;
4392                 case "beforeend":
4393                     el.insertAdjacentHTML('BeforeEnd', html);
4394                     return el.lastChild;
4395                 case "afterend":
4396                     el.insertAdjacentHTML('AfterEnd', html);
4397                     return el.nextSibling;
4398             }
4399             throw 'Illegal insertion point -> "' + where + '"';
4400         }
4401         var range = el.ownerDocument.createRange();
4402         var frag;
4403         switch(where){
4404              case "beforebegin":
4405                 range.setStartBefore(el);
4406                 frag = range.createContextualFragment(html);
4407                 el.parentNode.insertBefore(frag, el);
4408                 return el.previousSibling;
4409              case "afterbegin":
4410                 if(el.firstChild){
4411                     range.setStartBefore(el.firstChild);
4412                     frag = range.createContextualFragment(html);
4413                     el.insertBefore(frag, el.firstChild);
4414                     return el.firstChild;
4415                 }else{
4416                     el.innerHTML = html;
4417                     return el.firstChild;
4418                 }
4419             case "beforeend":
4420                 if(el.lastChild){
4421                     range.setStartAfter(el.lastChild);
4422                     frag = range.createContextualFragment(html);
4423                     el.appendChild(frag);
4424                     return el.lastChild;
4425                 }else{
4426                     el.innerHTML = html;
4427                     return el.lastChild;
4428                 }
4429             case "afterend":
4430                 range.setStartAfter(el);
4431                 frag = range.createContextualFragment(html);
4432                 el.parentNode.insertBefore(frag, el.nextSibling);
4433                 return el.nextSibling;
4434             }
4435             throw 'Illegal insertion point -> "' + where + '"';
4436     },
4437
4438     /**
4439      * Creates new Dom element(s) and inserts them before el
4440      * @param {String/HTMLElement/Element} el The context element
4441      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4442      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4443      * @return {HTMLElement/Roo.Element} The new node
4444      */
4445     insertBefore : function(el, o, returnElement){
4446         return this.doInsert(el, o, returnElement, "beforeBegin");
4447     },
4448
4449     /**
4450      * Creates new Dom element(s) and inserts them after el
4451      * @param {String/HTMLElement/Element} el The context element
4452      * @param {Object} o The Dom object spec (and children)
4453      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4454      * @return {HTMLElement/Roo.Element} The new node
4455      */
4456     insertAfter : function(el, o, returnElement){
4457         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4458     },
4459
4460     /**
4461      * Creates new Dom element(s) and inserts them as the first child of el
4462      * @param {String/HTMLElement/Element} el The context element
4463      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4464      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4465      * @return {HTMLElement/Roo.Element} The new node
4466      */
4467     insertFirst : function(el, o, returnElement){
4468         return this.doInsert(el, o, returnElement, "afterBegin");
4469     },
4470
4471     // private
4472     doInsert : function(el, o, returnElement, pos, sibling){
4473         el = Roo.getDom(el);
4474         var newNode;
4475         if(this.useDom || o.ns){
4476             newNode = createDom(o, null);
4477             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4478         }else{
4479             var html = createHtml(o);
4480             newNode = this.insertHtml(pos, el, html);
4481         }
4482         return returnElement ? Roo.get(newNode, true) : newNode;
4483     },
4484
4485     /**
4486      * Creates new Dom element(s) and appends them to el
4487      * @param {String/HTMLElement/Element} el The context element
4488      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4489      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4490      * @return {HTMLElement/Roo.Element} The new node
4491      */
4492     append : function(el, o, returnElement){
4493         el = Roo.getDom(el);
4494         var newNode;
4495         if(this.useDom || o.ns){
4496             newNode = createDom(o, null);
4497             el.appendChild(newNode);
4498         }else{
4499             var html = createHtml(o);
4500             newNode = this.insertHtml("beforeEnd", el, html);
4501         }
4502         return returnElement ? Roo.get(newNode, true) : newNode;
4503     },
4504
4505     /**
4506      * Creates new Dom element(s) and overwrites the contents of el with them
4507      * @param {String/HTMLElement/Element} el The context element
4508      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4509      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4510      * @return {HTMLElement/Roo.Element} The new node
4511      */
4512     overwrite : function(el, o, returnElement){
4513         el = Roo.getDom(el);
4514         if (o.ns) {
4515           
4516             while (el.childNodes.length) {
4517                 el.removeChild(el.firstChild);
4518             }
4519             createDom(o, el);
4520         } else {
4521             el.innerHTML = createHtml(o);   
4522         }
4523         
4524         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4525     },
4526
4527     /**
4528      * Creates a new Roo.DomHelper.Template from the Dom object spec
4529      * @param {Object} o The Dom object spec (and children)
4530      * @return {Roo.DomHelper.Template} The new template
4531      */
4532     createTemplate : function(o){
4533         var html = createHtml(o);
4534         return new Roo.Template(html);
4535     }
4536     };
4537 }();
4538 /*
4539  * Based on:
4540  * Ext JS Library 1.1.1
4541  * Copyright(c) 2006-2007, Ext JS, LLC.
4542  *
4543  * Originally Released Under LGPL - original licence link has changed is not relivant.
4544  *
4545  * Fork - LGPL
4546  * <script type="text/javascript">
4547  */
4548  
4549 /**
4550 * @class Roo.Template
4551 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4552 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4553 * Usage:
4554 <pre><code>
4555 var t = new Roo.Template({
4556     html :  '&lt;div name="{id}"&gt;' + 
4557         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4558         '&lt;/div&gt;',
4559     myformat: function (value, allValues) {
4560         return 'XX' + value;
4561     }
4562 });
4563 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4564 </code></pre>
4565 * For more information see this blog post with examples:
4566 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4567      - Create Elements using DOM, HTML fragments and Templates</a>. 
4568 * @constructor
4569 * @param {Object} cfg - Configuration object.
4570 */
4571 Roo.Template = function(cfg){
4572     // BC!
4573     if(cfg instanceof Array){
4574         cfg = cfg.join("");
4575     }else if(arguments.length > 1){
4576         cfg = Array.prototype.join.call(arguments, "");
4577     }
4578     
4579     
4580     if (typeof(cfg) == 'object') {
4581         Roo.apply(this,cfg)
4582     } else {
4583         // bc
4584         this.html = cfg;
4585     }
4586     if (this.url) {
4587         this.load();
4588     }
4589     
4590 };
4591 Roo.Template.prototype = {
4592     
4593     /**
4594      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4595      *                    it should be fixed so that template is observable...
4596      */
4597     url : false,
4598     /**
4599      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4600      */
4601     html : '',
4602     /**
4603      * Returns an HTML fragment of this template with the specified values applied.
4604      * @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'})
4605      * @return {String} The HTML fragment
4606      */
4607     applyTemplate : function(values){
4608         try {
4609            
4610             if(this.compiled){
4611                 return this.compiled(values);
4612             }
4613             var useF = this.disableFormats !== true;
4614             var fm = Roo.util.Format, tpl = this;
4615             var fn = function(m, name, format, args){
4616                 if(format && useF){
4617                     if(format.substr(0, 5) == "this."){
4618                         return tpl.call(format.substr(5), values[name], values);
4619                     }else{
4620                         if(args){
4621                             // quoted values are required for strings in compiled templates, 
4622                             // but for non compiled we need to strip them
4623                             // quoted reversed for jsmin
4624                             var re = /^\s*['"](.*)["']\s*$/;
4625                             args = args.split(',');
4626                             for(var i = 0, len = args.length; i < len; i++){
4627                                 args[i] = args[i].replace(re, "$1");
4628                             }
4629                             args = [values[name]].concat(args);
4630                         }else{
4631                             args = [values[name]];
4632                         }
4633                         return fm[format].apply(fm, args);
4634                     }
4635                 }else{
4636                     return values[name] !== undefined ? values[name] : "";
4637                 }
4638             };
4639             return this.html.replace(this.re, fn);
4640         } catch (e) {
4641             Roo.log(e);
4642             throw e;
4643         }
4644          
4645     },
4646     
4647     loading : false,
4648       
4649     load : function ()
4650     {
4651          
4652         if (this.loading) {
4653             return;
4654         }
4655         var _t = this;
4656         
4657         this.loading = true;
4658         this.compiled = false;
4659         
4660         var cx = new Roo.data.Connection();
4661         cx.request({
4662             url : this.url,
4663             method : 'GET',
4664             success : function (response) {
4665                 _t.loading = false;
4666                 _t.html = response.responseText;
4667                 _t.url = false;
4668                 _t.compile();
4669              },
4670             failure : function(response) {
4671                 Roo.log("Template failed to load from " + _t.url);
4672                 _t.loading = false;
4673             }
4674         });
4675     },
4676
4677     /**
4678      * Sets the HTML used as the template and optionally compiles it.
4679      * @param {String} html
4680      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4681      * @return {Roo.Template} this
4682      */
4683     set : function(html, compile){
4684         this.html = html;
4685         this.compiled = null;
4686         if(compile){
4687             this.compile();
4688         }
4689         return this;
4690     },
4691     
4692     /**
4693      * True to disable format functions (defaults to false)
4694      * @type Boolean
4695      */
4696     disableFormats : false,
4697     
4698     /**
4699     * The regular expression used to match template variables 
4700     * @type RegExp
4701     * @property 
4702     */
4703     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4704     
4705     /**
4706      * Compiles the template into an internal function, eliminating the RegEx overhead.
4707      * @return {Roo.Template} this
4708      */
4709     compile : function(){
4710         var fm = Roo.util.Format;
4711         var useF = this.disableFormats !== true;
4712         var sep = Roo.isGecko ? "+" : ",";
4713         var fn = function(m, name, format, args){
4714             if(format && useF){
4715                 args = args ? ',' + args : "";
4716                 if(format.substr(0, 5) != "this."){
4717                     format = "fm." + format + '(';
4718                 }else{
4719                     format = 'this.call("'+ format.substr(5) + '", ';
4720                     args = ", values";
4721                 }
4722             }else{
4723                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4724             }
4725             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4726         };
4727         var body;
4728         // branched to use + in gecko and [].join() in others
4729         if(Roo.isGecko){
4730             body = "this.compiled = function(values){ return '" +
4731                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4732                     "';};";
4733         }else{
4734             body = ["this.compiled = function(values){ return ['"];
4735             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4736             body.push("'].join('');};");
4737             body = body.join('');
4738         }
4739         /**
4740          * eval:var:values
4741          * eval:var:fm
4742          */
4743         eval(body);
4744         return this;
4745     },
4746     
4747     // private function used to call members
4748     call : function(fnName, value, allValues){
4749         return this[fnName](value, allValues);
4750     },
4751     
4752     /**
4753      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4754      * @param {String/HTMLElement/Roo.Element} el The context element
4755      * @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'})
4756      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4757      * @return {HTMLElement/Roo.Element} The new node or Element
4758      */
4759     insertFirst: function(el, values, returnElement){
4760         return this.doInsert('afterBegin', el, values, returnElement);
4761     },
4762
4763     /**
4764      * Applies the supplied values to the template and inserts the new node(s) before el.
4765      * @param {String/HTMLElement/Roo.Element} el The context element
4766      * @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'})
4767      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4768      * @return {HTMLElement/Roo.Element} The new node or Element
4769      */
4770     insertBefore: function(el, values, returnElement){
4771         return this.doInsert('beforeBegin', el, values, returnElement);
4772     },
4773
4774     /**
4775      * Applies the supplied values to the template and inserts the new node(s) after el.
4776      * @param {String/HTMLElement/Roo.Element} el The context element
4777      * @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'})
4778      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4779      * @return {HTMLElement/Roo.Element} The new node or Element
4780      */
4781     insertAfter : function(el, values, returnElement){
4782         return this.doInsert('afterEnd', el, values, returnElement);
4783     },
4784     
4785     /**
4786      * Applies the supplied values to the template and appends the new node(s) to el.
4787      * @param {String/HTMLElement/Roo.Element} el The context element
4788      * @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'})
4789      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790      * @return {HTMLElement/Roo.Element} The new node or Element
4791      */
4792     append : function(el, values, returnElement){
4793         return this.doInsert('beforeEnd', el, values, returnElement);
4794     },
4795
4796     doInsert : function(where, el, values, returnEl){
4797         el = Roo.getDom(el);
4798         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4799         return returnEl ? Roo.get(newNode, true) : newNode;
4800     },
4801
4802     /**
4803      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4804      * @param {String/HTMLElement/Roo.Element} el The context element
4805      * @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'})
4806      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4807      * @return {HTMLElement/Roo.Element} The new node or Element
4808      */
4809     overwrite : function(el, values, returnElement){
4810         el = Roo.getDom(el);
4811         el.innerHTML = this.applyTemplate(values);
4812         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4813     }
4814 };
4815 /**
4816  * Alias for {@link #applyTemplate}
4817  * @method
4818  */
4819 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4820
4821 // backwards compat
4822 Roo.DomHelper.Template = Roo.Template;
4823
4824 /**
4825  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4826  * @param {String/HTMLElement} el A DOM element or its id
4827  * @returns {Roo.Template} The created template
4828  * @static
4829  */
4830 Roo.Template.from = function(el){
4831     el = Roo.getDom(el);
4832     return new Roo.Template(el.value || el.innerHTML);
4833 };/*
4834  * Based on:
4835  * Ext JS Library 1.1.1
4836  * Copyright(c) 2006-2007, Ext JS, LLC.
4837  *
4838  * Originally Released Under LGPL - original licence link has changed is not relivant.
4839  *
4840  * Fork - LGPL
4841  * <script type="text/javascript">
4842  */
4843  
4844
4845 /*
4846  * This is code is also distributed under MIT license for use
4847  * with jQuery and prototype JavaScript libraries.
4848  */
4849 /**
4850  * @class Roo.DomQuery
4851 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).
4852 <p>
4853 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>
4854
4855 <p>
4856 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.
4857 </p>
4858 <h4>Element Selectors:</h4>
4859 <ul class="list">
4860     <li> <b>*</b> any element</li>
4861     <li> <b>E</b> an element with the tag E</li>
4862     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4863     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4864     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4865     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4866 </ul>
4867 <h4>Attribute Selectors:</h4>
4868 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4869 <ul class="list">
4870     <li> <b>E[foo]</b> has an attribute "foo"</li>
4871     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4872     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4873     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4874     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4875     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4876     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4877 </ul>
4878 <h4>Pseudo Classes:</h4>
4879 <ul class="list">
4880     <li> <b>E:first-child</b> E is the first child of its parent</li>
4881     <li> <b>E:last-child</b> E is the last child of its parent</li>
4882     <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>
4883     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4884     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4885     <li> <b>E:only-child</b> E is the only child of its parent</li>
4886     <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>
4887     <li> <b>E:first</b> the first E in the resultset</li>
4888     <li> <b>E:last</b> the last E in the resultset</li>
4889     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4890     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4891     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4892     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4893     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4894     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4895     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4896     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4897     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4898 </ul>
4899 <h4>CSS Value Selectors:</h4>
4900 <ul class="list">
4901     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4902     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4903     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4904     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4905     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4906     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4907 </ul>
4908  * @singleton
4909  */
4910 Roo.DomQuery = function(){
4911     var cache = {}, simpleCache = {}, valueCache = {};
4912     var nonSpace = /\S/;
4913     var trimRe = /^\s+|\s+$/g;
4914     var tplRe = /\{(\d+)\}/g;
4915     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4916     var tagTokenRe = /^(#)?([\w-\*]+)/;
4917     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4918
4919     function child(p, index){
4920         var i = 0;
4921         var n = p.firstChild;
4922         while(n){
4923             if(n.nodeType == 1){
4924                if(++i == index){
4925                    return n;
4926                }
4927             }
4928             n = n.nextSibling;
4929         }
4930         return null;
4931     };
4932
4933     function next(n){
4934         while((n = n.nextSibling) && n.nodeType != 1);
4935         return n;
4936     };
4937
4938     function prev(n){
4939         while((n = n.previousSibling) && n.nodeType != 1);
4940         return n;
4941     };
4942
4943     function children(d){
4944         var n = d.firstChild, ni = -1;
4945             while(n){
4946                 var nx = n.nextSibling;
4947                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4948                     d.removeChild(n);
4949                 }else{
4950                     n.nodeIndex = ++ni;
4951                 }
4952                 n = nx;
4953             }
4954             return this;
4955         };
4956
4957     function byClassName(c, a, v){
4958         if(!v){
4959             return c;
4960         }
4961         var r = [], ri = -1, cn;
4962         for(var i = 0, ci; ci = c[i]; i++){
4963             if((' '+ci.className+' ').indexOf(v) != -1){
4964                 r[++ri] = ci;
4965             }
4966         }
4967         return r;
4968     };
4969
4970     function attrValue(n, attr){
4971         if(!n.tagName && typeof n.length != "undefined"){
4972             n = n[0];
4973         }
4974         if(!n){
4975             return null;
4976         }
4977         if(attr == "for"){
4978             return n.htmlFor;
4979         }
4980         if(attr == "class" || attr == "className"){
4981             return n.className;
4982         }
4983         return n.getAttribute(attr) || n[attr];
4984
4985     };
4986
4987     function getNodes(ns, mode, tagName){
4988         var result = [], ri = -1, cs;
4989         if(!ns){
4990             return result;
4991         }
4992         tagName = tagName || "*";
4993         if(typeof ns.getElementsByTagName != "undefined"){
4994             ns = [ns];
4995         }
4996         if(!mode){
4997             for(var i = 0, ni; ni = ns[i]; i++){
4998                 cs = ni.getElementsByTagName(tagName);
4999                 for(var j = 0, ci; ci = cs[j]; j++){
5000                     result[++ri] = ci;
5001                 }
5002             }
5003         }else if(mode == "/" || mode == ">"){
5004             var utag = tagName.toUpperCase();
5005             for(var i = 0, ni, cn; ni = ns[i]; i++){
5006                 cn = ni.children || ni.childNodes;
5007                 for(var j = 0, cj; cj = cn[j]; j++){
5008                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5009                         result[++ri] = cj;
5010                     }
5011                 }
5012             }
5013         }else if(mode == "+"){
5014             var utag = tagName.toUpperCase();
5015             for(var i = 0, n; n = ns[i]; i++){
5016                 while((n = n.nextSibling) && n.nodeType != 1);
5017                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5018                     result[++ri] = n;
5019                 }
5020             }
5021         }else if(mode == "~"){
5022             for(var i = 0, n; n = ns[i]; i++){
5023                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5024                 if(n){
5025                     result[++ri] = n;
5026                 }
5027             }
5028         }
5029         return result;
5030     };
5031
5032     function concat(a, b){
5033         if(b.slice){
5034             return a.concat(b);
5035         }
5036         for(var i = 0, l = b.length; i < l; i++){
5037             a[a.length] = b[i];
5038         }
5039         return a;
5040     }
5041
5042     function byTag(cs, tagName){
5043         if(cs.tagName || cs == document){
5044             cs = [cs];
5045         }
5046         if(!tagName){
5047             return cs;
5048         }
5049         var r = [], ri = -1;
5050         tagName = tagName.toLowerCase();
5051         for(var i = 0, ci; ci = cs[i]; i++){
5052             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5053                 r[++ri] = ci;
5054             }
5055         }
5056         return r;
5057     };
5058
5059     function byId(cs, attr, id){
5060         if(cs.tagName || cs == document){
5061             cs = [cs];
5062         }
5063         if(!id){
5064             return cs;
5065         }
5066         var r = [], ri = -1;
5067         for(var i = 0,ci; ci = cs[i]; i++){
5068             if(ci && ci.id == id){
5069                 r[++ri] = ci;
5070                 return r;
5071             }
5072         }
5073         return r;
5074     };
5075
5076     function byAttribute(cs, attr, value, op, custom){
5077         var r = [], ri = -1, st = custom=="{";
5078         var f = Roo.DomQuery.operators[op];
5079         for(var i = 0, ci; ci = cs[i]; i++){
5080             var a;
5081             if(st){
5082                 a = Roo.DomQuery.getStyle(ci, attr);
5083             }
5084             else if(attr == "class" || attr == "className"){
5085                 a = ci.className;
5086             }else if(attr == "for"){
5087                 a = ci.htmlFor;
5088             }else if(attr == "href"){
5089                 a = ci.getAttribute("href", 2);
5090             }else{
5091                 a = ci.getAttribute(attr);
5092             }
5093             if((f && f(a, value)) || (!f && a)){
5094                 r[++ri] = ci;
5095             }
5096         }
5097         return r;
5098     };
5099
5100     function byPseudo(cs, name, value){
5101         return Roo.DomQuery.pseudos[name](cs, value);
5102     };
5103
5104     // This is for IE MSXML which does not support expandos.
5105     // IE runs the same speed using setAttribute, however FF slows way down
5106     // and Safari completely fails so they need to continue to use expandos.
5107     var isIE = window.ActiveXObject ? true : false;
5108
5109     // this eval is stop the compressor from
5110     // renaming the variable to something shorter
5111     
5112     /** eval:var:batch */
5113     var batch = 30803; 
5114
5115     var key = 30803;
5116
5117     function nodupIEXml(cs){
5118         var d = ++key;
5119         cs[0].setAttribute("_nodup", d);
5120         var r = [cs[0]];
5121         for(var i = 1, len = cs.length; i < len; i++){
5122             var c = cs[i];
5123             if(!c.getAttribute("_nodup") != d){
5124                 c.setAttribute("_nodup", d);
5125                 r[r.length] = c;
5126             }
5127         }
5128         for(var i = 0, len = cs.length; i < len; i++){
5129             cs[i].removeAttribute("_nodup");
5130         }
5131         return r;
5132     }
5133
5134     function nodup(cs){
5135         if(!cs){
5136             return [];
5137         }
5138         var len = cs.length, c, i, r = cs, cj, ri = -1;
5139         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5140             return cs;
5141         }
5142         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5143             return nodupIEXml(cs);
5144         }
5145         var d = ++key;
5146         cs[0]._nodup = d;
5147         for(i = 1; c = cs[i]; i++){
5148             if(c._nodup != d){
5149                 c._nodup = d;
5150             }else{
5151                 r = [];
5152                 for(var j = 0; j < i; j++){
5153                     r[++ri] = cs[j];
5154                 }
5155                 for(j = i+1; cj = cs[j]; j++){
5156                     if(cj._nodup != d){
5157                         cj._nodup = d;
5158                         r[++ri] = cj;
5159                     }
5160                 }
5161                 return r;
5162             }
5163         }
5164         return r;
5165     }
5166
5167     function quickDiffIEXml(c1, c2){
5168         var d = ++key;
5169         for(var i = 0, len = c1.length; i < len; i++){
5170             c1[i].setAttribute("_qdiff", d);
5171         }
5172         var r = [];
5173         for(var i = 0, len = c2.length; i < len; i++){
5174             if(c2[i].getAttribute("_qdiff") != d){
5175                 r[r.length] = c2[i];
5176             }
5177         }
5178         for(var i = 0, len = c1.length; i < len; i++){
5179            c1[i].removeAttribute("_qdiff");
5180         }
5181         return r;
5182     }
5183
5184     function quickDiff(c1, c2){
5185         var len1 = c1.length;
5186         if(!len1){
5187             return c2;
5188         }
5189         if(isIE && c1[0].selectSingleNode){
5190             return quickDiffIEXml(c1, c2);
5191         }
5192         var d = ++key;
5193         for(var i = 0; i < len1; i++){
5194             c1[i]._qdiff = d;
5195         }
5196         var r = [];
5197         for(var i = 0, len = c2.length; i < len; i++){
5198             if(c2[i]._qdiff != d){
5199                 r[r.length] = c2[i];
5200             }
5201         }
5202         return r;
5203     }
5204
5205     function quickId(ns, mode, root, id){
5206         if(ns == root){
5207            var d = root.ownerDocument || root;
5208            return d.getElementById(id);
5209         }
5210         ns = getNodes(ns, mode, "*");
5211         return byId(ns, null, id);
5212     }
5213
5214     return {
5215         getStyle : function(el, name){
5216             return Roo.fly(el).getStyle(name);
5217         },
5218         /**
5219          * Compiles a selector/xpath query into a reusable function. The returned function
5220          * takes one parameter "root" (optional), which is the context node from where the query should start.
5221          * @param {String} selector The selector/xpath query
5222          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5223          * @return {Function}
5224          */
5225         compile : function(path, type){
5226             type = type || "select";
5227             
5228             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5229             var q = path, mode, lq;
5230             var tk = Roo.DomQuery.matchers;
5231             var tklen = tk.length;
5232             var mm;
5233
5234             // accept leading mode switch
5235             var lmode = q.match(modeRe);
5236             if(lmode && lmode[1]){
5237                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5238                 q = q.replace(lmode[1], "");
5239             }
5240             // strip leading slashes
5241             while(path.substr(0, 1)=="/"){
5242                 path = path.substr(1);
5243             }
5244
5245             while(q && lq != q){
5246                 lq = q;
5247                 var tm = q.match(tagTokenRe);
5248                 if(type == "select"){
5249                     if(tm){
5250                         if(tm[1] == "#"){
5251                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5252                         }else{
5253                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5254                         }
5255                         q = q.replace(tm[0], "");
5256                     }else if(q.substr(0, 1) != '@'){
5257                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258                     }
5259                 }else{
5260                     if(tm){
5261                         if(tm[1] == "#"){
5262                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5263                         }else{
5264                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5265                         }
5266                         q = q.replace(tm[0], "");
5267                     }
5268                 }
5269                 while(!(mm = q.match(modeRe))){
5270                     var matched = false;
5271                     for(var j = 0; j < tklen; j++){
5272                         var t = tk[j];
5273                         var m = q.match(t.re);
5274                         if(m){
5275                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5276                                                     return m[i];
5277                                                 });
5278                             q = q.replace(m[0], "");
5279                             matched = true;
5280                             break;
5281                         }
5282                     }
5283                     // prevent infinite loop on bad selector
5284                     if(!matched){
5285                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5286                     }
5287                 }
5288                 if(mm[1]){
5289                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5290                     q = q.replace(mm[1], "");
5291                 }
5292             }
5293             fn[fn.length] = "return nodup(n);\n}";
5294             
5295              /** 
5296               * list of variables that need from compression as they are used by eval.
5297              *  eval:var:batch 
5298              *  eval:var:nodup
5299              *  eval:var:byTag
5300              *  eval:var:ById
5301              *  eval:var:getNodes
5302              *  eval:var:quickId
5303              *  eval:var:mode
5304              *  eval:var:root
5305              *  eval:var:n
5306              *  eval:var:byClassName
5307              *  eval:var:byPseudo
5308              *  eval:var:byAttribute
5309              *  eval:var:attrValue
5310              * 
5311              **/ 
5312             eval(fn.join(""));
5313             return f;
5314         },
5315
5316         /**
5317          * Selects a group of elements.
5318          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5319          * @param {Node} root (optional) The start of the query (defaults to document).
5320          * @return {Array}
5321          */
5322         select : function(path, root, type){
5323             if(!root || root == document){
5324                 root = document;
5325             }
5326             if(typeof root == "string"){
5327                 root = document.getElementById(root);
5328             }
5329             var paths = path.split(",");
5330             var results = [];
5331             for(var i = 0, len = paths.length; i < len; i++){
5332                 var p = paths[i].replace(trimRe, "");
5333                 if(!cache[p]){
5334                     cache[p] = Roo.DomQuery.compile(p);
5335                     if(!cache[p]){
5336                         throw p + " is not a valid selector";
5337                     }
5338                 }
5339                 var result = cache[p](root);
5340                 if(result && result != document){
5341                     results = results.concat(result);
5342                 }
5343             }
5344             if(paths.length > 1){
5345                 return nodup(results);
5346             }
5347             return results;
5348         },
5349
5350         /**
5351          * Selects a single element.
5352          * @param {String} selector The selector/xpath query
5353          * @param {Node} root (optional) The start of the query (defaults to document).
5354          * @return {Element}
5355          */
5356         selectNode : function(path, root){
5357             return Roo.DomQuery.select(path, root)[0];
5358         },
5359
5360         /**
5361          * Selects the value of a node, optionally replacing null with the defaultValue.
5362          * @param {String} selector The selector/xpath query
5363          * @param {Node} root (optional) The start of the query (defaults to document).
5364          * @param {String} defaultValue
5365          */
5366         selectValue : function(path, root, defaultValue){
5367             path = path.replace(trimRe, "");
5368             if(!valueCache[path]){
5369                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5370             }
5371             var n = valueCache[path](root);
5372             n = n[0] ? n[0] : n;
5373             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5374             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5375         },
5376
5377         /**
5378          * Selects the value of a node, parsing integers and floats.
5379          * @param {String} selector The selector/xpath query
5380          * @param {Node} root (optional) The start of the query (defaults to document).
5381          * @param {Number} defaultValue
5382          * @return {Number}
5383          */
5384         selectNumber : function(path, root, defaultValue){
5385             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5386             return parseFloat(v);
5387         },
5388
5389         /**
5390          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5391          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5392          * @param {String} selector The simple selector to test
5393          * @return {Boolean}
5394          */
5395         is : function(el, ss){
5396             if(typeof el == "string"){
5397                 el = document.getElementById(el);
5398             }
5399             var isArray = (el instanceof Array);
5400             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5401             return isArray ? (result.length == el.length) : (result.length > 0);
5402         },
5403
5404         /**
5405          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5406          * @param {Array} el An array of elements to filter
5407          * @param {String} selector The simple selector to test
5408          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5409          * the selector instead of the ones that match
5410          * @return {Array}
5411          */
5412         filter : function(els, ss, nonMatches){
5413             ss = ss.replace(trimRe, "");
5414             if(!simpleCache[ss]){
5415                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5416             }
5417             var result = simpleCache[ss](els);
5418             return nonMatches ? quickDiff(result, els) : result;
5419         },
5420
5421         /**
5422          * Collection of matching regular expressions and code snippets.
5423          */
5424         matchers : [{
5425                 re: /^\.([\w-]+)/,
5426                 select: 'n = byClassName(n, null, " {1} ");'
5427             }, {
5428                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5429                 select: 'n = byPseudo(n, "{1}", "{2}");'
5430             },{
5431                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5432                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5433             }, {
5434                 re: /^#([\w-]+)/,
5435                 select: 'n = byId(n, null, "{1}");'
5436             },{
5437                 re: /^@([\w-]+)/,
5438                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439             }
5440         ],
5441
5442         /**
5443          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5444          * 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;.
5445          */
5446         operators : {
5447             "=" : function(a, v){
5448                 return a == v;
5449             },
5450             "!=" : function(a, v){
5451                 return a != v;
5452             },
5453             "^=" : function(a, v){
5454                 return a && a.substr(0, v.length) == v;
5455             },
5456             "$=" : function(a, v){
5457                 return a && a.substr(a.length-v.length) == v;
5458             },
5459             "*=" : function(a, v){
5460                 return a && a.indexOf(v) !== -1;
5461             },
5462             "%=" : function(a, v){
5463                 return (a % v) == 0;
5464             },
5465             "|=" : function(a, v){
5466                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5467             },
5468             "~=" : function(a, v){
5469                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470             }
5471         },
5472
5473         /**
5474          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5475          * and the argument (if any) supplied in the selector.
5476          */
5477         pseudos : {
5478             "first-child" : function(c){
5479                 var r = [], ri = -1, n;
5480                 for(var i = 0, ci; ci = n = c[i]; i++){
5481                     while((n = n.previousSibling) && n.nodeType != 1);
5482                     if(!n){
5483                         r[++ri] = ci;
5484                     }
5485                 }
5486                 return r;
5487             },
5488
5489             "last-child" : function(c){
5490                 var r = [], ri = -1, n;
5491                 for(var i = 0, ci; ci = n = c[i]; i++){
5492                     while((n = n.nextSibling) && n.nodeType != 1);
5493                     if(!n){
5494                         r[++ri] = ci;
5495                     }
5496                 }
5497                 return r;
5498             },
5499
5500             "nth-child" : function(c, a) {
5501                 var r = [], ri = -1;
5502                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5503                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5504                 for(var i = 0, n; n = c[i]; i++){
5505                     var pn = n.parentNode;
5506                     if (batch != pn._batch) {
5507                         var j = 0;
5508                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5509                             if(cn.nodeType == 1){
5510                                cn.nodeIndex = ++j;
5511                             }
5512                         }
5513                         pn._batch = batch;
5514                     }
5515                     if (f == 1) {
5516                         if (l == 0 || n.nodeIndex == l){
5517                             r[++ri] = n;
5518                         }
5519                     } else if ((n.nodeIndex + l) % f == 0){
5520                         r[++ri] = n;
5521                     }
5522                 }
5523
5524                 return r;
5525             },
5526
5527             "only-child" : function(c){
5528                 var r = [], ri = -1;;
5529                 for(var i = 0, ci; ci = c[i]; i++){
5530                     if(!prev(ci) && !next(ci)){
5531                         r[++ri] = ci;
5532                     }
5533                 }
5534                 return r;
5535             },
5536
5537             "empty" : function(c){
5538                 var r = [], ri = -1;
5539                 for(var i = 0, ci; ci = c[i]; i++){
5540                     var cns = ci.childNodes, j = 0, cn, empty = true;
5541                     while(cn = cns[j]){
5542                         ++j;
5543                         if(cn.nodeType == 1 || cn.nodeType == 3){
5544                             empty = false;
5545                             break;
5546                         }
5547                     }
5548                     if(empty){
5549                         r[++ri] = ci;
5550                     }
5551                 }
5552                 return r;
5553             },
5554
5555             "contains" : function(c, v){
5556                 var r = [], ri = -1;
5557                 for(var i = 0, ci; ci = c[i]; i++){
5558                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5559                         r[++ri] = ci;
5560                     }
5561                 }
5562                 return r;
5563             },
5564
5565             "nodeValue" : function(c, v){
5566                 var r = [], ri = -1;
5567                 for(var i = 0, ci; ci = c[i]; i++){
5568                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5569                         r[++ri] = ci;
5570                     }
5571                 }
5572                 return r;
5573             },
5574
5575             "checked" : function(c){
5576                 var r = [], ri = -1;
5577                 for(var i = 0, ci; ci = c[i]; i++){
5578                     if(ci.checked == true){
5579                         r[++ri] = ci;
5580                     }
5581                 }
5582                 return r;
5583             },
5584
5585             "not" : function(c, ss){
5586                 return Roo.DomQuery.filter(c, ss, true);
5587             },
5588
5589             "odd" : function(c){
5590                 return this["nth-child"](c, "odd");
5591             },
5592
5593             "even" : function(c){
5594                 return this["nth-child"](c, "even");
5595             },
5596
5597             "nth" : function(c, a){
5598                 return c[a-1] || [];
5599             },
5600
5601             "first" : function(c){
5602                 return c[0] || [];
5603             },
5604
5605             "last" : function(c){
5606                 return c[c.length-1] || [];
5607             },
5608
5609             "has" : function(c, ss){
5610                 var s = Roo.DomQuery.select;
5611                 var r = [], ri = -1;
5612                 for(var i = 0, ci; ci = c[i]; i++){
5613                     if(s(ss, ci).length > 0){
5614                         r[++ri] = ci;
5615                     }
5616                 }
5617                 return r;
5618             },
5619
5620             "next" : function(c, ss){
5621                 var is = Roo.DomQuery.is;
5622                 var r = [], ri = -1;
5623                 for(var i = 0, ci; ci = c[i]; i++){
5624                     var n = next(ci);
5625                     if(n && is(n, ss)){
5626                         r[++ri] = ci;
5627                     }
5628                 }
5629                 return r;
5630             },
5631
5632             "prev" : function(c, ss){
5633                 var is = Roo.DomQuery.is;
5634                 var r = [], ri = -1;
5635                 for(var i = 0, ci; ci = c[i]; i++){
5636                     var n = prev(ci);
5637                     if(n && is(n, ss)){
5638                         r[++ri] = ci;
5639                     }
5640                 }
5641                 return r;
5642             }
5643         }
5644     };
5645 }();
5646
5647 /**
5648  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5649  * @param {String} path The selector/xpath query
5650  * @param {Node} root (optional) The start of the query (defaults to document).
5651  * @return {Array}
5652  * @member Roo
5653  * @method query
5654  */
5655 Roo.query = Roo.DomQuery.select;
5656 /*
5657  * Based on:
5658  * Ext JS Library 1.1.1
5659  * Copyright(c) 2006-2007, Ext JS, LLC.
5660  *
5661  * Originally Released Under LGPL - original licence link has changed is not relivant.
5662  *
5663  * Fork - LGPL
5664  * <script type="text/javascript">
5665  */
5666
5667 /**
5668  * @class Roo.util.Observable
5669  * Base class that provides a common interface for publishing events. Subclasses are expected to
5670  * to have a property "events" with all the events defined.<br>
5671  * For example:
5672  * <pre><code>
5673  Employee = function(name){
5674     this.name = name;
5675     this.addEvents({
5676         "fired" : true,
5677         "quit" : true
5678     });
5679  }
5680  Roo.extend(Employee, Roo.util.Observable);
5681 </code></pre>
5682  * @param {Object} config properties to use (incuding events / listeners)
5683  */
5684
5685 Roo.util.Observable = function(cfg){
5686     
5687     cfg = cfg|| {};
5688     this.addEvents(cfg.events || {});
5689     if (cfg.events) {
5690         delete cfg.events; // make sure
5691     }
5692      
5693     Roo.apply(this, cfg);
5694     
5695     if(this.listeners){
5696         this.on(this.listeners);
5697         delete this.listeners;
5698     }
5699 };
5700 Roo.util.Observable.prototype = {
5701     /** 
5702  * @cfg {Object} listeners  list of events and functions to call for this object, 
5703  * For example :
5704  * <pre><code>
5705     listeners :  { 
5706        'click' : function(e) {
5707            ..... 
5708         } ,
5709         .... 
5710     } 
5711   </code></pre>
5712  */
5713     
5714     
5715     /**
5716      * Fires the specified event with the passed parameters (minus the event name).
5717      * @param {String} eventName
5718      * @param {Object...} args Variable number of parameters are passed to handlers
5719      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5720      */
5721     fireEvent : function(){
5722         var ce = this.events[arguments[0].toLowerCase()];
5723         if(typeof ce == "object"){
5724             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5725         }else{
5726             return true;
5727         }
5728     },
5729
5730     // private
5731     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5732
5733     /**
5734      * Appends an event handler to this component
5735      * @param {String}   eventName The type of event to listen for
5736      * @param {Function} handler The method the event invokes
5737      * @param {Object}   scope (optional) The scope in which to execute the handler
5738      * function. The handler function's "this" context.
5739      * @param {Object}   options (optional) An object containing handler configuration
5740      * properties. This may contain any of the following properties:<ul>
5741      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5742      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5743      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5744      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5745      * by the specified number of milliseconds. If the event fires again within that time, the original
5746      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5747      * </ul><br>
5748      * <p>
5749      * <b>Combining Options</b><br>
5750      * Using the options argument, it is possible to combine different types of listeners:<br>
5751      * <br>
5752      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5753                 <pre><code>
5754                 el.on('click', this.onClick, this, {
5755                         single: true,
5756                 delay: 100,
5757                 forumId: 4
5758                 });
5759                 </code></pre>
5760      * <p>
5761      * <b>Attaching multiple handlers in 1 call</b><br>
5762      * The method also allows for a single argument to be passed which is a config object containing properties
5763      * which specify multiple handlers.
5764      * <pre><code>
5765                 el.on({
5766                         'click': {
5767                         fn: this.onClick,
5768                         scope: this,
5769                         delay: 100
5770                 }, 
5771                 'mouseover': {
5772                         fn: this.onMouseOver,
5773                         scope: this
5774                 },
5775                 'mouseout': {
5776                         fn: this.onMouseOut,
5777                         scope: this
5778                 }
5779                 });
5780                 </code></pre>
5781      * <p>
5782      * Or a shorthand syntax which passes the same scope object to all handlers:
5783         <pre><code>
5784                 el.on({
5785                         'click': this.onClick,
5786                 'mouseover': this.onMouseOver,
5787                 'mouseout': this.onMouseOut,
5788                 scope: this
5789                 });
5790                 </code></pre>
5791      */
5792     addListener : function(eventName, fn, scope, o){
5793         if(typeof eventName == "object"){
5794             o = eventName;
5795             for(var e in o){
5796                 if(this.filterOptRe.test(e)){
5797                     continue;
5798                 }
5799                 if(typeof o[e] == "function"){
5800                     // shared options
5801                     this.addListener(e, o[e], o.scope,  o);
5802                 }else{
5803                     // individual options
5804                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805                 }
5806             }
5807             return;
5808         }
5809         o = (!o || typeof o == "boolean") ? {} : o;
5810         eventName = eventName.toLowerCase();
5811         var ce = this.events[eventName] || true;
5812         if(typeof ce == "boolean"){
5813             ce = new Roo.util.Event(this, eventName);
5814             this.events[eventName] = ce;
5815         }
5816         ce.addListener(fn, scope, o);
5817     },
5818
5819     /**
5820      * Removes a listener
5821      * @param {String}   eventName     The type of event to listen for
5822      * @param {Function} handler        The handler to remove
5823      * @param {Object}   scope  (optional) The scope (this object) for the handler
5824      */
5825     removeListener : function(eventName, fn, scope){
5826         var ce = this.events[eventName.toLowerCase()];
5827         if(typeof ce == "object"){
5828             ce.removeListener(fn, scope);
5829         }
5830     },
5831
5832     /**
5833      * Removes all listeners for this object
5834      */
5835     purgeListeners : function(){
5836         for(var evt in this.events){
5837             if(typeof this.events[evt] == "object"){
5838                  this.events[evt].clearListeners();
5839             }
5840         }
5841     },
5842
5843     relayEvents : function(o, events){
5844         var createHandler = function(ename){
5845             return function(){
5846                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5847             };
5848         };
5849         for(var i = 0, len = events.length; i < len; i++){
5850             var ename = events[i];
5851             if(!this.events[ename]){ this.events[ename] = true; };
5852             o.on(ename, createHandler(ename), this);
5853         }
5854     },
5855
5856     /**
5857      * Used to define events on this Observable
5858      * @param {Object} object The object with the events defined
5859      */
5860     addEvents : function(o){
5861         if(!this.events){
5862             this.events = {};
5863         }
5864         Roo.applyIf(this.events, o);
5865     },
5866
5867     /**
5868      * Checks to see if this object has any listeners for a specified event
5869      * @param {String} eventName The name of the event to check for
5870      * @return {Boolean} True if the event is being listened for, else false
5871      */
5872     hasListener : function(eventName){
5873         var e = this.events[eventName];
5874         return typeof e == "object" && e.listeners.length > 0;
5875     }
5876 };
5877 /**
5878  * Appends an event handler to this element (shorthand for addListener)
5879  * @param {String}   eventName     The type of event to listen for
5880  * @param {Function} handler        The method the event invokes
5881  * @param {Object}   scope (optional) The scope in which to execute the handler
5882  * function. The handler function's "this" context.
5883  * @param {Object}   options  (optional)
5884  * @method
5885  */
5886 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5887 /**
5888  * Removes a listener (shorthand for removeListener)
5889  * @param {String}   eventName     The type of event to listen for
5890  * @param {Function} handler        The handler to remove
5891  * @param {Object}   scope  (optional) The scope (this object) for the handler
5892  * @method
5893  */
5894 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5895
5896 /**
5897  * Starts capture on the specified Observable. All events will be passed
5898  * to the supplied function with the event name + standard signature of the event
5899  * <b>before</b> the event is fired. If the supplied function returns false,
5900  * the event will not fire.
5901  * @param {Observable} o The Observable to capture
5902  * @param {Function} fn The function to call
5903  * @param {Object} scope (optional) The scope (this object) for the fn
5904  * @static
5905  */
5906 Roo.util.Observable.capture = function(o, fn, scope){
5907     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5908 };
5909
5910 /**
5911  * Removes <b>all</b> added captures from the Observable.
5912  * @param {Observable} o The Observable to release
5913  * @static
5914  */
5915 Roo.util.Observable.releaseCapture = function(o){
5916     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 };
5918
5919 (function(){
5920
5921     var createBuffered = function(h, o, scope){
5922         var task = new Roo.util.DelayedTask();
5923         return function(){
5924             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5925         };
5926     };
5927
5928     var createSingle = function(h, e, fn, scope){
5929         return function(){
5930             e.removeListener(fn, scope);
5931             return h.apply(scope, arguments);
5932         };
5933     };
5934
5935     var createDelayed = function(h, o, scope){
5936         return function(){
5937             var args = Array.prototype.slice.call(arguments, 0);
5938             setTimeout(function(){
5939                 h.apply(scope, args);
5940             }, o.delay || 10);
5941         };
5942     };
5943
5944     Roo.util.Event = function(obj, name){
5945         this.name = name;
5946         this.obj = obj;
5947         this.listeners = [];
5948     };
5949
5950     Roo.util.Event.prototype = {
5951         addListener : function(fn, scope, options){
5952             var o = options || {};
5953             scope = scope || this.obj;
5954             if(!this.isListening(fn, scope)){
5955                 var l = {fn: fn, scope: scope, options: o};
5956                 var h = fn;
5957                 if(o.delay){
5958                     h = createDelayed(h, o, scope);
5959                 }
5960                 if(o.single){
5961                     h = createSingle(h, this, fn, scope);
5962                 }
5963                 if(o.buffer){
5964                     h = createBuffered(h, o, scope);
5965                 }
5966                 l.fireFn = h;
5967                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5968                     this.listeners.push(l);
5969                 }else{
5970                     this.listeners = this.listeners.slice(0);
5971                     this.listeners.push(l);
5972                 }
5973             }
5974         },
5975
5976         findListener : function(fn, scope){
5977             scope = scope || this.obj;
5978             var ls = this.listeners;
5979             for(var i = 0, len = ls.length; i < len; i++){
5980                 var l = ls[i];
5981                 if(l.fn == fn && l.scope == scope){
5982                     return i;
5983                 }
5984             }
5985             return -1;
5986         },
5987
5988         isListening : function(fn, scope){
5989             return this.findListener(fn, scope) != -1;
5990         },
5991
5992         removeListener : function(fn, scope){
5993             var index;
5994             if((index = this.findListener(fn, scope)) != -1){
5995                 if(!this.firing){
5996                     this.listeners.splice(index, 1);
5997                 }else{
5998                     this.listeners = this.listeners.slice(0);
5999                     this.listeners.splice(index, 1);
6000                 }
6001                 return true;
6002             }
6003             return false;
6004         },
6005
6006         clearListeners : function(){
6007             this.listeners = [];
6008         },
6009
6010         fire : function(){
6011             var ls = this.listeners, scope, len = ls.length;
6012             if(len > 0){
6013                 this.firing = true;
6014                 var args = Array.prototype.slice.call(arguments, 0);
6015                 for(var i = 0; i < len; i++){
6016                     var l = ls[i];
6017                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6018                         this.firing = false;
6019                         return false;
6020                     }
6021                 }
6022                 this.firing = false;
6023             }
6024             return true;
6025         }
6026     };
6027 })();/*
6028  * Based on:
6029  * Ext JS Library 1.1.1
6030  * Copyright(c) 2006-2007, Ext JS, LLC.
6031  *
6032  * Originally Released Under LGPL - original licence link has changed is not relivant.
6033  *
6034  * Fork - LGPL
6035  * <script type="text/javascript">
6036  */
6037
6038 /**
6039  * @class Roo.EventManager
6040  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6041  * several useful events directly.
6042  * See {@link Roo.EventObject} for more details on normalized event objects.
6043  * @singleton
6044  */
6045 Roo.EventManager = function(){
6046     var docReadyEvent, docReadyProcId, docReadyState = false;
6047     var resizeEvent, resizeTask, textEvent, textSize;
6048     var E = Roo.lib.Event;
6049     var D = Roo.lib.Dom;
6050
6051
6052     var fireDocReady = function(){
6053         if(!docReadyState){
6054             docReadyState = true;
6055             Roo.isReady = true;
6056             if(docReadyProcId){
6057                 clearInterval(docReadyProcId);
6058             }
6059             if(Roo.isGecko || Roo.isOpera) {
6060                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6061             }
6062             if(Roo.isIE){
6063                 var defer = document.getElementById("ie-deferred-loader");
6064                 if(defer){
6065                     defer.onreadystatechange = null;
6066                     defer.parentNode.removeChild(defer);
6067                 }
6068             }
6069             if(docReadyEvent){
6070                 docReadyEvent.fire();
6071                 docReadyEvent.clearListeners();
6072             }
6073         }
6074     };
6075     
6076     var initDocReady = function(){
6077         docReadyEvent = new Roo.util.Event();
6078         if(Roo.isGecko || Roo.isOpera) {
6079             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6080         }else if(Roo.isIE){
6081             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6082             var defer = document.getElementById("ie-deferred-loader");
6083             defer.onreadystatechange = function(){
6084                 if(this.readyState == "complete"){
6085                     fireDocReady();
6086                 }
6087             };
6088         }else if(Roo.isSafari){ 
6089             docReadyProcId = setInterval(function(){
6090                 var rs = document.readyState;
6091                 if(rs == "complete") {
6092                     fireDocReady();     
6093                  }
6094             }, 10);
6095         }
6096         // no matter what, make sure it fires on load
6097         E.on(window, "load", fireDocReady);
6098     };
6099
6100     var createBuffered = function(h, o){
6101         var task = new Roo.util.DelayedTask(h);
6102         return function(e){
6103             // create new event object impl so new events don't wipe out properties
6104             e = new Roo.EventObjectImpl(e);
6105             task.delay(o.buffer, h, null, [e]);
6106         };
6107     };
6108
6109     var createSingle = function(h, el, ename, fn){
6110         return function(e){
6111             Roo.EventManager.removeListener(el, ename, fn);
6112             h(e);
6113         };
6114     };
6115
6116     var createDelayed = function(h, o){
6117         return function(e){
6118             // create new event object impl so new events don't wipe out properties
6119             e = new Roo.EventObjectImpl(e);
6120             setTimeout(function(){
6121                 h(e);
6122             }, o.delay || 10);
6123         };
6124     };
6125
6126     var listen = function(element, ename, opt, fn, scope){
6127         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6128         fn = fn || o.fn; scope = scope || o.scope;
6129         var el = Roo.getDom(element);
6130         if(!el){
6131             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6132         }
6133         var h = function(e){
6134             e = Roo.EventObject.setEvent(e);
6135             var t;
6136             if(o.delegate){
6137                 t = e.getTarget(o.delegate, el);
6138                 if(!t){
6139                     return;
6140                 }
6141             }else{
6142                 t = e.target;
6143             }
6144             if(o.stopEvent === true){
6145                 e.stopEvent();
6146             }
6147             if(o.preventDefault === true){
6148                e.preventDefault();
6149             }
6150             if(o.stopPropagation === true){
6151                 e.stopPropagation();
6152             }
6153
6154             if(o.normalized === false){
6155                 e = e.browserEvent;
6156             }
6157
6158             fn.call(scope || el, e, t, o);
6159         };
6160         if(o.delay){
6161             h = createDelayed(h, o);
6162         }
6163         if(o.single){
6164             h = createSingle(h, el, ename, fn);
6165         }
6166         if(o.buffer){
6167             h = createBuffered(h, o);
6168         }
6169         fn._handlers = fn._handlers || [];
6170         fn._handlers.push([Roo.id(el), ename, h]);
6171
6172         E.on(el, ename, h);
6173         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6174             el.addEventListener("DOMMouseScroll", h, false);
6175             E.on(window, 'unload', function(){
6176                 el.removeEventListener("DOMMouseScroll", h, false);
6177             });
6178         }
6179         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6180             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6181         }
6182         return h;
6183     };
6184
6185     var stopListening = function(el, ename, fn){
6186         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6187         if(hds){
6188             for(var i = 0, len = hds.length; i < len; i++){
6189                 var h = hds[i];
6190                 if(h[0] == id && h[1] == ename){
6191                     hd = h[2];
6192                     hds.splice(i, 1);
6193                     break;
6194                 }
6195             }
6196         }
6197         E.un(el, ename, hd);
6198         el = Roo.getDom(el);
6199         if(ename == "mousewheel" && el.addEventListener){
6200             el.removeEventListener("DOMMouseScroll", hd, false);
6201         }
6202         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6203             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6204         }
6205     };
6206
6207     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6208     
6209     var pub = {
6210         
6211         
6212         /** 
6213          * Fix for doc tools
6214          * @scope Roo.EventManager
6215          */
6216         
6217         
6218         /** 
6219          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6220          * object with a Roo.EventObject
6221          * @param {Function} fn        The method the event invokes
6222          * @param {Object}   scope    An object that becomes the scope of the handler
6223          * @param {boolean}  override If true, the obj passed in becomes
6224          *                             the execution scope of the listener
6225          * @return {Function} The wrapped function
6226          * @deprecated
6227          */
6228         wrap : function(fn, scope, override){
6229             return function(e){
6230                 Roo.EventObject.setEvent(e);
6231                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6232             };
6233         },
6234         
6235         /**
6236      * Appends an event handler to an element (shorthand for addListener)
6237      * @param {String/HTMLElement}   element        The html element or id to assign the
6238      * @param {String}   eventName The type of event to listen for
6239      * @param {Function} handler The method the event invokes
6240      * @param {Object}   scope (optional) The scope in which to execute the handler
6241      * function. The handler function's "this" context.
6242      * @param {Object}   options (optional) An object containing handler configuration
6243      * properties. This may contain any of the following properties:<ul>
6244      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6245      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6246      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6247      * <li>preventDefault {Boolean} True to prevent the default action</li>
6248      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6249      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6250      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6251      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6252      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6253      * by the specified number of milliseconds. If the event fires again within that time, the original
6254      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6255      * </ul><br>
6256      * <p>
6257      * <b>Combining Options</b><br>
6258      * Using the options argument, it is possible to combine different types of listeners:<br>
6259      * <br>
6260      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6261      * Code:<pre><code>
6262 el.on('click', this.onClick, this, {
6263     single: true,
6264     delay: 100,
6265     stopEvent : true,
6266     forumId: 4
6267 });</code></pre>
6268      * <p>
6269      * <b>Attaching multiple handlers in 1 call</b><br>
6270       * The method also allows for a single argument to be passed which is a config object containing properties
6271      * which specify multiple handlers.
6272      * <p>
6273      * Code:<pre><code>
6274 el.on({
6275     'click' : {
6276         fn: this.onClick
6277         scope: this,
6278         delay: 100
6279     },
6280     'mouseover' : {
6281         fn: this.onMouseOver
6282         scope: this
6283     },
6284     'mouseout' : {
6285         fn: this.onMouseOut
6286         scope: this
6287     }
6288 });</code></pre>
6289      * <p>
6290      * Or a shorthand syntax:<br>
6291      * Code:<pre><code>
6292 el.on({
6293     'click' : this.onClick,
6294     'mouseover' : this.onMouseOver,
6295     'mouseout' : this.onMouseOut
6296     scope: this
6297 });</code></pre>
6298      */
6299         addListener : function(element, eventName, fn, scope, options){
6300             if(typeof eventName == "object"){
6301                 var o = eventName;
6302                 for(var e in o){
6303                     if(propRe.test(e)){
6304                         continue;
6305                     }
6306                     if(typeof o[e] == "function"){
6307                         // shared options
6308                         listen(element, e, o, o[e], o.scope);
6309                     }else{
6310                         // individual options
6311                         listen(element, e, o[e]);
6312                     }
6313                 }
6314                 return;
6315             }
6316             return listen(element, eventName, options, fn, scope);
6317         },
6318         
6319         /**
6320          * Removes an event handler
6321          *
6322          * @param {String/HTMLElement}   element        The id or html element to remove the 
6323          *                             event from
6324          * @param {String}   eventName     The type of event
6325          * @param {Function} fn
6326          * @return {Boolean} True if a listener was actually removed
6327          */
6328         removeListener : function(element, eventName, fn){
6329             return stopListening(element, eventName, fn);
6330         },
6331         
6332         /**
6333          * Fires when the document is ready (before onload and before images are loaded). Can be 
6334          * accessed shorthanded Roo.onReady().
6335          * @param {Function} fn        The method the event invokes
6336          * @param {Object}   scope    An  object that becomes the scope of the handler
6337          * @param {boolean}  options
6338          */
6339         onDocumentReady : function(fn, scope, options){
6340             if(docReadyState){ // if it already fired
6341                 docReadyEvent.addListener(fn, scope, options);
6342                 docReadyEvent.fire();
6343                 docReadyEvent.clearListeners();
6344                 return;
6345             }
6346             if(!docReadyEvent){
6347                 initDocReady();
6348             }
6349             docReadyEvent.addListener(fn, scope, options);
6350         },
6351         
6352         /**
6353          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6354          * @param {Function} fn        The method the event invokes
6355          * @param {Object}   scope    An object that becomes the scope of the handler
6356          * @param {boolean}  options
6357          */
6358         onWindowResize : function(fn, scope, options){
6359             if(!resizeEvent){
6360                 resizeEvent = new Roo.util.Event();
6361                 resizeTask = new Roo.util.DelayedTask(function(){
6362                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6363                 });
6364                 E.on(window, "resize", function(){
6365                     if(Roo.isIE){
6366                         resizeTask.delay(50);
6367                     }else{
6368                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6369                     }
6370                 });
6371             }
6372             resizeEvent.addListener(fn, scope, options);
6373         },
6374
6375         /**
6376          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6377          * @param {Function} fn        The method the event invokes
6378          * @param {Object}   scope    An object that becomes the scope of the handler
6379          * @param {boolean}  options
6380          */
6381         onTextResize : function(fn, scope, options){
6382             if(!textEvent){
6383                 textEvent = new Roo.util.Event();
6384                 var textEl = new Roo.Element(document.createElement('div'));
6385                 textEl.dom.className = 'x-text-resize';
6386                 textEl.dom.innerHTML = 'X';
6387                 textEl.appendTo(document.body);
6388                 textSize = textEl.dom.offsetHeight;
6389                 setInterval(function(){
6390                     if(textEl.dom.offsetHeight != textSize){
6391                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6392                     }
6393                 }, this.textResizeInterval);
6394             }
6395             textEvent.addListener(fn, scope, options);
6396         },
6397
6398         /**
6399          * Removes the passed window resize listener.
6400          * @param {Function} fn        The method the event invokes
6401          * @param {Object}   scope    The scope of handler
6402          */
6403         removeResizeListener : function(fn, scope){
6404             if(resizeEvent){
6405                 resizeEvent.removeListener(fn, scope);
6406             }
6407         },
6408
6409         // private
6410         fireResize : function(){
6411             if(resizeEvent){
6412                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6413             }   
6414         },
6415         /**
6416          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6417          */
6418         ieDeferSrc : false,
6419         /**
6420          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6421          */
6422         textResizeInterval : 50
6423     };
6424     
6425     /**
6426      * Fix for doc tools
6427      * @scopeAlias pub=Roo.EventManager
6428      */
6429     
6430      /**
6431      * Appends an event handler to an element (shorthand for addListener)
6432      * @param {String/HTMLElement}   element        The html element or id to assign the
6433      * @param {String}   eventName The type of event to listen for
6434      * @param {Function} handler The method the event invokes
6435      * @param {Object}   scope (optional) The scope in which to execute the handler
6436      * function. The handler function's "this" context.
6437      * @param {Object}   options (optional) An object containing handler configuration
6438      * properties. This may contain any of the following properties:<ul>
6439      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6440      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6441      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6442      * <li>preventDefault {Boolean} True to prevent the default action</li>
6443      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6444      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6445      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6446      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6447      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6448      * by the specified number of milliseconds. If the event fires again within that time, the original
6449      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6450      * </ul><br>
6451      * <p>
6452      * <b>Combining Options</b><br>
6453      * Using the options argument, it is possible to combine different types of listeners:<br>
6454      * <br>
6455      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6456      * Code:<pre><code>
6457 el.on('click', this.onClick, this, {
6458     single: true,
6459     delay: 100,
6460     stopEvent : true,
6461     forumId: 4
6462 });</code></pre>
6463      * <p>
6464      * <b>Attaching multiple handlers in 1 call</b><br>
6465       * The method also allows for a single argument to be passed which is a config object containing properties
6466      * which specify multiple handlers.
6467      * <p>
6468      * Code:<pre><code>
6469 el.on({
6470     'click' : {
6471         fn: this.onClick
6472         scope: this,
6473         delay: 100
6474     },
6475     'mouseover' : {
6476         fn: this.onMouseOver
6477         scope: this
6478     },
6479     'mouseout' : {
6480         fn: this.onMouseOut
6481         scope: this
6482     }
6483 });</code></pre>
6484      * <p>
6485      * Or a shorthand syntax:<br>
6486      * Code:<pre><code>
6487 el.on({
6488     'click' : this.onClick,
6489     'mouseover' : this.onMouseOver,
6490     'mouseout' : this.onMouseOut
6491     scope: this
6492 });</code></pre>
6493      */
6494     pub.on = pub.addListener;
6495     pub.un = pub.removeListener;
6496
6497     pub.stoppedMouseDownEvent = new Roo.util.Event();
6498     return pub;
6499 }();
6500 /**
6501   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6502   * @param {Function} fn        The method the event invokes
6503   * @param {Object}   scope    An  object that becomes the scope of the handler
6504   * @param {boolean}  override If true, the obj passed in becomes
6505   *                             the execution scope of the listener
6506   * @member Roo
6507   * @method onReady
6508  */
6509 Roo.onReady = Roo.EventManager.onDocumentReady;
6510
6511 Roo.onReady(function(){
6512     var bd = Roo.get(document.body);
6513     if(!bd){ return; }
6514
6515     var cls = [
6516             Roo.isIE ? "roo-ie"
6517             : Roo.isGecko ? "roo-gecko"
6518             : Roo.isOpera ? "roo-opera"
6519             : Roo.isSafari ? "roo-safari" : ""];
6520
6521     if(Roo.isMac){
6522         cls.push("roo-mac");
6523     }
6524     if(Roo.isLinux){
6525         cls.push("roo-linux");
6526     }
6527     if(Roo.isBorderBox){
6528         cls.push('roo-border-box');
6529     }
6530     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6531         var p = bd.dom.parentNode;
6532         if(p){
6533             p.className += ' roo-strict';
6534         }
6535     }
6536     bd.addClass(cls.join(' '));
6537 });
6538
6539 /**
6540  * @class Roo.EventObject
6541  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6542  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6543  * Example:
6544  * <pre><code>
6545  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6546     e.preventDefault();
6547     var target = e.getTarget();
6548     ...
6549  }
6550  var myDiv = Roo.get("myDiv");
6551  myDiv.on("click", handleClick);
6552  //or
6553  Roo.EventManager.on("myDiv", 'click', handleClick);
6554  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6555  </code></pre>
6556  * @singleton
6557  */
6558 Roo.EventObject = function(){
6559     
6560     var E = Roo.lib.Event;
6561     
6562     // safari keypress events for special keys return bad keycodes
6563     var safariKeys = {
6564         63234 : 37, // left
6565         63235 : 39, // right
6566         63232 : 38, // up
6567         63233 : 40, // down
6568         63276 : 33, // page up
6569         63277 : 34, // page down
6570         63272 : 46, // delete
6571         63273 : 36, // home
6572         63275 : 35  // end
6573     };
6574
6575     // normalize button clicks
6576     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6577                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6578
6579     Roo.EventObjectImpl = function(e){
6580         if(e){
6581             this.setEvent(e.browserEvent || e);
6582         }
6583     };
6584     Roo.EventObjectImpl.prototype = {
6585         /**
6586          * Used to fix doc tools.
6587          * @scope Roo.EventObject.prototype
6588          */
6589             
6590
6591         
6592         
6593         /** The normal browser event */
6594         browserEvent : null,
6595         /** The button pressed in a mouse event */
6596         button : -1,
6597         /** True if the shift key was down during the event */
6598         shiftKey : false,
6599         /** True if the control key was down during the event */
6600         ctrlKey : false,
6601         /** True if the alt key was down during the event */
6602         altKey : false,
6603
6604         /** Key constant 
6605         * @type Number */
6606         BACKSPACE : 8,
6607         /** Key constant 
6608         * @type Number */
6609         TAB : 9,
6610         /** Key constant 
6611         * @type Number */
6612         RETURN : 13,
6613         /** Key constant 
6614         * @type Number */
6615         ENTER : 13,
6616         /** Key constant 
6617         * @type Number */
6618         SHIFT : 16,
6619         /** Key constant 
6620         * @type Number */
6621         CONTROL : 17,
6622         /** Key constant 
6623         * @type Number */
6624         ESC : 27,
6625         /** Key constant 
6626         * @type Number */
6627         SPACE : 32,
6628         /** Key constant 
6629         * @type Number */
6630         PAGEUP : 33,
6631         /** Key constant 
6632         * @type Number */
6633         PAGEDOWN : 34,
6634         /** Key constant 
6635         * @type Number */
6636         END : 35,
6637         /** Key constant 
6638         * @type Number */
6639         HOME : 36,
6640         /** Key constant 
6641         * @type Number */
6642         LEFT : 37,
6643         /** Key constant 
6644         * @type Number */
6645         UP : 38,
6646         /** Key constant 
6647         * @type Number */
6648         RIGHT : 39,
6649         /** Key constant 
6650         * @type Number */
6651         DOWN : 40,
6652         /** Key constant 
6653         * @type Number */
6654         DELETE : 46,
6655         /** Key constant 
6656         * @type Number */
6657         F5 : 116,
6658
6659            /** @private */
6660         setEvent : function(e){
6661             if(e == this || (e && e.browserEvent)){ // already wrapped
6662                 return e;
6663             }
6664             this.browserEvent = e;
6665             if(e){
6666                 // normalize buttons
6667                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6668                 if(e.type == 'click' && this.button == -1){
6669                     this.button = 0;
6670                 }
6671                 this.type = e.type;
6672                 this.shiftKey = e.shiftKey;
6673                 // mac metaKey behaves like ctrlKey
6674                 this.ctrlKey = e.ctrlKey || e.metaKey;
6675                 this.altKey = e.altKey;
6676                 // in getKey these will be normalized for the mac
6677                 this.keyCode = e.keyCode;
6678                 // keyup warnings on firefox.
6679                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6680                 // cache the target for the delayed and or buffered events
6681                 this.target = E.getTarget(e);
6682                 // same for XY
6683                 this.xy = E.getXY(e);
6684             }else{
6685                 this.button = -1;
6686                 this.shiftKey = false;
6687                 this.ctrlKey = false;
6688                 this.altKey = false;
6689                 this.keyCode = 0;
6690                 this.charCode =0;
6691                 this.target = null;
6692                 this.xy = [0, 0];
6693             }
6694             return this;
6695         },
6696
6697         /**
6698          * Stop the event (preventDefault and stopPropagation)
6699          */
6700         stopEvent : function(){
6701             if(this.browserEvent){
6702                 if(this.browserEvent.type == 'mousedown'){
6703                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6704                 }
6705                 E.stopEvent(this.browserEvent);
6706             }
6707         },
6708
6709         /**
6710          * Prevents the browsers default handling of the event.
6711          */
6712         preventDefault : function(){
6713             if(this.browserEvent){
6714                 E.preventDefault(this.browserEvent);
6715             }
6716         },
6717
6718         /** @private */
6719         isNavKeyPress : function(){
6720             var k = this.keyCode;
6721             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6722             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6723         },
6724
6725         isSpecialKey : function(){
6726             var k = this.keyCode;
6727             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6728             (k == 16) || (k == 17) ||
6729             (k >= 18 && k <= 20) ||
6730             (k >= 33 && k <= 35) ||
6731             (k >= 36 && k <= 39) ||
6732             (k >= 44 && k <= 45);
6733         },
6734         /**
6735          * Cancels bubbling of the event.
6736          */
6737         stopPropagation : function(){
6738             if(this.browserEvent){
6739                 if(this.type == 'mousedown'){
6740                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6741                 }
6742                 E.stopPropagation(this.browserEvent);
6743             }
6744         },
6745
6746         /**
6747          * Gets the key code for the event.
6748          * @return {Number}
6749          */
6750         getCharCode : function(){
6751             return this.charCode || this.keyCode;
6752         },
6753
6754         /**
6755          * Returns a normalized keyCode for the event.
6756          * @return {Number} The key code
6757          */
6758         getKey : function(){
6759             var k = this.keyCode || this.charCode;
6760             return Roo.isSafari ? (safariKeys[k] || k) : k;
6761         },
6762
6763         /**
6764          * Gets the x coordinate of the event.
6765          * @return {Number}
6766          */
6767         getPageX : function(){
6768             return this.xy[0];
6769         },
6770
6771         /**
6772          * Gets the y coordinate of the event.
6773          * @return {Number}
6774          */
6775         getPageY : function(){
6776             return this.xy[1];
6777         },
6778
6779         /**
6780          * Gets the time of the event.
6781          * @return {Number}
6782          */
6783         getTime : function(){
6784             if(this.browserEvent){
6785                 return E.getTime(this.browserEvent);
6786             }
6787             return null;
6788         },
6789
6790         /**
6791          * Gets the page coordinates of the event.
6792          * @return {Array} The xy values like [x, y]
6793          */
6794         getXY : function(){
6795             return this.xy;
6796         },
6797
6798         /**
6799          * Gets the target for the event.
6800          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6801          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6802                 search as a number or element (defaults to 10 || document.body)
6803          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6804          * @return {HTMLelement}
6805          */
6806         getTarget : function(selector, maxDepth, returnEl){
6807             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6808         },
6809         /**
6810          * Gets the related target.
6811          * @return {HTMLElement}
6812          */
6813         getRelatedTarget : function(){
6814             if(this.browserEvent){
6815                 return E.getRelatedTarget(this.browserEvent);
6816             }
6817             return null;
6818         },
6819
6820         /**
6821          * Normalizes mouse wheel delta across browsers
6822          * @return {Number} The delta
6823          */
6824         getWheelDelta : function(){
6825             var e = this.browserEvent;
6826             var delta = 0;
6827             if(e.wheelDelta){ /* IE/Opera. */
6828                 delta = e.wheelDelta/120;
6829             }else if(e.detail){ /* Mozilla case. */
6830                 delta = -e.detail/3;
6831             }
6832             return delta;
6833         },
6834
6835         /**
6836          * Returns true if the control, meta, shift or alt key was pressed during this event.
6837          * @return {Boolean}
6838          */
6839         hasModifier : function(){
6840             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6841         },
6842
6843         /**
6844          * Returns true if the target of this event equals el or is a child of el
6845          * @param {String/HTMLElement/Element} el
6846          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6847          * @return {Boolean}
6848          */
6849         within : function(el, related){
6850             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6851             return t && Roo.fly(el).contains(t);
6852         },
6853
6854         getPoint : function(){
6855             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6856         }
6857     };
6858
6859     return new Roo.EventObjectImpl();
6860 }();
6861             
6862     /*
6863  * Based on:
6864  * Ext JS Library 1.1.1
6865  * Copyright(c) 2006-2007, Ext JS, LLC.
6866  *
6867  * Originally Released Under LGPL - original licence link has changed is not relivant.
6868  *
6869  * Fork - LGPL
6870  * <script type="text/javascript">
6871  */
6872
6873  
6874 // was in Composite Element!??!?!
6875  
6876 (function(){
6877     var D = Roo.lib.Dom;
6878     var E = Roo.lib.Event;
6879     var A = Roo.lib.Anim;
6880
6881     // local style camelizing for speed
6882     var propCache = {};
6883     var camelRe = /(-[a-z])/gi;
6884     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6885     var view = document.defaultView;
6886
6887 /**
6888  * @class Roo.Element
6889  * Represents an Element in the DOM.<br><br>
6890  * Usage:<br>
6891 <pre><code>
6892 var el = Roo.get("my-div");
6893
6894 // or with getEl
6895 var el = getEl("my-div");
6896
6897 // or with a DOM element
6898 var el = Roo.get(myDivElement);
6899 </code></pre>
6900  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6901  * each call instead of constructing a new one.<br><br>
6902  * <b>Animations</b><br />
6903  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6904  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6905 <pre>
6906 Option    Default   Description
6907 --------- --------  ---------------------------------------------
6908 duration  .35       The duration of the animation in seconds
6909 easing    easeOut   The YUI easing method
6910 callback  none      A function to execute when the anim completes
6911 scope     this      The scope (this) of the callback function
6912 </pre>
6913 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6914 * manipulate the animation. Here's an example:
6915 <pre><code>
6916 var el = Roo.get("my-div");
6917
6918 // no animation
6919 el.setWidth(100);
6920
6921 // default animation
6922 el.setWidth(100, true);
6923
6924 // animation with some options set
6925 el.setWidth(100, {
6926     duration: 1,
6927     callback: this.foo,
6928     scope: this
6929 });
6930
6931 // using the "anim" property to get the Anim object
6932 var opt = {
6933     duration: 1,
6934     callback: this.foo,
6935     scope: this
6936 };
6937 el.setWidth(100, opt);
6938 ...
6939 if(opt.anim.isAnimated()){
6940     opt.anim.stop();
6941 }
6942 </code></pre>
6943 * <b> Composite (Collections of) Elements</b><br />
6944  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6945  * @constructor Create a new Element directly.
6946  * @param {String/HTMLElement} element
6947  * @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).
6948  */
6949     Roo.Element = function(element, forceNew){
6950         var dom = typeof element == "string" ?
6951                 document.getElementById(element) : element;
6952         if(!dom){ // invalid id/element
6953             return null;
6954         }
6955         var id = dom.id;
6956         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6957             return Roo.Element.cache[id];
6958         }
6959
6960         /**
6961          * The DOM element
6962          * @type HTMLElement
6963          */
6964         this.dom = dom;
6965
6966         /**
6967          * The DOM element ID
6968          * @type String
6969          */
6970         this.id = id || Roo.id(dom);
6971     };
6972
6973     var El = Roo.Element;
6974
6975     El.prototype = {
6976         /**
6977          * The element's default display mode  (defaults to "")
6978          * @type String
6979          */
6980         originalDisplay : "",
6981
6982         visibilityMode : 1,
6983         /**
6984          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6985          * @type String
6986          */
6987         defaultUnit : "px",
6988         /**
6989          * Sets the element's visibility mode. When setVisible() is called it
6990          * will use this to determine whether to set the visibility or the display property.
6991          * @param visMode Element.VISIBILITY or Element.DISPLAY
6992          * @return {Roo.Element} this
6993          */
6994         setVisibilityMode : function(visMode){
6995             this.visibilityMode = visMode;
6996             return this;
6997         },
6998         /**
6999          * Convenience method for setVisibilityMode(Element.DISPLAY)
7000          * @param {String} display (optional) What to set display to when visible
7001          * @return {Roo.Element} this
7002          */
7003         enableDisplayMode : function(display){
7004             this.setVisibilityMode(El.DISPLAY);
7005             if(typeof display != "undefined") this.originalDisplay = display;
7006             return this;
7007         },
7008
7009         /**
7010          * 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)
7011          * @param {String} selector The simple selector to test
7012          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7013                 search as a number or element (defaults to 10 || document.body)
7014          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7015          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7016          */
7017         findParent : function(simpleSelector, maxDepth, returnEl){
7018             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7019             maxDepth = maxDepth || 50;
7020             if(typeof maxDepth != "number"){
7021                 stopEl = Roo.getDom(maxDepth);
7022                 maxDepth = 10;
7023             }
7024             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7025                 if(dq.is(p, simpleSelector)){
7026                     return returnEl ? Roo.get(p) : p;
7027                 }
7028                 depth++;
7029                 p = p.parentNode;
7030             }
7031             return null;
7032         },
7033
7034
7035         /**
7036          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7037          * @param {String} selector The simple selector to test
7038          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7039                 search as a number or element (defaults to 10 || document.body)
7040          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7041          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7042          */
7043         findParentNode : function(simpleSelector, maxDepth, returnEl){
7044             var p = Roo.fly(this.dom.parentNode, '_internal');
7045             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7046         },
7047
7048         /**
7049          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7050          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7051          * @param {String} selector The simple selector to test
7052          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7053                 search as a number or element (defaults to 10 || document.body)
7054          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7055          */
7056         up : function(simpleSelector, maxDepth){
7057             return this.findParentNode(simpleSelector, maxDepth, true);
7058         },
7059
7060
7061
7062         /**
7063          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7064          * @param {String} selector The simple selector to test
7065          * @return {Boolean} True if this element matches the selector, else false
7066          */
7067         is : function(simpleSelector){
7068             return Roo.DomQuery.is(this.dom, simpleSelector);
7069         },
7070
7071         /**
7072          * Perform animation on this element.
7073          * @param {Object} args The YUI animation control args
7074          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7075          * @param {Function} onComplete (optional) Function to call when animation completes
7076          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7077          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7078          * @return {Roo.Element} this
7079          */
7080         animate : function(args, duration, onComplete, easing, animType){
7081             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7082             return this;
7083         },
7084
7085         /*
7086          * @private Internal animation call
7087          */
7088         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7089             animType = animType || 'run';
7090             opt = opt || {};
7091             var anim = Roo.lib.Anim[animType](
7092                 this.dom, args,
7093                 (opt.duration || defaultDur) || .35,
7094                 (opt.easing || defaultEase) || 'easeOut',
7095                 function(){
7096                     Roo.callback(cb, this);
7097                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7098                 },
7099                 this
7100             );
7101             opt.anim = anim;
7102             return anim;
7103         },
7104
7105         // private legacy anim prep
7106         preanim : function(a, i){
7107             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7108         },
7109
7110         /**
7111          * Removes worthless text nodes
7112          * @param {Boolean} forceReclean (optional) By default the element
7113          * keeps track if it has been cleaned already so
7114          * you can call this over and over. However, if you update the element and
7115          * need to force a reclean, you can pass true.
7116          */
7117         clean : function(forceReclean){
7118             if(this.isCleaned && forceReclean !== true){
7119                 return this;
7120             }
7121             var ns = /\S/;
7122             var d = this.dom, n = d.firstChild, ni = -1;
7123             while(n){
7124                 var nx = n.nextSibling;
7125                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7126                     d.removeChild(n);
7127                 }else{
7128                     n.nodeIndex = ++ni;
7129                 }
7130                 n = nx;
7131             }
7132             this.isCleaned = true;
7133             return this;
7134         },
7135
7136         // private
7137         calcOffsetsTo : function(el){
7138             el = Roo.get(el);
7139             var d = el.dom;
7140             var restorePos = false;
7141             if(el.getStyle('position') == 'static'){
7142                 el.position('relative');
7143                 restorePos = true;
7144             }
7145             var x = 0, y =0;
7146             var op = this.dom;
7147             while(op && op != d && op.tagName != 'HTML'){
7148                 x+= op.offsetLeft;
7149                 y+= op.offsetTop;
7150                 op = op.offsetParent;
7151             }
7152             if(restorePos){
7153                 el.position('static');
7154             }
7155             return [x, y];
7156         },
7157
7158         /**
7159          * Scrolls this element into view within the passed container.
7160          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7161          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7162          * @return {Roo.Element} this
7163          */
7164         scrollIntoView : function(container, hscroll){
7165             var c = Roo.getDom(container) || document.body;
7166             var el = this.dom;
7167
7168             var o = this.calcOffsetsTo(c),
7169                 l = o[0],
7170                 t = o[1],
7171                 b = t+el.offsetHeight,
7172                 r = l+el.offsetWidth;
7173
7174             var ch = c.clientHeight;
7175             var ct = parseInt(c.scrollTop, 10);
7176             var cl = parseInt(c.scrollLeft, 10);
7177             var cb = ct + ch;
7178             var cr = cl + c.clientWidth;
7179
7180             if(t < ct){
7181                 c.scrollTop = t;
7182             }else if(b > cb){
7183                 c.scrollTop = b-ch;
7184             }
7185
7186             if(hscroll !== false){
7187                 if(l < cl){
7188                     c.scrollLeft = l;
7189                 }else if(r > cr){
7190                     c.scrollLeft = r-c.clientWidth;
7191                 }
7192             }
7193             return this;
7194         },
7195
7196         // private
7197         scrollChildIntoView : function(child, hscroll){
7198             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7199         },
7200
7201         /**
7202          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7203          * the new height may not be available immediately.
7204          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7205          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7206          * @param {Function} onComplete (optional) Function to call when animation completes
7207          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7208          * @return {Roo.Element} this
7209          */
7210         autoHeight : function(animate, duration, onComplete, easing){
7211             var oldHeight = this.getHeight();
7212             this.clip();
7213             this.setHeight(1); // force clipping
7214             setTimeout(function(){
7215                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7216                 if(!animate){
7217                     this.setHeight(height);
7218                     this.unclip();
7219                     if(typeof onComplete == "function"){
7220                         onComplete();
7221                     }
7222                 }else{
7223                     this.setHeight(oldHeight); // restore original height
7224                     this.setHeight(height, animate, duration, function(){
7225                         this.unclip();
7226                         if(typeof onComplete == "function") onComplete();
7227                     }.createDelegate(this), easing);
7228                 }
7229             }.createDelegate(this), 0);
7230             return this;
7231         },
7232
7233         /**
7234          * Returns true if this element is an ancestor of the passed element
7235          * @param {HTMLElement/String} el The element to check
7236          * @return {Boolean} True if this element is an ancestor of el, else false
7237          */
7238         contains : function(el){
7239             if(!el){return false;}
7240             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7241         },
7242
7243         /**
7244          * Checks whether the element is currently visible using both visibility and display properties.
7245          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7246          * @return {Boolean} True if the element is currently visible, else false
7247          */
7248         isVisible : function(deep) {
7249             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7250             if(deep !== true || !vis){
7251                 return vis;
7252             }
7253             var p = this.dom.parentNode;
7254             while(p && p.tagName.toLowerCase() != "body"){
7255                 if(!Roo.fly(p, '_isVisible').isVisible()){
7256                     return false;
7257                 }
7258                 p = p.parentNode;
7259             }
7260             return true;
7261         },
7262
7263         /**
7264          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7265          * @param {String} selector The CSS selector
7266          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7267          * @return {CompositeElement/CompositeElementLite} The composite element
7268          */
7269         select : function(selector, unique){
7270             return El.select(selector, unique, this.dom);
7271         },
7272
7273         /**
7274          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7275          * @param {String} selector The CSS selector
7276          * @return {Array} An array of the matched nodes
7277          */
7278         query : function(selector, unique){
7279             return Roo.DomQuery.select(selector, this.dom);
7280         },
7281
7282         /**
7283          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7284          * @param {String} selector The CSS selector
7285          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7286          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7287          */
7288         child : function(selector, returnDom){
7289             var n = Roo.DomQuery.selectNode(selector, this.dom);
7290             return returnDom ? n : Roo.get(n);
7291         },
7292
7293         /**
7294          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7295          * @param {String} selector The CSS selector
7296          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7297          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7298          */
7299         down : function(selector, returnDom){
7300             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7301             return returnDom ? n : Roo.get(n);
7302         },
7303
7304         /**
7305          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7306          * @param {String} group The group the DD object is member of
7307          * @param {Object} config The DD config object
7308          * @param {Object} overrides An object containing methods to override/implement on the DD object
7309          * @return {Roo.dd.DD} The DD object
7310          */
7311         initDD : function(group, config, overrides){
7312             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7313             return Roo.apply(dd, overrides);
7314         },
7315
7316         /**
7317          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7318          * @param {String} group The group the DDProxy object is member of
7319          * @param {Object} config The DDProxy config object
7320          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7321          * @return {Roo.dd.DDProxy} The DDProxy object
7322          */
7323         initDDProxy : function(group, config, overrides){
7324             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7325             return Roo.apply(dd, overrides);
7326         },
7327
7328         /**
7329          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7330          * @param {String} group The group the DDTarget object is member of
7331          * @param {Object} config The DDTarget config object
7332          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7333          * @return {Roo.dd.DDTarget} The DDTarget object
7334          */
7335         initDDTarget : function(group, config, overrides){
7336             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7337             return Roo.apply(dd, overrides);
7338         },
7339
7340         /**
7341          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7342          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7343          * @param {Boolean} visible Whether the element is visible
7344          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7345          * @return {Roo.Element} this
7346          */
7347          setVisible : function(visible, animate){
7348             if(!animate || !A){
7349                 if(this.visibilityMode == El.DISPLAY){
7350                     this.setDisplayed(visible);
7351                 }else{
7352                     this.fixDisplay();
7353                     this.dom.style.visibility = visible ? "visible" : "hidden";
7354                 }
7355             }else{
7356                 // closure for composites
7357                 var dom = this.dom;
7358                 var visMode = this.visibilityMode;
7359                 if(visible){
7360                     this.setOpacity(.01);
7361                     this.setVisible(true);
7362                 }
7363                 this.anim({opacity: { to: (visible?1:0) }},
7364                       this.preanim(arguments, 1),
7365                       null, .35, 'easeIn', function(){
7366                          if(!visible){
7367                              if(visMode == El.DISPLAY){
7368                                  dom.style.display = "none";
7369                              }else{
7370                                  dom.style.visibility = "hidden";
7371                              }
7372                              Roo.get(dom).setOpacity(1);
7373                          }
7374                      });
7375             }
7376             return this;
7377         },
7378
7379         /**
7380          * Returns true if display is not "none"
7381          * @return {Boolean}
7382          */
7383         isDisplayed : function() {
7384             return this.getStyle("display") != "none";
7385         },
7386
7387         /**
7388          * Toggles the element's visibility or display, depending on visibility mode.
7389          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7390          * @return {Roo.Element} this
7391          */
7392         toggle : function(animate){
7393             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7394             return this;
7395         },
7396
7397         /**
7398          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7399          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7400          * @return {Roo.Element} this
7401          */
7402         setDisplayed : function(value) {
7403             if(typeof value == "boolean"){
7404                value = value ? this.originalDisplay : "none";
7405             }
7406             this.setStyle("display", value);
7407             return this;
7408         },
7409
7410         /**
7411          * Tries to focus the element. Any exceptions are caught and ignored.
7412          * @return {Roo.Element} this
7413          */
7414         focus : function() {
7415             try{
7416                 this.dom.focus();
7417             }catch(e){}
7418             return this;
7419         },
7420
7421         /**
7422          * Tries to blur the element. Any exceptions are caught and ignored.
7423          * @return {Roo.Element} this
7424          */
7425         blur : function() {
7426             try{
7427                 this.dom.blur();
7428             }catch(e){}
7429             return this;
7430         },
7431
7432         /**
7433          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7434          * @param {String/Array} className The CSS class to add, or an array of classes
7435          * @return {Roo.Element} this
7436          */
7437         addClass : function(className){
7438             if(className instanceof Array){
7439                 for(var i = 0, len = className.length; i < len; i++) {
7440                     this.addClass(className[i]);
7441                 }
7442             }else{
7443                 if(className && !this.hasClass(className)){
7444                     this.dom.className = this.dom.className + " " + className;
7445                 }
7446             }
7447             return this;
7448         },
7449
7450         /**
7451          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7452          * @param {String/Array} className The CSS class to add, or an array of classes
7453          * @return {Roo.Element} this
7454          */
7455         radioClass : function(className){
7456             var siblings = this.dom.parentNode.childNodes;
7457             for(var i = 0; i < siblings.length; i++) {
7458                 var s = siblings[i];
7459                 if(s.nodeType == 1){
7460                     Roo.get(s).removeClass(className);
7461                 }
7462             }
7463             this.addClass(className);
7464             return this;
7465         },
7466
7467         /**
7468          * Removes one or more CSS classes from the element.
7469          * @param {String/Array} className The CSS class to remove, or an array of classes
7470          * @return {Roo.Element} this
7471          */
7472         removeClass : function(className){
7473             if(!className || !this.dom.className){
7474                 return this;
7475             }
7476             if(className instanceof Array){
7477                 for(var i = 0, len = className.length; i < len; i++) {
7478                     this.removeClass(className[i]);
7479                 }
7480             }else{
7481                 if(this.hasClass(className)){
7482                     var re = this.classReCache[className];
7483                     if (!re) {
7484                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7485                        this.classReCache[className] = re;
7486                     }
7487                     this.dom.className =
7488                         this.dom.className.replace(re, " ");
7489                 }
7490             }
7491             return this;
7492         },
7493
7494         // private
7495         classReCache: {},
7496
7497         /**
7498          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7499          * @param {String} className The CSS class to toggle
7500          * @return {Roo.Element} this
7501          */
7502         toggleClass : function(className){
7503             if(this.hasClass(className)){
7504                 this.removeClass(className);
7505             }else{
7506                 this.addClass(className);
7507             }
7508             return this;
7509         },
7510
7511         /**
7512          * Checks if the specified CSS class exists on this element's DOM node.
7513          * @param {String} className The CSS class to check for
7514          * @return {Boolean} True if the class exists, else false
7515          */
7516         hasClass : function(className){
7517             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7518         },
7519
7520         /**
7521          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7522          * @param {String} oldClassName The CSS class to replace
7523          * @param {String} newClassName The replacement CSS class
7524          * @return {Roo.Element} this
7525          */
7526         replaceClass : function(oldClassName, newClassName){
7527             this.removeClass(oldClassName);
7528             this.addClass(newClassName);
7529             return this;
7530         },
7531
7532         /**
7533          * Returns an object with properties matching the styles requested.
7534          * For example, el.getStyles('color', 'font-size', 'width') might return
7535          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7536          * @param {String} style1 A style name
7537          * @param {String} style2 A style name
7538          * @param {String} etc.
7539          * @return {Object} The style object
7540          */
7541         getStyles : function(){
7542             var a = arguments, len = a.length, r = {};
7543             for(var i = 0; i < len; i++){
7544                 r[a[i]] = this.getStyle(a[i]);
7545             }
7546             return r;
7547         },
7548
7549         /**
7550          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7551          * @param {String} property The style property whose value is returned.
7552          * @return {String} The current value of the style property for this element.
7553          */
7554         getStyle : function(){
7555             return view && view.getComputedStyle ?
7556                 function(prop){
7557                     var el = this.dom, v, cs, camel;
7558                     if(prop == 'float'){
7559                         prop = "cssFloat";
7560                     }
7561                     if(el.style && (v = el.style[prop])){
7562                         return v;
7563                     }
7564                     if(cs = view.getComputedStyle(el, "")){
7565                         if(!(camel = propCache[prop])){
7566                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7567                         }
7568                         return cs[camel];
7569                     }
7570                     return null;
7571                 } :
7572                 function(prop){
7573                     var el = this.dom, v, cs, camel;
7574                     if(prop == 'opacity'){
7575                         if(typeof el.style.filter == 'string'){
7576                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7577                             if(m){
7578                                 var fv = parseFloat(m[1]);
7579                                 if(!isNaN(fv)){
7580                                     return fv ? fv / 100 : 0;
7581                                 }
7582                             }
7583                         }
7584                         return 1;
7585                     }else if(prop == 'float'){
7586                         prop = "styleFloat";
7587                     }
7588                     if(!(camel = propCache[prop])){
7589                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7590                     }
7591                     if(v = el.style[camel]){
7592                         return v;
7593                     }
7594                     if(cs = el.currentStyle){
7595                         return cs[camel];
7596                     }
7597                     return null;
7598                 };
7599         }(),
7600
7601         /**
7602          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7603          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7604          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7605          * @return {Roo.Element} this
7606          */
7607         setStyle : function(prop, value){
7608             if(typeof prop == "string"){
7609                 
7610                 if (prop == 'float') {
7611                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7612                     return this;
7613                 }
7614                 
7615                 var camel;
7616                 if(!(camel = propCache[prop])){
7617                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7618                 }
7619                 
7620                 if(camel == 'opacity') {
7621                     this.setOpacity(value);
7622                 }else{
7623                     this.dom.style[camel] = value;
7624                 }
7625             }else{
7626                 for(var style in prop){
7627                     if(typeof prop[style] != "function"){
7628                        this.setStyle(style, prop[style]);
7629                     }
7630                 }
7631             }
7632             return this;
7633         },
7634
7635         /**
7636          * More flexible version of {@link #setStyle} for setting style properties.
7637          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7638          * a function which returns such a specification.
7639          * @return {Roo.Element} this
7640          */
7641         applyStyles : function(style){
7642             Roo.DomHelper.applyStyles(this.dom, style);
7643             return this;
7644         },
7645
7646         /**
7647           * 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).
7648           * @return {Number} The X position of the element
7649           */
7650         getX : function(){
7651             return D.getX(this.dom);
7652         },
7653
7654         /**
7655           * 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).
7656           * @return {Number} The Y position of the element
7657           */
7658         getY : function(){
7659             return D.getY(this.dom);
7660         },
7661
7662         /**
7663           * 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).
7664           * @return {Array} The XY position of the element
7665           */
7666         getXY : function(){
7667             return D.getXY(this.dom);
7668         },
7669
7670         /**
7671          * 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).
7672          * @param {Number} The X position of the element
7673          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7674          * @return {Roo.Element} this
7675          */
7676         setX : function(x, animate){
7677             if(!animate || !A){
7678                 D.setX(this.dom, x);
7679             }else{
7680                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7681             }
7682             return this;
7683         },
7684
7685         /**
7686          * 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).
7687          * @param {Number} The Y position of the element
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         setY : function(y, animate){
7692             if(!animate || !A){
7693                 D.setY(this.dom, y);
7694             }else{
7695                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7696             }
7697             return this;
7698         },
7699
7700         /**
7701          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7702          * @param {String} left The left CSS property value
7703          * @return {Roo.Element} this
7704          */
7705         setLeft : function(left){
7706             this.setStyle("left", this.addUnits(left));
7707             return this;
7708         },
7709
7710         /**
7711          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7712          * @param {String} top The top CSS property value
7713          * @return {Roo.Element} this
7714          */
7715         setTop : function(top){
7716             this.setStyle("top", this.addUnits(top));
7717             return this;
7718         },
7719
7720         /**
7721          * Sets the element's CSS right style.
7722          * @param {String} right The right CSS property value
7723          * @return {Roo.Element} this
7724          */
7725         setRight : function(right){
7726             this.setStyle("right", this.addUnits(right));
7727             return this;
7728         },
7729
7730         /**
7731          * Sets the element's CSS bottom style.
7732          * @param {String} bottom The bottom CSS property value
7733          * @return {Roo.Element} this
7734          */
7735         setBottom : function(bottom){
7736             this.setStyle("bottom", this.addUnits(bottom));
7737             return this;
7738         },
7739
7740         /**
7741          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7742          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7743          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7744          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7745          * @return {Roo.Element} this
7746          */
7747         setXY : function(pos, animate){
7748             if(!animate || !A){
7749                 D.setXY(this.dom, pos);
7750             }else{
7751                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7752             }
7753             return this;
7754         },
7755
7756         /**
7757          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7758          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7759          * @param {Number} x X value for new position (coordinates are page-based)
7760          * @param {Number} y Y value for new position (coordinates are page-based)
7761          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7762          * @return {Roo.Element} this
7763          */
7764         setLocation : function(x, y, animate){
7765             this.setXY([x, y], this.preanim(arguments, 2));
7766             return this;
7767         },
7768
7769         /**
7770          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7771          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7772          * @param {Number} x X value for new position (coordinates are page-based)
7773          * @param {Number} y Y value for new position (coordinates are page-based)
7774          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7775          * @return {Roo.Element} this
7776          */
7777         moveTo : function(x, y, animate){
7778             this.setXY([x, y], this.preanim(arguments, 2));
7779             return this;
7780         },
7781
7782         /**
7783          * Returns the region of the given element.
7784          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7785          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7786          */
7787         getRegion : function(){
7788             return D.getRegion(this.dom);
7789         },
7790
7791         /**
7792          * Returns the offset height of the element
7793          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7794          * @return {Number} The element's height
7795          */
7796         getHeight : function(contentHeight){
7797             var h = this.dom.offsetHeight || 0;
7798             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7799         },
7800
7801         /**
7802          * Returns the offset width of the element
7803          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7804          * @return {Number} The element's width
7805          */
7806         getWidth : function(contentWidth){
7807             var w = this.dom.offsetWidth || 0;
7808             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7809         },
7810
7811         /**
7812          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7813          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7814          * if a height has not been set using CSS.
7815          * @return {Number}
7816          */
7817         getComputedHeight : function(){
7818             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7819             if(!h){
7820                 h = parseInt(this.getStyle('height'), 10) || 0;
7821                 if(!this.isBorderBox()){
7822                     h += this.getFrameWidth('tb');
7823                 }
7824             }
7825             return h;
7826         },
7827
7828         /**
7829          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7830          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7831          * if a width has not been set using CSS.
7832          * @return {Number}
7833          */
7834         getComputedWidth : function(){
7835             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7836             if(!w){
7837                 w = parseInt(this.getStyle('width'), 10) || 0;
7838                 if(!this.isBorderBox()){
7839                     w += this.getFrameWidth('lr');
7840                 }
7841             }
7842             return w;
7843         },
7844
7845         /**
7846          * Returns the size of the element.
7847          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7848          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7849          */
7850         getSize : function(contentSize){
7851             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7852         },
7853
7854         /**
7855          * Returns the width and height of the viewport.
7856          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7857          */
7858         getViewSize : function(){
7859             var d = this.dom, doc = document, aw = 0, ah = 0;
7860             if(d == doc || d == doc.body){
7861                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7862             }else{
7863                 return {
7864                     width : d.clientWidth,
7865                     height: d.clientHeight
7866                 };
7867             }
7868         },
7869
7870         /**
7871          * Returns the value of the "value" attribute
7872          * @param {Boolean} asNumber true to parse the value as a number
7873          * @return {String/Number}
7874          */
7875         getValue : function(asNumber){
7876             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7877         },
7878
7879         // private
7880         adjustWidth : function(width){
7881             if(typeof width == "number"){
7882                 if(this.autoBoxAdjust && !this.isBorderBox()){
7883                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7884                 }
7885                 if(width < 0){
7886                     width = 0;
7887                 }
7888             }
7889             return width;
7890         },
7891
7892         // private
7893         adjustHeight : function(height){
7894             if(typeof height == "number"){
7895                if(this.autoBoxAdjust && !this.isBorderBox()){
7896                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7897                }
7898                if(height < 0){
7899                    height = 0;
7900                }
7901             }
7902             return height;
7903         },
7904
7905         /**
7906          * Set the width of the element
7907          * @param {Number} width The new width
7908          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7909          * @return {Roo.Element} this
7910          */
7911         setWidth : function(width, animate){
7912             width = this.adjustWidth(width);
7913             if(!animate || !A){
7914                 this.dom.style.width = this.addUnits(width);
7915             }else{
7916                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7917             }
7918             return this;
7919         },
7920
7921         /**
7922          * Set the height of the element
7923          * @param {Number} height The new height
7924          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7925          * @return {Roo.Element} this
7926          */
7927          setHeight : function(height, animate){
7928             height = this.adjustHeight(height);
7929             if(!animate || !A){
7930                 this.dom.style.height = this.addUnits(height);
7931             }else{
7932                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7933             }
7934             return this;
7935         },
7936
7937         /**
7938          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7939          * @param {Number} width The new width
7940          * @param {Number} height The new height
7941          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7942          * @return {Roo.Element} this
7943          */
7944          setSize : function(width, height, animate){
7945             if(typeof width == "object"){ // in case of object from getSize()
7946                 height = width.height; width = width.width;
7947             }
7948             width = this.adjustWidth(width); height = this.adjustHeight(height);
7949             if(!animate || !A){
7950                 this.dom.style.width = this.addUnits(width);
7951                 this.dom.style.height = this.addUnits(height);
7952             }else{
7953                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7954             }
7955             return this;
7956         },
7957
7958         /**
7959          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7960          * @param {Number} x X value for new position (coordinates are page-based)
7961          * @param {Number} y Y value for new position (coordinates are page-based)
7962          * @param {Number} width The new width
7963          * @param {Number} height The new height
7964          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7965          * @return {Roo.Element} this
7966          */
7967         setBounds : function(x, y, width, height, animate){
7968             if(!animate || !A){
7969                 this.setSize(width, height);
7970                 this.setLocation(x, y);
7971             }else{
7972                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7973                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7974                               this.preanim(arguments, 4), 'motion');
7975             }
7976             return this;
7977         },
7978
7979         /**
7980          * 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.
7981          * @param {Roo.lib.Region} region The region to fill
7982          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7983          * @return {Roo.Element} this
7984          */
7985         setRegion : function(region, animate){
7986             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7987             return this;
7988         },
7989
7990         /**
7991          * Appends an event handler
7992          *
7993          * @param {String}   eventName     The type of event to append
7994          * @param {Function} fn        The method the event invokes
7995          * @param {Object} scope       (optional) The scope (this object) of the fn
7996          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7997          */
7998         addListener : function(eventName, fn, scope, options){
7999             if (this.dom) {
8000                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8001             }
8002         },
8003
8004         /**
8005          * Removes an event handler from this element
8006          * @param {String} eventName the type of event to remove
8007          * @param {Function} fn the method the event invokes
8008          * @return {Roo.Element} this
8009          */
8010         removeListener : function(eventName, fn){
8011             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8012             return this;
8013         },
8014
8015         /**
8016          * Removes all previous added listeners from this element
8017          * @return {Roo.Element} this
8018          */
8019         removeAllListeners : function(){
8020             E.purgeElement(this.dom);
8021             return this;
8022         },
8023
8024         relayEvent : function(eventName, observable){
8025             this.on(eventName, function(e){
8026                 observable.fireEvent(eventName, e);
8027             });
8028         },
8029
8030         /**
8031          * Set the opacity of the element
8032          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8033          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8034          * @return {Roo.Element} this
8035          */
8036          setOpacity : function(opacity, animate){
8037             if(!animate || !A){
8038                 var s = this.dom.style;
8039                 if(Roo.isIE){
8040                     s.zoom = 1;
8041                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8042                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8043                 }else{
8044                     s.opacity = opacity;
8045                 }
8046             }else{
8047                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8048             }
8049             return this;
8050         },
8051
8052         /**
8053          * Gets the left X coordinate
8054          * @param {Boolean} local True to get the local css position instead of page coordinate
8055          * @return {Number}
8056          */
8057         getLeft : function(local){
8058             if(!local){
8059                 return this.getX();
8060             }else{
8061                 return parseInt(this.getStyle("left"), 10) || 0;
8062             }
8063         },
8064
8065         /**
8066          * Gets the right X coordinate of the element (element X position + element width)
8067          * @param {Boolean} local True to get the local css position instead of page coordinate
8068          * @return {Number}
8069          */
8070         getRight : function(local){
8071             if(!local){
8072                 return this.getX() + this.getWidth();
8073             }else{
8074                 return (this.getLeft(true) + this.getWidth()) || 0;
8075             }
8076         },
8077
8078         /**
8079          * Gets the top Y coordinate
8080          * @param {Boolean} local True to get the local css position instead of page coordinate
8081          * @return {Number}
8082          */
8083         getTop : function(local) {
8084             if(!local){
8085                 return this.getY();
8086             }else{
8087                 return parseInt(this.getStyle("top"), 10) || 0;
8088             }
8089         },
8090
8091         /**
8092          * Gets the bottom Y coordinate of the element (element Y position + element height)
8093          * @param {Boolean} local True to get the local css position instead of page coordinate
8094          * @return {Number}
8095          */
8096         getBottom : function(local){
8097             if(!local){
8098                 return this.getY() + this.getHeight();
8099             }else{
8100                 return (this.getTop(true) + this.getHeight()) || 0;
8101             }
8102         },
8103
8104         /**
8105         * Initializes positioning on this element. If a desired position is not passed, it will make the
8106         * the element positioned relative IF it is not already positioned.
8107         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8108         * @param {Number} zIndex (optional) The zIndex to apply
8109         * @param {Number} x (optional) Set the page X position
8110         * @param {Number} y (optional) Set the page Y position
8111         */
8112         position : function(pos, zIndex, x, y){
8113             if(!pos){
8114                if(this.getStyle('position') == 'static'){
8115                    this.setStyle('position', 'relative');
8116                }
8117             }else{
8118                 this.setStyle("position", pos);
8119             }
8120             if(zIndex){
8121                 this.setStyle("z-index", zIndex);
8122             }
8123             if(x !== undefined && y !== undefined){
8124                 this.setXY([x, y]);
8125             }else if(x !== undefined){
8126                 this.setX(x);
8127             }else if(y !== undefined){
8128                 this.setY(y);
8129             }
8130         },
8131
8132         /**
8133         * Clear positioning back to the default when the document was loaded
8134         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8135         * @return {Roo.Element} this
8136          */
8137         clearPositioning : function(value){
8138             value = value ||'';
8139             this.setStyle({
8140                 "left": value,
8141                 "right": value,
8142                 "top": value,
8143                 "bottom": value,
8144                 "z-index": "",
8145                 "position" : "static"
8146             });
8147             return this;
8148         },
8149
8150         /**
8151         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8152         * snapshot before performing an update and then restoring the element.
8153         * @return {Object}
8154         */
8155         getPositioning : function(){
8156             var l = this.getStyle("left");
8157             var t = this.getStyle("top");
8158             return {
8159                 "position" : this.getStyle("position"),
8160                 "left" : l,
8161                 "right" : l ? "" : this.getStyle("right"),
8162                 "top" : t,
8163                 "bottom" : t ? "" : this.getStyle("bottom"),
8164                 "z-index" : this.getStyle("z-index")
8165             };
8166         },
8167
8168         /**
8169          * Gets the width of the border(s) for the specified side(s)
8170          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8171          * passing lr would get the border (l)eft width + the border (r)ight width.
8172          * @return {Number} The width of the sides passed added together
8173          */
8174         getBorderWidth : function(side){
8175             return this.addStyles(side, El.borders);
8176         },
8177
8178         /**
8179          * Gets the width of the padding(s) for the specified side(s)
8180          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8181          * passing lr would get the padding (l)eft + the padding (r)ight.
8182          * @return {Number} The padding of the sides passed added together
8183          */
8184         getPadding : function(side){
8185             return this.addStyles(side, El.paddings);
8186         },
8187
8188         /**
8189         * Set positioning with an object returned by getPositioning().
8190         * @param {Object} posCfg
8191         * @return {Roo.Element} this
8192          */
8193         setPositioning : function(pc){
8194             this.applyStyles(pc);
8195             if(pc.right == "auto"){
8196                 this.dom.style.right = "";
8197             }
8198             if(pc.bottom == "auto"){
8199                 this.dom.style.bottom = "";
8200             }
8201             return this;
8202         },
8203
8204         // private
8205         fixDisplay : function(){
8206             if(this.getStyle("display") == "none"){
8207                 this.setStyle("visibility", "hidden");
8208                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8209                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8210                     this.setStyle("display", "block");
8211                 }
8212             }
8213         },
8214
8215         /**
8216          * Quick set left and top adding default units
8217          * @param {String} left The left CSS property value
8218          * @param {String} top The top CSS property value
8219          * @return {Roo.Element} this
8220          */
8221          setLeftTop : function(left, top){
8222             this.dom.style.left = this.addUnits(left);
8223             this.dom.style.top = this.addUnits(top);
8224             return this;
8225         },
8226
8227         /**
8228          * Move this element relative to its current position.
8229          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8230          * @param {Number} distance How far to move the element in pixels
8231          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8232          * @return {Roo.Element} this
8233          */
8234          move : function(direction, distance, animate){
8235             var xy = this.getXY();
8236             direction = direction.toLowerCase();
8237             switch(direction){
8238                 case "l":
8239                 case "left":
8240                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8241                     break;
8242                case "r":
8243                case "right":
8244                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8245                     break;
8246                case "t":
8247                case "top":
8248                case "up":
8249                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8250                     break;
8251                case "b":
8252                case "bottom":
8253                case "down":
8254                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8255                     break;
8256             }
8257             return this;
8258         },
8259
8260         /**
8261          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8262          * @return {Roo.Element} this
8263          */
8264         clip : function(){
8265             if(!this.isClipped){
8266                this.isClipped = true;
8267                this.originalClip = {
8268                    "o": this.getStyle("overflow"),
8269                    "x": this.getStyle("overflow-x"),
8270                    "y": this.getStyle("overflow-y")
8271                };
8272                this.setStyle("overflow", "hidden");
8273                this.setStyle("overflow-x", "hidden");
8274                this.setStyle("overflow-y", "hidden");
8275             }
8276             return this;
8277         },
8278
8279         /**
8280          *  Return clipping (overflow) to original clipping before clip() was called
8281          * @return {Roo.Element} this
8282          */
8283         unclip : function(){
8284             if(this.isClipped){
8285                 this.isClipped = false;
8286                 var o = this.originalClip;
8287                 if(o.o){this.setStyle("overflow", o.o);}
8288                 if(o.x){this.setStyle("overflow-x", o.x);}
8289                 if(o.y){this.setStyle("overflow-y", o.y);}
8290             }
8291             return this;
8292         },
8293
8294
8295         /**
8296          * Gets the x,y coordinates specified by the anchor position on the element.
8297          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8298          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8299          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8300          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8301          * @return {Array} [x, y] An array containing the element's x and y coordinates
8302          */
8303         getAnchorXY : function(anchor, local, s){
8304             //Passing a different size is useful for pre-calculating anchors,
8305             //especially for anchored animations that change the el size.
8306
8307             var w, h, vp = false;
8308             if(!s){
8309                 var d = this.dom;
8310                 if(d == document.body || d == document){
8311                     vp = true;
8312                     w = D.getViewWidth(); h = D.getViewHeight();
8313                 }else{
8314                     w = this.getWidth(); h = this.getHeight();
8315                 }
8316             }else{
8317                 w = s.width;  h = s.height;
8318             }
8319             var x = 0, y = 0, r = Math.round;
8320             switch((anchor || "tl").toLowerCase()){
8321                 case "c":
8322                     x = r(w*.5);
8323                     y = r(h*.5);
8324                 break;
8325                 case "t":
8326                     x = r(w*.5);
8327                     y = 0;
8328                 break;
8329                 case "l":
8330                     x = 0;
8331                     y = r(h*.5);
8332                 break;
8333                 case "r":
8334                     x = w;
8335                     y = r(h*.5);
8336                 break;
8337                 case "b":
8338                     x = r(w*.5);
8339                     y = h;
8340                 break;
8341                 case "tl":
8342                     x = 0;
8343                     y = 0;
8344                 break;
8345                 case "bl":
8346                     x = 0;
8347                     y = h;
8348                 break;
8349                 case "br":
8350                     x = w;
8351                     y = h;
8352                 break;
8353                 case "tr":
8354                     x = w;
8355                     y = 0;
8356                 break;
8357             }
8358             if(local === true){
8359                 return [x, y];
8360             }
8361             if(vp){
8362                 var sc = this.getScroll();
8363                 return [x + sc.left, y + sc.top];
8364             }
8365             //Add the element's offset xy
8366             var o = this.getXY();
8367             return [x+o[0], y+o[1]];
8368         },
8369
8370         /**
8371          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8372          * supported position values.
8373          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8374          * @param {String} position The position to align to.
8375          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8376          * @return {Array} [x, y]
8377          */
8378         getAlignToXY : function(el, p, o){
8379             el = Roo.get(el);
8380             var d = this.dom;
8381             if(!el.dom){
8382                 throw "Element.alignTo with an element that doesn't exist";
8383             }
8384             var c = false; //constrain to viewport
8385             var p1 = "", p2 = "";
8386             o = o || [0,0];
8387
8388             if(!p){
8389                 p = "tl-bl";
8390             }else if(p == "?"){
8391                 p = "tl-bl?";
8392             }else if(p.indexOf("-") == -1){
8393                 p = "tl-" + p;
8394             }
8395             p = p.toLowerCase();
8396             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8397             if(!m){
8398                throw "Element.alignTo with an invalid alignment " + p;
8399             }
8400             p1 = m[1]; p2 = m[2]; c = !!m[3];
8401
8402             //Subtract the aligned el's internal xy from the target's offset xy
8403             //plus custom offset to get the aligned el's new offset xy
8404             var a1 = this.getAnchorXY(p1, true);
8405             var a2 = el.getAnchorXY(p2, false);
8406             var x = a2[0] - a1[0] + o[0];
8407             var y = a2[1] - a1[1] + o[1];
8408             if(c){
8409                 //constrain the aligned el to viewport if necessary
8410                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8411                 // 5px of margin for ie
8412                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8413
8414                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8415                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8416                 //otherwise swap the aligned el to the opposite border of the target.
8417                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8418                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8419                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8420                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8421
8422                var doc = document;
8423                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8424                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8425
8426                if((x+w) > dw + scrollX){
8427                     x = swapX ? r.left-w : dw+scrollX-w;
8428                 }
8429                if(x < scrollX){
8430                    x = swapX ? r.right : scrollX;
8431                }
8432                if((y+h) > dh + scrollY){
8433                     y = swapY ? r.top-h : dh+scrollY-h;
8434                 }
8435                if (y < scrollY){
8436                    y = swapY ? r.bottom : scrollY;
8437                }
8438             }
8439             return [x,y];
8440         },
8441
8442         // private
8443         getConstrainToXY : function(){
8444             var os = {top:0, left:0, bottom:0, right: 0};
8445
8446             return function(el, local, offsets, proposedXY){
8447                 el = Roo.get(el);
8448                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8449
8450                 var vw, vh, vx = 0, vy = 0;
8451                 if(el.dom == document.body || el.dom == document){
8452                     vw = Roo.lib.Dom.getViewWidth();
8453                     vh = Roo.lib.Dom.getViewHeight();
8454                 }else{
8455                     vw = el.dom.clientWidth;
8456                     vh = el.dom.clientHeight;
8457                     if(!local){
8458                         var vxy = el.getXY();
8459                         vx = vxy[0];
8460                         vy = vxy[1];
8461                     }
8462                 }
8463
8464                 var s = el.getScroll();
8465
8466                 vx += offsets.left + s.left;
8467                 vy += offsets.top + s.top;
8468
8469                 vw -= offsets.right;
8470                 vh -= offsets.bottom;
8471
8472                 var vr = vx+vw;
8473                 var vb = vy+vh;
8474
8475                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8476                 var x = xy[0], y = xy[1];
8477                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8478
8479                 // only move it if it needs it
8480                 var moved = false;
8481
8482                 // first validate right/bottom
8483                 if((x + w) > vr){
8484                     x = vr - w;
8485                     moved = true;
8486                 }
8487                 if((y + h) > vb){
8488                     y = vb - h;
8489                     moved = true;
8490                 }
8491                 // then make sure top/left isn't negative
8492                 if(x < vx){
8493                     x = vx;
8494                     moved = true;
8495                 }
8496                 if(y < vy){
8497                     y = vy;
8498                     moved = true;
8499                 }
8500                 return moved ? [x, y] : false;
8501             };
8502         }(),
8503
8504         // private
8505         adjustForConstraints : function(xy, parent, offsets){
8506             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8507         },
8508
8509         /**
8510          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8511          * document it aligns it to the viewport.
8512          * The position parameter is optional, and can be specified in any one of the following formats:
8513          * <ul>
8514          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8515          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8516          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8517          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8518          *   <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
8519          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8520          * </ul>
8521          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8522          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8523          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8524          * that specified in order to enforce the viewport constraints.
8525          * Following are all of the supported anchor positions:
8526     <pre>
8527     Value  Description
8528     -----  -----------------------------
8529     tl     The top left corner (default)
8530     t      The center of the top edge
8531     tr     The top right corner
8532     l      The center of the left edge
8533     c      In the center of the element
8534     r      The center of the right edge
8535     bl     The bottom left corner
8536     b      The center of the bottom edge
8537     br     The bottom right corner
8538     </pre>
8539     Example Usage:
8540     <pre><code>
8541     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8542     el.alignTo("other-el");
8543
8544     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8545     el.alignTo("other-el", "tr?");
8546
8547     // align the bottom right corner of el with the center left edge of other-el
8548     el.alignTo("other-el", "br-l?");
8549
8550     // align the center of el with the bottom left corner of other-el and
8551     // adjust the x position by -6 pixels (and the y position by 0)
8552     el.alignTo("other-el", "c-bl", [-6, 0]);
8553     </code></pre>
8554          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8555          * @param {String} position The position to align to.
8556          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8557          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8558          * @return {Roo.Element} this
8559          */
8560         alignTo : function(element, position, offsets, animate){
8561             var xy = this.getAlignToXY(element, position, offsets);
8562             this.setXY(xy, this.preanim(arguments, 3));
8563             return this;
8564         },
8565
8566         /**
8567          * Anchors an element to another element and realigns it when the window is resized.
8568          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8569          * @param {String} position The position to align to.
8570          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8571          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8572          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8573          * is a number, it is used as the buffer delay (defaults to 50ms).
8574          * @param {Function} callback The function to call after the animation finishes
8575          * @return {Roo.Element} this
8576          */
8577         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8578             var action = function(){
8579                 this.alignTo(el, alignment, offsets, animate);
8580                 Roo.callback(callback, this);
8581             };
8582             Roo.EventManager.onWindowResize(action, this);
8583             var tm = typeof monitorScroll;
8584             if(tm != 'undefined'){
8585                 Roo.EventManager.on(window, 'scroll', action, this,
8586                     {buffer: tm == 'number' ? monitorScroll : 50});
8587             }
8588             action.call(this); // align immediately
8589             return this;
8590         },
8591         /**
8592          * Clears any opacity settings from this element. Required in some cases for IE.
8593          * @return {Roo.Element} this
8594          */
8595         clearOpacity : function(){
8596             if (window.ActiveXObject) {
8597                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8598                     this.dom.style.filter = "";
8599                 }
8600             } else {
8601                 this.dom.style.opacity = "";
8602                 this.dom.style["-moz-opacity"] = "";
8603                 this.dom.style["-khtml-opacity"] = "";
8604             }
8605             return this;
8606         },
8607
8608         /**
8609          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8610          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8611          * @return {Roo.Element} this
8612          */
8613         hide : function(animate){
8614             this.setVisible(false, this.preanim(arguments, 0));
8615             return this;
8616         },
8617
8618         /**
8619         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8620         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8621          * @return {Roo.Element} this
8622          */
8623         show : function(animate){
8624             this.setVisible(true, this.preanim(arguments, 0));
8625             return this;
8626         },
8627
8628         /**
8629          * @private Test if size has a unit, otherwise appends the default
8630          */
8631         addUnits : function(size){
8632             return Roo.Element.addUnits(size, this.defaultUnit);
8633         },
8634
8635         /**
8636          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8637          * @return {Roo.Element} this
8638          */
8639         beginMeasure : function(){
8640             var el = this.dom;
8641             if(el.offsetWidth || el.offsetHeight){
8642                 return this; // offsets work already
8643             }
8644             var changed = [];
8645             var p = this.dom, b = document.body; // start with this element
8646             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8647                 var pe = Roo.get(p);
8648                 if(pe.getStyle('display') == 'none'){
8649                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8650                     p.style.visibility = "hidden";
8651                     p.style.display = "block";
8652                 }
8653                 p = p.parentNode;
8654             }
8655             this._measureChanged = changed;
8656             return this;
8657
8658         },
8659
8660         /**
8661          * Restores displays to before beginMeasure was called
8662          * @return {Roo.Element} this
8663          */
8664         endMeasure : function(){
8665             var changed = this._measureChanged;
8666             if(changed){
8667                 for(var i = 0, len = changed.length; i < len; i++) {
8668                     var r = changed[i];
8669                     r.el.style.visibility = r.visibility;
8670                     r.el.style.display = "none";
8671                 }
8672                 this._measureChanged = null;
8673             }
8674             return this;
8675         },
8676
8677         /**
8678         * Update the innerHTML of this element, optionally searching for and processing scripts
8679         * @param {String} html The new HTML
8680         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8681         * @param {Function} callback For async script loading you can be noticed when the update completes
8682         * @return {Roo.Element} this
8683          */
8684         update : function(html, loadScripts, callback){
8685             if(typeof html == "undefined"){
8686                 html = "";
8687             }
8688             if(loadScripts !== true){
8689                 this.dom.innerHTML = html;
8690                 if(typeof callback == "function"){
8691                     callback();
8692                 }
8693                 return this;
8694             }
8695             var id = Roo.id();
8696             var dom = this.dom;
8697
8698             html += '<span id="' + id + '"></span>';
8699
8700             E.onAvailable(id, function(){
8701                 var hd = document.getElementsByTagName("head")[0];
8702                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8703                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8704                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8705
8706                 var match;
8707                 while(match = re.exec(html)){
8708                     var attrs = match[1];
8709                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8710                     if(srcMatch && srcMatch[2]){
8711                        var s = document.createElement("script");
8712                        s.src = srcMatch[2];
8713                        var typeMatch = attrs.match(typeRe);
8714                        if(typeMatch && typeMatch[2]){
8715                            s.type = typeMatch[2];
8716                        }
8717                        hd.appendChild(s);
8718                     }else if(match[2] && match[2].length > 0){
8719                         if(window.execScript) {
8720                            window.execScript(match[2]);
8721                         } else {
8722                             /**
8723                              * eval:var:id
8724                              * eval:var:dom
8725                              * eval:var:html
8726                              * 
8727                              */
8728                            window.eval(match[2]);
8729                         }
8730                     }
8731                 }
8732                 var el = document.getElementById(id);
8733                 if(el){el.parentNode.removeChild(el);}
8734                 if(typeof callback == "function"){
8735                     callback();
8736                 }
8737             });
8738             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8739             return this;
8740         },
8741
8742         /**
8743          * Direct access to the UpdateManager update() method (takes the same parameters).
8744          * @param {String/Function} url The url for this request or a function to call to get the url
8745          * @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}
8746          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8747          * @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.
8748          * @return {Roo.Element} this
8749          */
8750         load : function(){
8751             var um = this.getUpdateManager();
8752             um.update.apply(um, arguments);
8753             return this;
8754         },
8755
8756         /**
8757         * Gets this element's UpdateManager
8758         * @return {Roo.UpdateManager} The UpdateManager
8759         */
8760         getUpdateManager : function(){
8761             if(!this.updateManager){
8762                 this.updateManager = new Roo.UpdateManager(this);
8763             }
8764             return this.updateManager;
8765         },
8766
8767         /**
8768          * Disables text selection for this element (normalized across browsers)
8769          * @return {Roo.Element} this
8770          */
8771         unselectable : function(){
8772             this.dom.unselectable = "on";
8773             this.swallowEvent("selectstart", true);
8774             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8775             this.addClass("x-unselectable");
8776             return this;
8777         },
8778
8779         /**
8780         * Calculates the x, y to center this element on the screen
8781         * @return {Array} The x, y values [x, y]
8782         */
8783         getCenterXY : function(){
8784             return this.getAlignToXY(document, 'c-c');
8785         },
8786
8787         /**
8788         * Centers the Element in either the viewport, or another Element.
8789         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8790         */
8791         center : function(centerIn){
8792             this.alignTo(centerIn || document, 'c-c');
8793             return this;
8794         },
8795
8796         /**
8797          * Tests various css rules/browsers to determine if this element uses a border box
8798          * @return {Boolean}
8799          */
8800         isBorderBox : function(){
8801             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8802         },
8803
8804         /**
8805          * Return a box {x, y, width, height} that can be used to set another elements
8806          * size/location to match this element.
8807          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8808          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8809          * @return {Object} box An object in the format {x, y, width, height}
8810          */
8811         getBox : function(contentBox, local){
8812             var xy;
8813             if(!local){
8814                 xy = this.getXY();
8815             }else{
8816                 var left = parseInt(this.getStyle("left"), 10) || 0;
8817                 var top = parseInt(this.getStyle("top"), 10) || 0;
8818                 xy = [left, top];
8819             }
8820             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8821             if(!contentBox){
8822                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8823             }else{
8824                 var l = this.getBorderWidth("l")+this.getPadding("l");
8825                 var r = this.getBorderWidth("r")+this.getPadding("r");
8826                 var t = this.getBorderWidth("t")+this.getPadding("t");
8827                 var b = this.getBorderWidth("b")+this.getPadding("b");
8828                 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)};
8829             }
8830             bx.right = bx.x + bx.width;
8831             bx.bottom = bx.y + bx.height;
8832             return bx;
8833         },
8834
8835         /**
8836          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8837          for more information about the sides.
8838          * @param {String} sides
8839          * @return {Number}
8840          */
8841         getFrameWidth : function(sides, onlyContentBox){
8842             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8843         },
8844
8845         /**
8846          * 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.
8847          * @param {Object} box The box to fill {x, y, width, height}
8848          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8849          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8850          * @return {Roo.Element} this
8851          */
8852         setBox : function(box, adjust, animate){
8853             var w = box.width, h = box.height;
8854             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8855                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8856                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8857             }
8858             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8859             return this;
8860         },
8861
8862         /**
8863          * Forces the browser to repaint this element
8864          * @return {Roo.Element} this
8865          */
8866          repaint : function(){
8867             var dom = this.dom;
8868             this.addClass("x-repaint");
8869             setTimeout(function(){
8870                 Roo.get(dom).removeClass("x-repaint");
8871             }, 1);
8872             return this;
8873         },
8874
8875         /**
8876          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8877          * then it returns the calculated width of the sides (see getPadding)
8878          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8879          * @return {Object/Number}
8880          */
8881         getMargins : function(side){
8882             if(!side){
8883                 return {
8884                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8885                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8886                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8887                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8888                 };
8889             }else{
8890                 return this.addStyles(side, El.margins);
8891              }
8892         },
8893
8894         // private
8895         addStyles : function(sides, styles){
8896             var val = 0, v, w;
8897             for(var i = 0, len = sides.length; i < len; i++){
8898                 v = this.getStyle(styles[sides.charAt(i)]);
8899                 if(v){
8900                      w = parseInt(v, 10);
8901                      if(w){ val += w; }
8902                 }
8903             }
8904             return val;
8905         },
8906
8907         /**
8908          * Creates a proxy element of this element
8909          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8910          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8911          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8912          * @return {Roo.Element} The new proxy element
8913          */
8914         createProxy : function(config, renderTo, matchBox){
8915             if(renderTo){
8916                 renderTo = Roo.getDom(renderTo);
8917             }else{
8918                 renderTo = document.body;
8919             }
8920             config = typeof config == "object" ?
8921                 config : {tag : "div", cls: config};
8922             var proxy = Roo.DomHelper.append(renderTo, config, true);
8923             if(matchBox){
8924                proxy.setBox(this.getBox());
8925             }
8926             return proxy;
8927         },
8928
8929         /**
8930          * Puts a mask over this element to disable user interaction. Requires core.css.
8931          * This method can only be applied to elements which accept child nodes.
8932          * @param {String} msg (optional) A message to display in the mask
8933          * @param {String} msgCls (optional) A css class to apply to the msg element
8934          * @return {Element} The mask  element
8935          */
8936         mask : function(msg, msgCls)
8937         {
8938             if(this.getStyle("position") == "static"){
8939                 this.setStyle("position", "relative");
8940             }
8941             if(!this._mask){
8942                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8943             }
8944             this.addClass("x-masked");
8945             this._mask.setDisplayed(true);
8946             
8947             // we wander
8948             var z = 0;
8949             var dom = this.dom
8950             while (dom && dom.style) {
8951                 if (!isNaN(parseInt(dom.style.zIndex))) {
8952                     z = Math.max(z, parseInt(dom.style.zIndex));
8953                 }
8954                 dom = dom.parentNode;
8955             }
8956             // if we are masking the body - then it hides everything..
8957             if (this.dom == document.body) {
8958                 z = 1000000;
8959                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8960                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8961             }
8962            
8963             if(typeof msg == 'string'){
8964                 if(!this._maskMsg){
8965                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8966                 }
8967                 var mm = this._maskMsg;
8968                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8969                 mm.dom.firstChild.innerHTML = msg;
8970                 mm.setDisplayed(true);
8971                 mm.center(this);
8972                 mm.setStyle('z-index', z + 102);
8973             }
8974             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8975                 this._mask.setHeight(this.getHeight());
8976             }
8977             this._mask.setStyle('z-index', z + 100);
8978             
8979             return this._mask;
8980         },
8981
8982         /**
8983          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8984          * it is cached for reuse.
8985          */
8986         unmask : function(removeEl){
8987             if(this._mask){
8988                 if(removeEl === true){
8989                     this._mask.remove();
8990                     delete this._mask;
8991                     if(this._maskMsg){
8992                         this._maskMsg.remove();
8993                         delete this._maskMsg;
8994                     }
8995                 }else{
8996                     this._mask.setDisplayed(false);
8997                     if(this._maskMsg){
8998                         this._maskMsg.setDisplayed(false);
8999                     }
9000                 }
9001             }
9002             this.removeClass("x-masked");
9003         },
9004
9005         /**
9006          * Returns true if this element is masked
9007          * @return {Boolean}
9008          */
9009         isMasked : function(){
9010             return this._mask && this._mask.isVisible();
9011         },
9012
9013         /**
9014          * Creates an iframe shim for this element to keep selects and other windowed objects from
9015          * showing through.
9016          * @return {Roo.Element} The new shim element
9017          */
9018         createShim : function(){
9019             var el = document.createElement('iframe');
9020             el.frameBorder = 'no';
9021             el.className = 'roo-shim';
9022             if(Roo.isIE && Roo.isSecure){
9023                 el.src = Roo.SSL_SECURE_URL;
9024             }
9025             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9026             shim.autoBoxAdjust = false;
9027             return shim;
9028         },
9029
9030         /**
9031          * Removes this element from the DOM and deletes it from the cache
9032          */
9033         remove : function(){
9034             if(this.dom.parentNode){
9035                 this.dom.parentNode.removeChild(this.dom);
9036             }
9037             delete El.cache[this.dom.id];
9038         },
9039
9040         /**
9041          * Sets up event handlers to add and remove a css class when the mouse is over this element
9042          * @param {String} className
9043          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9044          * mouseout events for children elements
9045          * @return {Roo.Element} this
9046          */
9047         addClassOnOver : function(className, preventFlicker){
9048             this.on("mouseover", function(){
9049                 Roo.fly(this, '_internal').addClass(className);
9050             }, this.dom);
9051             var removeFn = function(e){
9052                 if(preventFlicker !== true || !e.within(this, true)){
9053                     Roo.fly(this, '_internal').removeClass(className);
9054                 }
9055             };
9056             this.on("mouseout", removeFn, this.dom);
9057             return this;
9058         },
9059
9060         /**
9061          * Sets up event handlers to add and remove a css class when this element has the focus
9062          * @param {String} className
9063          * @return {Roo.Element} this
9064          */
9065         addClassOnFocus : function(className){
9066             this.on("focus", function(){
9067                 Roo.fly(this, '_internal').addClass(className);
9068             }, this.dom);
9069             this.on("blur", function(){
9070                 Roo.fly(this, '_internal').removeClass(className);
9071             }, this.dom);
9072             return this;
9073         },
9074         /**
9075          * 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)
9076          * @param {String} className
9077          * @return {Roo.Element} this
9078          */
9079         addClassOnClick : function(className){
9080             var dom = this.dom;
9081             this.on("mousedown", function(){
9082                 Roo.fly(dom, '_internal').addClass(className);
9083                 var d = Roo.get(document);
9084                 var fn = function(){
9085                     Roo.fly(dom, '_internal').removeClass(className);
9086                     d.removeListener("mouseup", fn);
9087                 };
9088                 d.on("mouseup", fn);
9089             });
9090             return this;
9091         },
9092
9093         /**
9094          * Stops the specified event from bubbling and optionally prevents the default action
9095          * @param {String} eventName
9096          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9097          * @return {Roo.Element} this
9098          */
9099         swallowEvent : function(eventName, preventDefault){
9100             var fn = function(e){
9101                 e.stopPropagation();
9102                 if(preventDefault){
9103                     e.preventDefault();
9104                 }
9105             };
9106             if(eventName instanceof Array){
9107                 for(var i = 0, len = eventName.length; i < len; i++){
9108                      this.on(eventName[i], fn);
9109                 }
9110                 return this;
9111             }
9112             this.on(eventName, fn);
9113             return this;
9114         },
9115
9116         /**
9117          * @private
9118          */
9119       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9120
9121         /**
9122          * Sizes this element to its parent element's dimensions performing
9123          * neccessary box adjustments.
9124          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9125          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9126          * @return {Roo.Element} this
9127          */
9128         fitToParent : function(monitorResize, targetParent) {
9129           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9130           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9131           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9132             return;
9133           }
9134           var p = Roo.get(targetParent || this.dom.parentNode);
9135           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9136           if (monitorResize === true) {
9137             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9138             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9139           }
9140           return this;
9141         },
9142
9143         /**
9144          * Gets the next sibling, skipping text nodes
9145          * @return {HTMLElement} The next sibling or null
9146          */
9147         getNextSibling : function(){
9148             var n = this.dom.nextSibling;
9149             while(n && n.nodeType != 1){
9150                 n = n.nextSibling;
9151             }
9152             return n;
9153         },
9154
9155         /**
9156          * Gets the previous sibling, skipping text nodes
9157          * @return {HTMLElement} The previous sibling or null
9158          */
9159         getPrevSibling : function(){
9160             var n = this.dom.previousSibling;
9161             while(n && n.nodeType != 1){
9162                 n = n.previousSibling;
9163             }
9164             return n;
9165         },
9166
9167
9168         /**
9169          * Appends the passed element(s) to this element
9170          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9171          * @return {Roo.Element} this
9172          */
9173         appendChild: function(el){
9174             el = Roo.get(el);
9175             el.appendTo(this);
9176             return this;
9177         },
9178
9179         /**
9180          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9181          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9182          * automatically generated with the specified attributes.
9183          * @param {HTMLElement} insertBefore (optional) a child element of this element
9184          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9185          * @return {Roo.Element} The new child element
9186          */
9187         createChild: function(config, insertBefore, returnDom){
9188             config = config || {tag:'div'};
9189             if(insertBefore){
9190                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9191             }
9192             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9193         },
9194
9195         /**
9196          * Appends this element to the passed element
9197          * @param {String/HTMLElement/Element} el The new parent element
9198          * @return {Roo.Element} this
9199          */
9200         appendTo: function(el){
9201             el = Roo.getDom(el);
9202             el.appendChild(this.dom);
9203             return this;
9204         },
9205
9206         /**
9207          * Inserts this element before the passed element in the DOM
9208          * @param {String/HTMLElement/Element} el The element to insert before
9209          * @return {Roo.Element} this
9210          */
9211         insertBefore: function(el){
9212             el = Roo.getDom(el);
9213             el.parentNode.insertBefore(this.dom, el);
9214             return this;
9215         },
9216
9217         /**
9218          * Inserts this element after the passed element in the DOM
9219          * @param {String/HTMLElement/Element} el The element to insert after
9220          * @return {Roo.Element} this
9221          */
9222         insertAfter: function(el){
9223             el = Roo.getDom(el);
9224             el.parentNode.insertBefore(this.dom, el.nextSibling);
9225             return this;
9226         },
9227
9228         /**
9229          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9230          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9231          * @return {Roo.Element} The new child
9232          */
9233         insertFirst: function(el, returnDom){
9234             el = el || {};
9235             if(typeof el == 'object' && !el.nodeType){ // dh config
9236                 return this.createChild(el, this.dom.firstChild, returnDom);
9237             }else{
9238                 el = Roo.getDom(el);
9239                 this.dom.insertBefore(el, this.dom.firstChild);
9240                 return !returnDom ? Roo.get(el) : el;
9241             }
9242         },
9243
9244         /**
9245          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9246          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9247          * @param {String} where (optional) 'before' or 'after' defaults to before
9248          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9249          * @return {Roo.Element} the inserted Element
9250          */
9251         insertSibling: function(el, where, returnDom){
9252             where = where ? where.toLowerCase() : 'before';
9253             el = el || {};
9254             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9255
9256             if(typeof el == 'object' && !el.nodeType){ // dh config
9257                 if(where == 'after' && !this.dom.nextSibling){
9258                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9259                 }else{
9260                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9261                 }
9262
9263             }else{
9264                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9265                             where == 'before' ? this.dom : this.dom.nextSibling);
9266                 if(!returnDom){
9267                     rt = Roo.get(rt);
9268                 }
9269             }
9270             return rt;
9271         },
9272
9273         /**
9274          * Creates and wraps this element with another element
9275          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9276          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9277          * @return {HTMLElement/Element} The newly created wrapper element
9278          */
9279         wrap: function(config, returnDom){
9280             if(!config){
9281                 config = {tag: "div"};
9282             }
9283             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9284             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9285             return newEl;
9286         },
9287
9288         /**
9289          * Replaces the passed element with this element
9290          * @param {String/HTMLElement/Element} el The element to replace
9291          * @return {Roo.Element} this
9292          */
9293         replace: function(el){
9294             el = Roo.get(el);
9295             this.insertBefore(el);
9296             el.remove();
9297             return this;
9298         },
9299
9300         /**
9301          * Inserts an html fragment into this element
9302          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9303          * @param {String} html The HTML fragment
9304          * @param {Boolean} returnEl True to return an Roo.Element
9305          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9306          */
9307         insertHtml : function(where, html, returnEl){
9308             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9309             return returnEl ? Roo.get(el) : el;
9310         },
9311
9312         /**
9313          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9314          * @param {Object} o The object with the attributes
9315          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9316          * @return {Roo.Element} this
9317          */
9318         set : function(o, useSet){
9319             var el = this.dom;
9320             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9321             for(var attr in o){
9322                 if(attr == "style" || typeof o[attr] == "function") continue;
9323                 if(attr=="cls"){
9324                     el.className = o["cls"];
9325                 }else{
9326                     if(useSet) el.setAttribute(attr, o[attr]);
9327                     else el[attr] = o[attr];
9328                 }
9329             }
9330             if(o.style){
9331                 Roo.DomHelper.applyStyles(el, o.style);
9332             }
9333             return this;
9334         },
9335
9336         /**
9337          * Convenience method for constructing a KeyMap
9338          * @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:
9339          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9340          * @param {Function} fn The function to call
9341          * @param {Object} scope (optional) The scope of the function
9342          * @return {Roo.KeyMap} The KeyMap created
9343          */
9344         addKeyListener : function(key, fn, scope){
9345             var config;
9346             if(typeof key != "object" || key instanceof Array){
9347                 config = {
9348                     key: key,
9349                     fn: fn,
9350                     scope: scope
9351                 };
9352             }else{
9353                 config = {
9354                     key : key.key,
9355                     shift : key.shift,
9356                     ctrl : key.ctrl,
9357                     alt : key.alt,
9358                     fn: fn,
9359                     scope: scope
9360                 };
9361             }
9362             return new Roo.KeyMap(this, config);
9363         },
9364
9365         /**
9366          * Creates a KeyMap for this element
9367          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9368          * @return {Roo.KeyMap} The KeyMap created
9369          */
9370         addKeyMap : function(config){
9371             return new Roo.KeyMap(this, config);
9372         },
9373
9374         /**
9375          * Returns true if this element is scrollable.
9376          * @return {Boolean}
9377          */
9378          isScrollable : function(){
9379             var dom = this.dom;
9380             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9381         },
9382
9383         /**
9384          * 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().
9385          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9386          * @param {Number} value The new scroll value
9387          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9388          * @return {Element} this
9389          */
9390
9391         scrollTo : function(side, value, animate){
9392             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9393             if(!animate || !A){
9394                 this.dom[prop] = value;
9395             }else{
9396                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9397                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9398             }
9399             return this;
9400         },
9401
9402         /**
9403          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9404          * within this element's scrollable range.
9405          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9406          * @param {Number} distance How far to scroll the element in pixels
9407          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9408          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9409          * was scrolled as far as it could go.
9410          */
9411          scroll : function(direction, distance, animate){
9412              if(!this.isScrollable()){
9413                  return;
9414              }
9415              var el = this.dom;
9416              var l = el.scrollLeft, t = el.scrollTop;
9417              var w = el.scrollWidth, h = el.scrollHeight;
9418              var cw = el.clientWidth, ch = el.clientHeight;
9419              direction = direction.toLowerCase();
9420              var scrolled = false;
9421              var a = this.preanim(arguments, 2);
9422              switch(direction){
9423                  case "l":
9424                  case "left":
9425                      if(w - l > cw){
9426                          var v = Math.min(l + distance, w-cw);
9427                          this.scrollTo("left", v, a);
9428                          scrolled = true;
9429                      }
9430                      break;
9431                 case "r":
9432                 case "right":
9433                      if(l > 0){
9434                          var v = Math.max(l - distance, 0);
9435                          this.scrollTo("left", v, a);
9436                          scrolled = true;
9437                      }
9438                      break;
9439                 case "t":
9440                 case "top":
9441                 case "up":
9442                      if(t > 0){
9443                          var v = Math.max(t - distance, 0);
9444                          this.scrollTo("top", v, a);
9445                          scrolled = true;
9446                      }
9447                      break;
9448                 case "b":
9449                 case "bottom":
9450                 case "down":
9451                      if(h - t > ch){
9452                          var v = Math.min(t + distance, h-ch);
9453                          this.scrollTo("top", v, a);
9454                          scrolled = true;
9455                      }
9456                      break;
9457              }
9458              return scrolled;
9459         },
9460
9461         /**
9462          * Translates the passed page coordinates into left/top css values for this element
9463          * @param {Number/Array} x The page x or an array containing [x, y]
9464          * @param {Number} y The page y
9465          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9466          */
9467         translatePoints : function(x, y){
9468             if(typeof x == 'object' || x instanceof Array){
9469                 y = x[1]; x = x[0];
9470             }
9471             var p = this.getStyle('position');
9472             var o = this.getXY();
9473
9474             var l = parseInt(this.getStyle('left'), 10);
9475             var t = parseInt(this.getStyle('top'), 10);
9476
9477             if(isNaN(l)){
9478                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9479             }
9480             if(isNaN(t)){
9481                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9482             }
9483
9484             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9485         },
9486
9487         /**
9488          * Returns the current scroll position of the element.
9489          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9490          */
9491         getScroll : function(){
9492             var d = this.dom, doc = document;
9493             if(d == doc || d == doc.body){
9494                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9495                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9496                 return {left: l, top: t};
9497             }else{
9498                 return {left: d.scrollLeft, top: d.scrollTop};
9499             }
9500         },
9501
9502         /**
9503          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9504          * are convert to standard 6 digit hex color.
9505          * @param {String} attr The css attribute
9506          * @param {String} defaultValue The default value to use when a valid color isn't found
9507          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9508          * YUI color anims.
9509          */
9510         getColor : function(attr, defaultValue, prefix){
9511             var v = this.getStyle(attr);
9512             if(!v || v == "transparent" || v == "inherit") {
9513                 return defaultValue;
9514             }
9515             var color = typeof prefix == "undefined" ? "#" : prefix;
9516             if(v.substr(0, 4) == "rgb("){
9517                 var rvs = v.slice(4, v.length -1).split(",");
9518                 for(var i = 0; i < 3; i++){
9519                     var h = parseInt(rvs[i]).toString(16);
9520                     if(h < 16){
9521                         h = "0" + h;
9522                     }
9523                     color += h;
9524                 }
9525             } else {
9526                 if(v.substr(0, 1) == "#"){
9527                     if(v.length == 4) {
9528                         for(var i = 1; i < 4; i++){
9529                             var c = v.charAt(i);
9530                             color +=  c + c;
9531                         }
9532                     }else if(v.length == 7){
9533                         color += v.substr(1);
9534                     }
9535                 }
9536             }
9537             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9538         },
9539
9540         /**
9541          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9542          * gradient background, rounded corners and a 4-way shadow.
9543          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9544          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9545          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9546          * @return {Roo.Element} this
9547          */
9548         boxWrap : function(cls){
9549             cls = cls || 'x-box';
9550             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9551             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9552             return el;
9553         },
9554
9555         /**
9556          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9557          * @param {String} namespace The namespace in which to look for the attribute
9558          * @param {String} name The attribute name
9559          * @return {String} The attribute value
9560          */
9561         getAttributeNS : Roo.isIE ? function(ns, name){
9562             var d = this.dom;
9563             var type = typeof d[ns+":"+name];
9564             if(type != 'undefined' && type != 'unknown'){
9565                 return d[ns+":"+name];
9566             }
9567             return d[name];
9568         } : function(ns, name){
9569             var d = this.dom;
9570             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9571         },
9572         
9573         
9574         /**
9575          * Sets or Returns the value the dom attribute value
9576          * @param {String} name The attribute name
9577          * @param {String} value (optional) The value to set the attribute to
9578          * @return {String} The attribute value
9579          */
9580         attr : function(name){
9581             if (arguments.length > 1) {
9582                 this.dom.setAttribute(name, arguments[1]);
9583                 return arguments[1];
9584             }
9585             if (!this.dom.hasAttribute(name)) {
9586                 return undefined;
9587             }
9588             return this.dom.getAttribute(name);
9589         }
9590         
9591         
9592         
9593     };
9594
9595     var ep = El.prototype;
9596
9597     /**
9598      * Appends an event handler (Shorthand for addListener)
9599      * @param {String}   eventName     The type of event to append
9600      * @param {Function} fn        The method the event invokes
9601      * @param {Object} scope       (optional) The scope (this object) of the fn
9602      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9603      * @method
9604      */
9605     ep.on = ep.addListener;
9606         // backwards compat
9607     ep.mon = ep.addListener;
9608
9609     /**
9610      * Removes an event handler from this element (shorthand for removeListener)
9611      * @param {String} eventName the type of event to remove
9612      * @param {Function} fn the method the event invokes
9613      * @return {Roo.Element} this
9614      * @method
9615      */
9616     ep.un = ep.removeListener;
9617
9618     /**
9619      * true to automatically adjust width and height settings for box-model issues (default to true)
9620      */
9621     ep.autoBoxAdjust = true;
9622
9623     // private
9624     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9625
9626     // private
9627     El.addUnits = function(v, defaultUnit){
9628         if(v === "" || v == "auto"){
9629             return v;
9630         }
9631         if(v === undefined){
9632             return '';
9633         }
9634         if(typeof v == "number" || !El.unitPattern.test(v)){
9635             return v + (defaultUnit || 'px');
9636         }
9637         return v;
9638     };
9639
9640     // special markup used throughout Roo when box wrapping elements
9641     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>';
9642     /**
9643      * Visibility mode constant - Use visibility to hide element
9644      * @static
9645      * @type Number
9646      */
9647     El.VISIBILITY = 1;
9648     /**
9649      * Visibility mode constant - Use display to hide element
9650      * @static
9651      * @type Number
9652      */
9653     El.DISPLAY = 2;
9654
9655     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9656     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9657     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9658
9659
9660
9661     /**
9662      * @private
9663      */
9664     El.cache = {};
9665
9666     var docEl;
9667
9668     /**
9669      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9670      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9671      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9672      * @return {Element} The Element object
9673      * @static
9674      */
9675     El.get = function(el){
9676         var ex, elm, id;
9677         if(!el){ return null; }
9678         if(typeof el == "string"){ // element id
9679             if(!(elm = document.getElementById(el))){
9680                 return null;
9681             }
9682             if(ex = El.cache[el]){
9683                 ex.dom = elm;
9684             }else{
9685                 ex = El.cache[el] = new El(elm);
9686             }
9687             return ex;
9688         }else if(el.tagName){ // dom element
9689             if(!(id = el.id)){
9690                 id = Roo.id(el);
9691             }
9692             if(ex = El.cache[id]){
9693                 ex.dom = el;
9694             }else{
9695                 ex = El.cache[id] = new El(el);
9696             }
9697             return ex;
9698         }else if(el instanceof El){
9699             if(el != docEl){
9700                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9701                                                               // catch case where it hasn't been appended
9702                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9703             }
9704             return el;
9705         }else if(el.isComposite){
9706             return el;
9707         }else if(el instanceof Array){
9708             return El.select(el);
9709         }else if(el == document){
9710             // create a bogus element object representing the document object
9711             if(!docEl){
9712                 var f = function(){};
9713                 f.prototype = El.prototype;
9714                 docEl = new f();
9715                 docEl.dom = document;
9716             }
9717             return docEl;
9718         }
9719         return null;
9720     };
9721
9722     // private
9723     El.uncache = function(el){
9724         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9725             if(a[i]){
9726                 delete El.cache[a[i].id || a[i]];
9727             }
9728         }
9729     };
9730
9731     // private
9732     // Garbage collection - uncache elements/purge listeners on orphaned elements
9733     // so we don't hold a reference and cause the browser to retain them
9734     El.garbageCollect = function(){
9735         if(!Roo.enableGarbageCollector){
9736             clearInterval(El.collectorThread);
9737             return;
9738         }
9739         for(var eid in El.cache){
9740             var el = El.cache[eid], d = el.dom;
9741             // -------------------------------------------------------
9742             // Determining what is garbage:
9743             // -------------------------------------------------------
9744             // !d
9745             // dom node is null, definitely garbage
9746             // -------------------------------------------------------
9747             // !d.parentNode
9748             // no parentNode == direct orphan, definitely garbage
9749             // -------------------------------------------------------
9750             // !d.offsetParent && !document.getElementById(eid)
9751             // display none elements have no offsetParent so we will
9752             // also try to look it up by it's id. However, check
9753             // offsetParent first so we don't do unneeded lookups.
9754             // This enables collection of elements that are not orphans
9755             // directly, but somewhere up the line they have an orphan
9756             // parent.
9757             // -------------------------------------------------------
9758             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9759                 delete El.cache[eid];
9760                 if(d && Roo.enableListenerCollection){
9761                     E.purgeElement(d);
9762                 }
9763             }
9764         }
9765     }
9766     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9767
9768
9769     // dom is optional
9770     El.Flyweight = function(dom){
9771         this.dom = dom;
9772     };
9773     El.Flyweight.prototype = El.prototype;
9774
9775     El._flyweights = {};
9776     /**
9777      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9778      * the dom node can be overwritten by other code.
9779      * @param {String/HTMLElement} el The dom node or id
9780      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9781      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9782      * @static
9783      * @return {Element} The shared Element object
9784      */
9785     El.fly = function(el, named){
9786         named = named || '_global';
9787         el = Roo.getDom(el);
9788         if(!el){
9789             return null;
9790         }
9791         if(!El._flyweights[named]){
9792             El._flyweights[named] = new El.Flyweight();
9793         }
9794         El._flyweights[named].dom = el;
9795         return El._flyweights[named];
9796     };
9797
9798     /**
9799      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9800      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9801      * Shorthand of {@link Roo.Element#get}
9802      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9803      * @return {Element} The Element object
9804      * @member Roo
9805      * @method get
9806      */
9807     Roo.get = El.get;
9808     /**
9809      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9810      * the dom node can be overwritten by other code.
9811      * Shorthand of {@link Roo.Element#fly}
9812      * @param {String/HTMLElement} el The dom node or id
9813      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9814      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9815      * @static
9816      * @return {Element} The shared Element object
9817      * @member Roo
9818      * @method fly
9819      */
9820     Roo.fly = El.fly;
9821
9822     // speedy lookup for elements never to box adjust
9823     var noBoxAdjust = Roo.isStrict ? {
9824         select:1
9825     } : {
9826         input:1, select:1, textarea:1
9827     };
9828     if(Roo.isIE || Roo.isGecko){
9829         noBoxAdjust['button'] = 1;
9830     }
9831
9832
9833     Roo.EventManager.on(window, 'unload', function(){
9834         delete El.cache;
9835         delete El._flyweights;
9836     });
9837 })();
9838
9839
9840
9841
9842 if(Roo.DomQuery){
9843     Roo.Element.selectorFunction = Roo.DomQuery.select;
9844 }
9845
9846 Roo.Element.select = function(selector, unique, root){
9847     var els;
9848     if(typeof selector == "string"){
9849         els = Roo.Element.selectorFunction(selector, root);
9850     }else if(selector.length !== undefined){
9851         els = selector;
9852     }else{
9853         throw "Invalid selector";
9854     }
9855     if(unique === true){
9856         return new Roo.CompositeElement(els);
9857     }else{
9858         return new Roo.CompositeElementLite(els);
9859     }
9860 };
9861 /**
9862  * Selects elements based on the passed CSS selector to enable working on them as 1.
9863  * @param {String/Array} selector The CSS selector or an array of elements
9864  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9865  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9866  * @return {CompositeElementLite/CompositeElement}
9867  * @member Roo
9868  * @method select
9869  */
9870 Roo.select = Roo.Element.select;
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883
9884
9885 /*
9886  * Based on:
9887  * Ext JS Library 1.1.1
9888  * Copyright(c) 2006-2007, Ext JS, LLC.
9889  *
9890  * Originally Released Under LGPL - original licence link has changed is not relivant.
9891  *
9892  * Fork - LGPL
9893  * <script type="text/javascript">
9894  */
9895
9896
9897
9898 //Notifies Element that fx methods are available
9899 Roo.enableFx = true;
9900
9901 /**
9902  * @class Roo.Fx
9903  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9904  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9905  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9906  * Element effects to work.</p><br/>
9907  *
9908  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9909  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9910  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9911  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9912  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9913  * expected results and should be done with care.</p><br/>
9914  *
9915  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9916  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9917 <pre>
9918 Value  Description
9919 -----  -----------------------------
9920 tl     The top left corner
9921 t      The center of the top edge
9922 tr     The top right corner
9923 l      The center of the left edge
9924 r      The center of the right edge
9925 bl     The bottom left corner
9926 b      The center of the bottom edge
9927 br     The bottom right corner
9928 </pre>
9929  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9930  * below are common options that can be passed to any Fx method.</b>
9931  * @cfg {Function} callback A function called when the effect is finished
9932  * @cfg {Object} scope The scope of the effect function
9933  * @cfg {String} easing A valid Easing value for the effect
9934  * @cfg {String} afterCls A css class to apply after the effect
9935  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9936  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9937  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9938  * effects that end with the element being visually hidden, ignored otherwise)
9939  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9940  * a function which returns such a specification that will be applied to the Element after the effect finishes
9941  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9942  * @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
9943  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9944  */
9945 Roo.Fx = {
9946         /**
9947          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9948          * origin for the slide effect.  This function automatically handles wrapping the element with
9949          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9950          * Usage:
9951          *<pre><code>
9952 // default: slide the element in from the top
9953 el.slideIn();
9954
9955 // custom: slide the element in from the right with a 2-second duration
9956 el.slideIn('r', { duration: 2 });
9957
9958 // common config options shown with default values
9959 el.slideIn('t', {
9960     easing: 'easeOut',
9961     duration: .5
9962 });
9963 </code></pre>
9964          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9965          * @param {Object} options (optional) Object literal with any of the Fx config options
9966          * @return {Roo.Element} The Element
9967          */
9968     slideIn : function(anchor, o){
9969         var el = this.getFxEl();
9970         o = o || {};
9971
9972         el.queueFx(o, function(){
9973
9974             anchor = anchor || "t";
9975
9976             // fix display to visibility
9977             this.fixDisplay();
9978
9979             // restore values after effect
9980             var r = this.getFxRestore();
9981             var b = this.getBox();
9982             // fixed size for slide
9983             this.setSize(b);
9984
9985             // wrap if needed
9986             var wrap = this.fxWrap(r.pos, o, "hidden");
9987
9988             var st = this.dom.style;
9989             st.visibility = "visible";
9990             st.position = "absolute";
9991
9992             // clear out temp styles after slide and unwrap
9993             var after = function(){
9994                 el.fxUnwrap(wrap, r.pos, o);
9995                 st.width = r.width;
9996                 st.height = r.height;
9997                 el.afterFx(o);
9998             };
9999             // time to calc the positions
10000             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10001
10002             switch(anchor.toLowerCase()){
10003                 case "t":
10004                     wrap.setSize(b.width, 0);
10005                     st.left = st.bottom = "0";
10006                     a = {height: bh};
10007                 break;
10008                 case "l":
10009                     wrap.setSize(0, b.height);
10010                     st.right = st.top = "0";
10011                     a = {width: bw};
10012                 break;
10013                 case "r":
10014                     wrap.setSize(0, b.height);
10015                     wrap.setX(b.right);
10016                     st.left = st.top = "0";
10017                     a = {width: bw, points: pt};
10018                 break;
10019                 case "b":
10020                     wrap.setSize(b.width, 0);
10021                     wrap.setY(b.bottom);
10022                     st.left = st.top = "0";
10023                     a = {height: bh, points: pt};
10024                 break;
10025                 case "tl":
10026                     wrap.setSize(0, 0);
10027                     st.right = st.bottom = "0";
10028                     a = {width: bw, height: bh};
10029                 break;
10030                 case "bl":
10031                     wrap.setSize(0, 0);
10032                     wrap.setY(b.y+b.height);
10033                     st.right = st.top = "0";
10034                     a = {width: bw, height: bh, points: pt};
10035                 break;
10036                 case "br":
10037                     wrap.setSize(0, 0);
10038                     wrap.setXY([b.right, b.bottom]);
10039                     st.left = st.top = "0";
10040                     a = {width: bw, height: bh, points: pt};
10041                 break;
10042                 case "tr":
10043                     wrap.setSize(0, 0);
10044                     wrap.setX(b.x+b.width);
10045                     st.left = st.bottom = "0";
10046                     a = {width: bw, height: bh, points: pt};
10047                 break;
10048             }
10049             this.dom.style.visibility = "visible";
10050             wrap.show();
10051
10052             arguments.callee.anim = wrap.fxanim(a,
10053                 o,
10054                 'motion',
10055                 .5,
10056                 'easeOut', after);
10057         });
10058         return this;
10059     },
10060     
10061         /**
10062          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10063          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10064          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10065          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10066          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10067          * Usage:
10068          *<pre><code>
10069 // default: slide the element out to the top
10070 el.slideOut();
10071
10072 // custom: slide the element out to the right with a 2-second duration
10073 el.slideOut('r', { duration: 2 });
10074
10075 // common config options shown with default values
10076 el.slideOut('t', {
10077     easing: 'easeOut',
10078     duration: .5,
10079     remove: false,
10080     useDisplay: false
10081 });
10082 </code></pre>
10083          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10084          * @param {Object} options (optional) Object literal with any of the Fx config options
10085          * @return {Roo.Element} The Element
10086          */
10087     slideOut : function(anchor, o){
10088         var el = this.getFxEl();
10089         o = o || {};
10090
10091         el.queueFx(o, function(){
10092
10093             anchor = anchor || "t";
10094
10095             // restore values after effect
10096             var r = this.getFxRestore();
10097             
10098             var b = this.getBox();
10099             // fixed size for slide
10100             this.setSize(b);
10101
10102             // wrap if needed
10103             var wrap = this.fxWrap(r.pos, o, "visible");
10104
10105             var st = this.dom.style;
10106             st.visibility = "visible";
10107             st.position = "absolute";
10108
10109             wrap.setSize(b);
10110
10111             var after = function(){
10112                 if(o.useDisplay){
10113                     el.setDisplayed(false);
10114                 }else{
10115                     el.hide();
10116                 }
10117
10118                 el.fxUnwrap(wrap, r.pos, o);
10119
10120                 st.width = r.width;
10121                 st.height = r.height;
10122
10123                 el.afterFx(o);
10124             };
10125
10126             var a, zero = {to: 0};
10127             switch(anchor.toLowerCase()){
10128                 case "t":
10129                     st.left = st.bottom = "0";
10130                     a = {height: zero};
10131                 break;
10132                 case "l":
10133                     st.right = st.top = "0";
10134                     a = {width: zero};
10135                 break;
10136                 case "r":
10137                     st.left = st.top = "0";
10138                     a = {width: zero, points: {to:[b.right, b.y]}};
10139                 break;
10140                 case "b":
10141                     st.left = st.top = "0";
10142                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10143                 break;
10144                 case "tl":
10145                     st.right = st.bottom = "0";
10146                     a = {width: zero, height: zero};
10147                 break;
10148                 case "bl":
10149                     st.right = st.top = "0";
10150                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10151                 break;
10152                 case "br":
10153                     st.left = st.top = "0";
10154                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10155                 break;
10156                 case "tr":
10157                     st.left = st.bottom = "0";
10158                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10159                 break;
10160             }
10161
10162             arguments.callee.anim = wrap.fxanim(a,
10163                 o,
10164                 'motion',
10165                 .5,
10166                 "easeOut", after);
10167         });
10168         return this;
10169     },
10170
10171         /**
10172          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10173          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10174          * The element must be removed from the DOM using the 'remove' config option if desired.
10175          * Usage:
10176          *<pre><code>
10177 // default
10178 el.puff();
10179
10180 // common config options shown with default values
10181 el.puff({
10182     easing: 'easeOut',
10183     duration: .5,
10184     remove: false,
10185     useDisplay: false
10186 });
10187 </code></pre>
10188          * @param {Object} options (optional) Object literal with any of the Fx config options
10189          * @return {Roo.Element} The Element
10190          */
10191     puff : function(o){
10192         var el = this.getFxEl();
10193         o = o || {};
10194
10195         el.queueFx(o, function(){
10196             this.clearOpacity();
10197             this.show();
10198
10199             // restore values after effect
10200             var r = this.getFxRestore();
10201             var st = this.dom.style;
10202
10203             var after = function(){
10204                 if(o.useDisplay){
10205                     el.setDisplayed(false);
10206                 }else{
10207                     el.hide();
10208                 }
10209
10210                 el.clearOpacity();
10211
10212                 el.setPositioning(r.pos);
10213                 st.width = r.width;
10214                 st.height = r.height;
10215                 st.fontSize = '';
10216                 el.afterFx(o);
10217             };
10218
10219             var width = this.getWidth();
10220             var height = this.getHeight();
10221
10222             arguments.callee.anim = this.fxanim({
10223                     width : {to: this.adjustWidth(width * 2)},
10224                     height : {to: this.adjustHeight(height * 2)},
10225                     points : {by: [-(width * .5), -(height * .5)]},
10226                     opacity : {to: 0},
10227                     fontSize: {to:200, unit: "%"}
10228                 },
10229                 o,
10230                 'motion',
10231                 .5,
10232                 "easeOut", after);
10233         });
10234         return this;
10235     },
10236
10237         /**
10238          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10239          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10240          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10241          * Usage:
10242          *<pre><code>
10243 // default
10244 el.switchOff();
10245
10246 // all config options shown with default values
10247 el.switchOff({
10248     easing: 'easeIn',
10249     duration: .3,
10250     remove: false,
10251     useDisplay: false
10252 });
10253 </code></pre>
10254          * @param {Object} options (optional) Object literal with any of the Fx config options
10255          * @return {Roo.Element} The Element
10256          */
10257     switchOff : function(o){
10258         var el = this.getFxEl();
10259         o = o || {};
10260
10261         el.queueFx(o, function(){
10262             this.clearOpacity();
10263             this.clip();
10264
10265             // restore values after effect
10266             var r = this.getFxRestore();
10267             var st = this.dom.style;
10268
10269             var after = function(){
10270                 if(o.useDisplay){
10271                     el.setDisplayed(false);
10272                 }else{
10273                     el.hide();
10274                 }
10275
10276                 el.clearOpacity();
10277                 el.setPositioning(r.pos);
10278                 st.width = r.width;
10279                 st.height = r.height;
10280
10281                 el.afterFx(o);
10282             };
10283
10284             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10285                 this.clearOpacity();
10286                 (function(){
10287                     this.fxanim({
10288                         height:{to:1},
10289                         points:{by:[0, this.getHeight() * .5]}
10290                     }, o, 'motion', 0.3, 'easeIn', after);
10291                 }).defer(100, this);
10292             });
10293         });
10294         return this;
10295     },
10296
10297     /**
10298      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10299      * changed using the "attr" config option) and then fading back to the original color. If no original
10300      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10301      * Usage:
10302 <pre><code>
10303 // default: highlight background to yellow
10304 el.highlight();
10305
10306 // custom: highlight foreground text to blue for 2 seconds
10307 el.highlight("0000ff", { attr: 'color', duration: 2 });
10308
10309 // common config options shown with default values
10310 el.highlight("ffff9c", {
10311     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10312     endColor: (current color) or "ffffff",
10313     easing: 'easeIn',
10314     duration: 1
10315 });
10316 </code></pre>
10317      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10318      * @param {Object} options (optional) Object literal with any of the Fx config options
10319      * @return {Roo.Element} The Element
10320      */ 
10321     highlight : function(color, o){
10322         var el = this.getFxEl();
10323         o = o || {};
10324
10325         el.queueFx(o, function(){
10326             color = color || "ffff9c";
10327             attr = o.attr || "backgroundColor";
10328
10329             this.clearOpacity();
10330             this.show();
10331
10332             var origColor = this.getColor(attr);
10333             var restoreColor = this.dom.style[attr];
10334             endColor = (o.endColor || origColor) || "ffffff";
10335
10336             var after = function(){
10337                 el.dom.style[attr] = restoreColor;
10338                 el.afterFx(o);
10339             };
10340
10341             var a = {};
10342             a[attr] = {from: color, to: endColor};
10343             arguments.callee.anim = this.fxanim(a,
10344                 o,
10345                 'color',
10346                 1,
10347                 'easeIn', after);
10348         });
10349         return this;
10350     },
10351
10352    /**
10353     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10354     * Usage:
10355 <pre><code>
10356 // default: a single light blue ripple
10357 el.frame();
10358
10359 // custom: 3 red ripples lasting 3 seconds total
10360 el.frame("ff0000", 3, { duration: 3 });
10361
10362 // common config options shown with default values
10363 el.frame("C3DAF9", 1, {
10364     duration: 1 //duration of entire animation (not each individual ripple)
10365     // Note: Easing is not configurable and will be ignored if included
10366 });
10367 </code></pre>
10368     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10369     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10370     * @param {Object} options (optional) Object literal with any of the Fx config options
10371     * @return {Roo.Element} The Element
10372     */
10373     frame : function(color, count, o){
10374         var el = this.getFxEl();
10375         o = o || {};
10376
10377         el.queueFx(o, function(){
10378             color = color || "#C3DAF9";
10379             if(color.length == 6){
10380                 color = "#" + color;
10381             }
10382             count = count || 1;
10383             duration = o.duration || 1;
10384             this.show();
10385
10386             var b = this.getBox();
10387             var animFn = function(){
10388                 var proxy = this.createProxy({
10389
10390                      style:{
10391                         visbility:"hidden",
10392                         position:"absolute",
10393                         "z-index":"35000", // yee haw
10394                         border:"0px solid " + color
10395                      }
10396                   });
10397                 var scale = Roo.isBorderBox ? 2 : 1;
10398                 proxy.animate({
10399                     top:{from:b.y, to:b.y - 20},
10400                     left:{from:b.x, to:b.x - 20},
10401                     borderWidth:{from:0, to:10},
10402                     opacity:{from:1, to:0},
10403                     height:{from:b.height, to:(b.height + (20*scale))},
10404                     width:{from:b.width, to:(b.width + (20*scale))}
10405                 }, duration, function(){
10406                     proxy.remove();
10407                 });
10408                 if(--count > 0){
10409                      animFn.defer((duration/2)*1000, this);
10410                 }else{
10411                     el.afterFx(o);
10412                 }
10413             };
10414             animFn.call(this);
10415         });
10416         return this;
10417     },
10418
10419    /**
10420     * Creates a pause before any subsequent queued effects begin.  If there are
10421     * no effects queued after the pause it will have no effect.
10422     * Usage:
10423 <pre><code>
10424 el.pause(1);
10425 </code></pre>
10426     * @param {Number} seconds The length of time to pause (in seconds)
10427     * @return {Roo.Element} The Element
10428     */
10429     pause : function(seconds){
10430         var el = this.getFxEl();
10431         var o = {};
10432
10433         el.queueFx(o, function(){
10434             setTimeout(function(){
10435                 el.afterFx(o);
10436             }, seconds * 1000);
10437         });
10438         return this;
10439     },
10440
10441    /**
10442     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10443     * using the "endOpacity" config option.
10444     * Usage:
10445 <pre><code>
10446 // default: fade in from opacity 0 to 100%
10447 el.fadeIn();
10448
10449 // custom: fade in from opacity 0 to 75% over 2 seconds
10450 el.fadeIn({ endOpacity: .75, duration: 2});
10451
10452 // common config options shown with default values
10453 el.fadeIn({
10454     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10455     easing: 'easeOut',
10456     duration: .5
10457 });
10458 </code></pre>
10459     * @param {Object} options (optional) Object literal with any of the Fx config options
10460     * @return {Roo.Element} The Element
10461     */
10462     fadeIn : function(o){
10463         var el = this.getFxEl();
10464         o = o || {};
10465         el.queueFx(o, function(){
10466             this.setOpacity(0);
10467             this.fixDisplay();
10468             this.dom.style.visibility = 'visible';
10469             var to = o.endOpacity || 1;
10470             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10471                 o, null, .5, "easeOut", function(){
10472                 if(to == 1){
10473                     this.clearOpacity();
10474                 }
10475                 el.afterFx(o);
10476             });
10477         });
10478         return this;
10479     },
10480
10481    /**
10482     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10483     * using the "endOpacity" config option.
10484     * Usage:
10485 <pre><code>
10486 // default: fade out from the element's current opacity to 0
10487 el.fadeOut();
10488
10489 // custom: fade out from the element's current opacity to 25% over 2 seconds
10490 el.fadeOut({ endOpacity: .25, duration: 2});
10491
10492 // common config options shown with default values
10493 el.fadeOut({
10494     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10495     easing: 'easeOut',
10496     duration: .5
10497     remove: false,
10498     useDisplay: false
10499 });
10500 </code></pre>
10501     * @param {Object} options (optional) Object literal with any of the Fx config options
10502     * @return {Roo.Element} The Element
10503     */
10504     fadeOut : function(o){
10505         var el = this.getFxEl();
10506         o = o || {};
10507         el.queueFx(o, function(){
10508             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10509                 o, null, .5, "easeOut", function(){
10510                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10511                      this.dom.style.display = "none";
10512                 }else{
10513                      this.dom.style.visibility = "hidden";
10514                 }
10515                 this.clearOpacity();
10516                 el.afterFx(o);
10517             });
10518         });
10519         return this;
10520     },
10521
10522    /**
10523     * Animates the transition of an element's dimensions from a starting height/width
10524     * to an ending height/width.
10525     * Usage:
10526 <pre><code>
10527 // change height and width to 100x100 pixels
10528 el.scale(100, 100);
10529
10530 // common config options shown with default values.  The height and width will default to
10531 // the element's existing values if passed as null.
10532 el.scale(
10533     [element's width],
10534     [element's height], {
10535     easing: 'easeOut',
10536     duration: .35
10537 });
10538 </code></pre>
10539     * @param {Number} width  The new width (pass undefined to keep the original width)
10540     * @param {Number} height  The new height (pass undefined to keep the original height)
10541     * @param {Object} options (optional) Object literal with any of the Fx config options
10542     * @return {Roo.Element} The Element
10543     */
10544     scale : function(w, h, o){
10545         this.shift(Roo.apply({}, o, {
10546             width: w,
10547             height: h
10548         }));
10549         return this;
10550     },
10551
10552    /**
10553     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10554     * Any of these properties not specified in the config object will not be changed.  This effect 
10555     * requires that at least one new dimension, position or opacity setting must be passed in on
10556     * the config object in order for the function to have any effect.
10557     * Usage:
10558 <pre><code>
10559 // slide the element horizontally to x position 200 while changing the height and opacity
10560 el.shift({ x: 200, height: 50, opacity: .8 });
10561
10562 // common config options shown with default values.
10563 el.shift({
10564     width: [element's width],
10565     height: [element's height],
10566     x: [element's x position],
10567     y: [element's y position],
10568     opacity: [element's opacity],
10569     easing: 'easeOut',
10570     duration: .35
10571 });
10572 </code></pre>
10573     * @param {Object} options  Object literal with any of the Fx config options
10574     * @return {Roo.Element} The Element
10575     */
10576     shift : function(o){
10577         var el = this.getFxEl();
10578         o = o || {};
10579         el.queueFx(o, function(){
10580             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10581             if(w !== undefined){
10582                 a.width = {to: this.adjustWidth(w)};
10583             }
10584             if(h !== undefined){
10585                 a.height = {to: this.adjustHeight(h)};
10586             }
10587             if(x !== undefined || y !== undefined){
10588                 a.points = {to: [
10589                     x !== undefined ? x : this.getX(),
10590                     y !== undefined ? y : this.getY()
10591                 ]};
10592             }
10593             if(op !== undefined){
10594                 a.opacity = {to: op};
10595             }
10596             if(o.xy !== undefined){
10597                 a.points = {to: o.xy};
10598             }
10599             arguments.callee.anim = this.fxanim(a,
10600                 o, 'motion', .35, "easeOut", function(){
10601                 el.afterFx(o);
10602             });
10603         });
10604         return this;
10605     },
10606
10607         /**
10608          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10609          * ending point of the effect.
10610          * Usage:
10611          *<pre><code>
10612 // default: slide the element downward while fading out
10613 el.ghost();
10614
10615 // custom: slide the element out to the right with a 2-second duration
10616 el.ghost('r', { duration: 2 });
10617
10618 // common config options shown with default values
10619 el.ghost('b', {
10620     easing: 'easeOut',
10621     duration: .5
10622     remove: false,
10623     useDisplay: false
10624 });
10625 </code></pre>
10626          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10627          * @param {Object} options (optional) Object literal with any of the Fx config options
10628          * @return {Roo.Element} The Element
10629          */
10630     ghost : function(anchor, o){
10631         var el = this.getFxEl();
10632         o = o || {};
10633
10634         el.queueFx(o, function(){
10635             anchor = anchor || "b";
10636
10637             // restore values after effect
10638             var r = this.getFxRestore();
10639             var w = this.getWidth(),
10640                 h = this.getHeight();
10641
10642             var st = this.dom.style;
10643
10644             var after = function(){
10645                 if(o.useDisplay){
10646                     el.setDisplayed(false);
10647                 }else{
10648                     el.hide();
10649                 }
10650
10651                 el.clearOpacity();
10652                 el.setPositioning(r.pos);
10653                 st.width = r.width;
10654                 st.height = r.height;
10655
10656                 el.afterFx(o);
10657             };
10658
10659             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10660             switch(anchor.toLowerCase()){
10661                 case "t":
10662                     pt.by = [0, -h];
10663                 break;
10664                 case "l":
10665                     pt.by = [-w, 0];
10666                 break;
10667                 case "r":
10668                     pt.by = [w, 0];
10669                 break;
10670                 case "b":
10671                     pt.by = [0, h];
10672                 break;
10673                 case "tl":
10674                     pt.by = [-w, -h];
10675                 break;
10676                 case "bl":
10677                     pt.by = [-w, h];
10678                 break;
10679                 case "br":
10680                     pt.by = [w, h];
10681                 break;
10682                 case "tr":
10683                     pt.by = [w, -h];
10684                 break;
10685             }
10686
10687             arguments.callee.anim = this.fxanim(a,
10688                 o,
10689                 'motion',
10690                 .5,
10691                 "easeOut", after);
10692         });
10693         return this;
10694     },
10695
10696         /**
10697          * Ensures that all effects queued after syncFx is called on the element are
10698          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10699          * @return {Roo.Element} The Element
10700          */
10701     syncFx : function(){
10702         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10703             block : false,
10704             concurrent : true,
10705             stopFx : false
10706         });
10707         return this;
10708     },
10709
10710         /**
10711          * Ensures that all effects queued after sequenceFx is called on the element are
10712          * run in sequence.  This is the opposite of {@link #syncFx}.
10713          * @return {Roo.Element} The Element
10714          */
10715     sequenceFx : function(){
10716         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10717             block : false,
10718             concurrent : false,
10719             stopFx : false
10720         });
10721         return this;
10722     },
10723
10724         /* @private */
10725     nextFx : function(){
10726         var ef = this.fxQueue[0];
10727         if(ef){
10728             ef.call(this);
10729         }
10730     },
10731
10732         /**
10733          * Returns true if the element has any effects actively running or queued, else returns false.
10734          * @return {Boolean} True if element has active effects, else false
10735          */
10736     hasActiveFx : function(){
10737         return this.fxQueue && this.fxQueue[0];
10738     },
10739
10740         /**
10741          * Stops any running effects and clears the element's internal effects queue if it contains
10742          * any additional effects that haven't started yet.
10743          * @return {Roo.Element} The Element
10744          */
10745     stopFx : function(){
10746         if(this.hasActiveFx()){
10747             var cur = this.fxQueue[0];
10748             if(cur && cur.anim && cur.anim.isAnimated()){
10749                 this.fxQueue = [cur]; // clear out others
10750                 cur.anim.stop(true);
10751             }
10752         }
10753         return this;
10754     },
10755
10756         /* @private */
10757     beforeFx : function(o){
10758         if(this.hasActiveFx() && !o.concurrent){
10759            if(o.stopFx){
10760                this.stopFx();
10761                return true;
10762            }
10763            return false;
10764         }
10765         return true;
10766     },
10767
10768         /**
10769          * Returns true if the element is currently blocking so that no other effect can be queued
10770          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10771          * used to ensure that an effect initiated by a user action runs to completion prior to the
10772          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10773          * @return {Boolean} True if blocking, else false
10774          */
10775     hasFxBlock : function(){
10776         var q = this.fxQueue;
10777         return q && q[0] && q[0].block;
10778     },
10779
10780         /* @private */
10781     queueFx : function(o, fn){
10782         if(!this.fxQueue){
10783             this.fxQueue = [];
10784         }
10785         if(!this.hasFxBlock()){
10786             Roo.applyIf(o, this.fxDefaults);
10787             if(!o.concurrent){
10788                 var run = this.beforeFx(o);
10789                 fn.block = o.block;
10790                 this.fxQueue.push(fn);
10791                 if(run){
10792                     this.nextFx();
10793                 }
10794             }else{
10795                 fn.call(this);
10796             }
10797         }
10798         return this;
10799     },
10800
10801         /* @private */
10802     fxWrap : function(pos, o, vis){
10803         var wrap;
10804         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10805             var wrapXY;
10806             if(o.fixPosition){
10807                 wrapXY = this.getXY();
10808             }
10809             var div = document.createElement("div");
10810             div.style.visibility = vis;
10811             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10812             wrap.setPositioning(pos);
10813             if(wrap.getStyle("position") == "static"){
10814                 wrap.position("relative");
10815             }
10816             this.clearPositioning('auto');
10817             wrap.clip();
10818             wrap.dom.appendChild(this.dom);
10819             if(wrapXY){
10820                 wrap.setXY(wrapXY);
10821             }
10822         }
10823         return wrap;
10824     },
10825
10826         /* @private */
10827     fxUnwrap : function(wrap, pos, o){
10828         this.clearPositioning();
10829         this.setPositioning(pos);
10830         if(!o.wrap){
10831             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10832             wrap.remove();
10833         }
10834     },
10835
10836         /* @private */
10837     getFxRestore : function(){
10838         var st = this.dom.style;
10839         return {pos: this.getPositioning(), width: st.width, height : st.height};
10840     },
10841
10842         /* @private */
10843     afterFx : function(o){
10844         if(o.afterStyle){
10845             this.applyStyles(o.afterStyle);
10846         }
10847         if(o.afterCls){
10848             this.addClass(o.afterCls);
10849         }
10850         if(o.remove === true){
10851             this.remove();
10852         }
10853         Roo.callback(o.callback, o.scope, [this]);
10854         if(!o.concurrent){
10855             this.fxQueue.shift();
10856             this.nextFx();
10857         }
10858     },
10859
10860         /* @private */
10861     getFxEl : function(){ // support for composite element fx
10862         return Roo.get(this.dom);
10863     },
10864
10865         /* @private */
10866     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10867         animType = animType || 'run';
10868         opt = opt || {};
10869         var anim = Roo.lib.Anim[animType](
10870             this.dom, args,
10871             (opt.duration || defaultDur) || .35,
10872             (opt.easing || defaultEase) || 'easeOut',
10873             function(){
10874                 Roo.callback(cb, this);
10875             },
10876             this
10877         );
10878         opt.anim = anim;
10879         return anim;
10880     }
10881 };
10882
10883 // backwords compat
10884 Roo.Fx.resize = Roo.Fx.scale;
10885
10886 //When included, Roo.Fx is automatically applied to Element so that all basic
10887 //effects are available directly via the Element API
10888 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10889  * Based on:
10890  * Ext JS Library 1.1.1
10891  * Copyright(c) 2006-2007, Ext JS, LLC.
10892  *
10893  * Originally Released Under LGPL - original licence link has changed is not relivant.
10894  *
10895  * Fork - LGPL
10896  * <script type="text/javascript">
10897  */
10898
10899
10900 /**
10901  * @class Roo.CompositeElement
10902  * Standard composite class. Creates a Roo.Element for every element in the collection.
10903  * <br><br>
10904  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10905  * actions will be performed on all the elements in this collection.</b>
10906  * <br><br>
10907  * All methods return <i>this</i> and can be chained.
10908  <pre><code>
10909  var els = Roo.select("#some-el div.some-class", true);
10910  // or select directly from an existing element
10911  var el = Roo.get('some-el');
10912  el.select('div.some-class', true);
10913
10914  els.setWidth(100); // all elements become 100 width
10915  els.hide(true); // all elements fade out and hide
10916  // or
10917  els.setWidth(100).hide(true);
10918  </code></pre>
10919  */
10920 Roo.CompositeElement = function(els){
10921     this.elements = [];
10922     this.addElements(els);
10923 };
10924 Roo.CompositeElement.prototype = {
10925     isComposite: true,
10926     addElements : function(els){
10927         if(!els) return this;
10928         if(typeof els == "string"){
10929             els = Roo.Element.selectorFunction(els);
10930         }
10931         var yels = this.elements;
10932         var index = yels.length-1;
10933         for(var i = 0, len = els.length; i < len; i++) {
10934                 yels[++index] = Roo.get(els[i]);
10935         }
10936         return this;
10937     },
10938
10939     /**
10940     * Clears this composite and adds the elements returned by the passed selector.
10941     * @param {String/Array} els A string CSS selector, an array of elements or an element
10942     * @return {CompositeElement} this
10943     */
10944     fill : function(els){
10945         this.elements = [];
10946         this.add(els);
10947         return this;
10948     },
10949
10950     /**
10951     * Filters this composite to only elements that match the passed selector.
10952     * @param {String} selector A string CSS selector
10953     * @return {CompositeElement} this
10954     */
10955     filter : function(selector){
10956         var els = [];
10957         this.each(function(el){
10958             if(el.is(selector)){
10959                 els[els.length] = el.dom;
10960             }
10961         });
10962         this.fill(els);
10963         return this;
10964     },
10965
10966     invoke : function(fn, args){
10967         var els = this.elements;
10968         for(var i = 0, len = els.length; i < len; i++) {
10969                 Roo.Element.prototype[fn].apply(els[i], args);
10970         }
10971         return this;
10972     },
10973     /**
10974     * Adds elements to this composite.
10975     * @param {String/Array} els A string CSS selector, an array of elements or an element
10976     * @return {CompositeElement} this
10977     */
10978     add : function(els){
10979         if(typeof els == "string"){
10980             this.addElements(Roo.Element.selectorFunction(els));
10981         }else if(els.length !== undefined){
10982             this.addElements(els);
10983         }else{
10984             this.addElements([els]);
10985         }
10986         return this;
10987     },
10988     /**
10989     * Calls the passed function passing (el, this, index) for each element in this composite.
10990     * @param {Function} fn The function to call
10991     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10992     * @return {CompositeElement} this
10993     */
10994     each : function(fn, scope){
10995         var els = this.elements;
10996         for(var i = 0, len = els.length; i < len; i++){
10997             if(fn.call(scope || els[i], els[i], this, i) === false) {
10998                 break;
10999             }
11000         }
11001         return this;
11002     },
11003
11004     /**
11005      * Returns the Element object at the specified index
11006      * @param {Number} index
11007      * @return {Roo.Element}
11008      */
11009     item : function(index){
11010         return this.elements[index] || null;
11011     },
11012
11013     /**
11014      * Returns the first Element
11015      * @return {Roo.Element}
11016      */
11017     first : function(){
11018         return this.item(0);
11019     },
11020
11021     /**
11022      * Returns the last Element
11023      * @return {Roo.Element}
11024      */
11025     last : function(){
11026         return this.item(this.elements.length-1);
11027     },
11028
11029     /**
11030      * Returns the number of elements in this composite
11031      * @return Number
11032      */
11033     getCount : function(){
11034         return this.elements.length;
11035     },
11036
11037     /**
11038      * Returns true if this composite contains the passed element
11039      * @return Boolean
11040      */
11041     contains : function(el){
11042         return this.indexOf(el) !== -1;
11043     },
11044
11045     /**
11046      * Returns true if this composite contains the passed element
11047      * @return Boolean
11048      */
11049     indexOf : function(el){
11050         return this.elements.indexOf(Roo.get(el));
11051     },
11052
11053
11054     /**
11055     * Removes the specified element(s).
11056     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11057     * or an array of any of those.
11058     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11059     * @return {CompositeElement} this
11060     */
11061     removeElement : function(el, removeDom){
11062         if(el instanceof Array){
11063             for(var i = 0, len = el.length; i < len; i++){
11064                 this.removeElement(el[i]);
11065             }
11066             return this;
11067         }
11068         var index = typeof el == 'number' ? el : this.indexOf(el);
11069         if(index !== -1){
11070             if(removeDom){
11071                 var d = this.elements[index];
11072                 if(d.dom){
11073                     d.remove();
11074                 }else{
11075                     d.parentNode.removeChild(d);
11076                 }
11077             }
11078             this.elements.splice(index, 1);
11079         }
11080         return this;
11081     },
11082
11083     /**
11084     * Replaces the specified element with the passed element.
11085     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11086     * to replace.
11087     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11088     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11089     * @return {CompositeElement} this
11090     */
11091     replaceElement : function(el, replacement, domReplace){
11092         var index = typeof el == 'number' ? el : this.indexOf(el);
11093         if(index !== -1){
11094             if(domReplace){
11095                 this.elements[index].replaceWith(replacement);
11096             }else{
11097                 this.elements.splice(index, 1, Roo.get(replacement))
11098             }
11099         }
11100         return this;
11101     },
11102
11103     /**
11104      * Removes all elements.
11105      */
11106     clear : function(){
11107         this.elements = [];
11108     }
11109 };
11110 (function(){
11111     Roo.CompositeElement.createCall = function(proto, fnName){
11112         if(!proto[fnName]){
11113             proto[fnName] = function(){
11114                 return this.invoke(fnName, arguments);
11115             };
11116         }
11117     };
11118     for(var fnName in Roo.Element.prototype){
11119         if(typeof Roo.Element.prototype[fnName] == "function"){
11120             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11121         }
11122     };
11123 })();
11124 /*
11125  * Based on:
11126  * Ext JS Library 1.1.1
11127  * Copyright(c) 2006-2007, Ext JS, LLC.
11128  *
11129  * Originally Released Under LGPL - original licence link has changed is not relivant.
11130  *
11131  * Fork - LGPL
11132  * <script type="text/javascript">
11133  */
11134
11135 /**
11136  * @class Roo.CompositeElementLite
11137  * @extends Roo.CompositeElement
11138  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11139  <pre><code>
11140  var els = Roo.select("#some-el div.some-class");
11141  // or select directly from an existing element
11142  var el = Roo.get('some-el');
11143  el.select('div.some-class');
11144
11145  els.setWidth(100); // all elements become 100 width
11146  els.hide(true); // all elements fade out and hide
11147  // or
11148  els.setWidth(100).hide(true);
11149  </code></pre><br><br>
11150  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11151  * actions will be performed on all the elements in this collection.</b>
11152  */
11153 Roo.CompositeElementLite = function(els){
11154     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11155     this.el = new Roo.Element.Flyweight();
11156 };
11157 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11158     addElements : function(els){
11159         if(els){
11160             if(els instanceof Array){
11161                 this.elements = this.elements.concat(els);
11162             }else{
11163                 var yels = this.elements;
11164                 var index = yels.length-1;
11165                 for(var i = 0, len = els.length; i < len; i++) {
11166                     yels[++index] = els[i];
11167                 }
11168             }
11169         }
11170         return this;
11171     },
11172     invoke : function(fn, args){
11173         var els = this.elements;
11174         var el = this.el;
11175         for(var i = 0, len = els.length; i < len; i++) {
11176             el.dom = els[i];
11177                 Roo.Element.prototype[fn].apply(el, args);
11178         }
11179         return this;
11180     },
11181     /**
11182      * Returns a flyweight Element of the dom element object at the specified index
11183      * @param {Number} index
11184      * @return {Roo.Element}
11185      */
11186     item : function(index){
11187         if(!this.elements[index]){
11188             return null;
11189         }
11190         this.el.dom = this.elements[index];
11191         return this.el;
11192     },
11193
11194     // fixes scope with flyweight
11195     addListener : function(eventName, handler, scope, opt){
11196         var els = this.elements;
11197         for(var i = 0, len = els.length; i < len; i++) {
11198             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11199         }
11200         return this;
11201     },
11202
11203     /**
11204     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11205     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11206     * a reference to the dom node, use el.dom.</b>
11207     * @param {Function} fn The function to call
11208     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11209     * @return {CompositeElement} this
11210     */
11211     each : function(fn, scope){
11212         var els = this.elements;
11213         var el = this.el;
11214         for(var i = 0, len = els.length; i < len; i++){
11215             el.dom = els[i];
11216                 if(fn.call(scope || el, el, this, i) === false){
11217                 break;
11218             }
11219         }
11220         return this;
11221     },
11222
11223     indexOf : function(el){
11224         return this.elements.indexOf(Roo.getDom(el));
11225     },
11226
11227     replaceElement : function(el, replacement, domReplace){
11228         var index = typeof el == 'number' ? el : this.indexOf(el);
11229         if(index !== -1){
11230             replacement = Roo.getDom(replacement);
11231             if(domReplace){
11232                 var d = this.elements[index];
11233                 d.parentNode.insertBefore(replacement, d);
11234                 d.parentNode.removeChild(d);
11235             }
11236             this.elements.splice(index, 1, replacement);
11237         }
11238         return this;
11239     }
11240 });
11241 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11242
11243 /*
11244  * Based on:
11245  * Ext JS Library 1.1.1
11246  * Copyright(c) 2006-2007, Ext JS, LLC.
11247  *
11248  * Originally Released Under LGPL - original licence link has changed is not relivant.
11249  *
11250  * Fork - LGPL
11251  * <script type="text/javascript">
11252  */
11253
11254  
11255
11256 /**
11257  * @class Roo.data.Connection
11258  * @extends Roo.util.Observable
11259  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11260  * either to a configured URL, or to a URL specified at request time.<br><br>
11261  * <p>
11262  * Requests made by this class are asynchronous, and will return immediately. No data from
11263  * the server will be available to the statement immediately following the {@link #request} call.
11264  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11265  * <p>
11266  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11267  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11268  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11269  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11270  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11271  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11272  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11273  * standard DOM methods.
11274  * @constructor
11275  * @param {Object} config a configuration object.
11276  */
11277 Roo.data.Connection = function(config){
11278     Roo.apply(this, config);
11279     this.addEvents({
11280         /**
11281          * @event beforerequest
11282          * Fires before a network request is made to retrieve a data object.
11283          * @param {Connection} conn This Connection object.
11284          * @param {Object} options The options config object passed to the {@link #request} method.
11285          */
11286         "beforerequest" : true,
11287         /**
11288          * @event requestcomplete
11289          * Fires if the request was successfully completed.
11290          * @param {Connection} conn This Connection object.
11291          * @param {Object} response The XHR object containing the response data.
11292          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11293          * @param {Object} options The options config object passed to the {@link #request} method.
11294          */
11295         "requestcomplete" : true,
11296         /**
11297          * @event requestexception
11298          * Fires if an error HTTP status was returned from the server.
11299          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11300          * @param {Connection} conn This Connection object.
11301          * @param {Object} response The XHR object containing the response data.
11302          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11303          * @param {Object} options The options config object passed to the {@link #request} method.
11304          */
11305         "requestexception" : true
11306     });
11307     Roo.data.Connection.superclass.constructor.call(this);
11308 };
11309
11310 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11311     /**
11312      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11313      */
11314     /**
11315      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11316      * extra parameters to each request made by this object. (defaults to undefined)
11317      */
11318     /**
11319      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11320      *  to each request made by this object. (defaults to undefined)
11321      */
11322     /**
11323      * @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)
11324      */
11325     /**
11326      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11327      */
11328     timeout : 30000,
11329     /**
11330      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11331      * @type Boolean
11332      */
11333     autoAbort:false,
11334
11335     /**
11336      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11337      * @type Boolean
11338      */
11339     disableCaching: true,
11340
11341     /**
11342      * Sends an HTTP request to a remote server.
11343      * @param {Object} options An object which may contain the following properties:<ul>
11344      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11345      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11346      * request, a url encoded string or a function to call to get either.</li>
11347      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11348      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11349      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11350      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11351      * <li>options {Object} The parameter to the request call.</li>
11352      * <li>success {Boolean} True if the request succeeded.</li>
11353      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11354      * </ul></li>
11355      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11356      * The callback is passed the following parameters:<ul>
11357      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11358      * <li>options {Object} The parameter to the request call.</li>
11359      * </ul></li>
11360      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11361      * The callback is passed the following parameters:<ul>
11362      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11363      * <li>options {Object} The parameter to the request call.</li>
11364      * </ul></li>
11365      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11366      * for the callback function. Defaults to the browser window.</li>
11367      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11368      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11369      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11370      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11371      * params for the post data. Any params will be appended to the URL.</li>
11372      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11373      * </ul>
11374      * @return {Number} transactionId
11375      */
11376     request : function(o){
11377         if(this.fireEvent("beforerequest", this, o) !== false){
11378             var p = o.params;
11379
11380             if(typeof p == "function"){
11381                 p = p.call(o.scope||window, o);
11382             }
11383             if(typeof p == "object"){
11384                 p = Roo.urlEncode(o.params);
11385             }
11386             if(this.extraParams){
11387                 var extras = Roo.urlEncode(this.extraParams);
11388                 p = p ? (p + '&' + extras) : extras;
11389             }
11390
11391             var url = o.url || this.url;
11392             if(typeof url == 'function'){
11393                 url = url.call(o.scope||window, o);
11394             }
11395
11396             if(o.form){
11397                 var form = Roo.getDom(o.form);
11398                 url = url || form.action;
11399
11400                 var enctype = form.getAttribute("enctype");
11401                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11402                     return this.doFormUpload(o, p, url);
11403                 }
11404                 var f = Roo.lib.Ajax.serializeForm(form);
11405                 p = p ? (p + '&' + f) : f;
11406             }
11407
11408             var hs = o.headers;
11409             if(this.defaultHeaders){
11410                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11411                 if(!o.headers){
11412                     o.headers = hs;
11413                 }
11414             }
11415
11416             var cb = {
11417                 success: this.handleResponse,
11418                 failure: this.handleFailure,
11419                 scope: this,
11420                 argument: {options: o},
11421                 timeout : o.timeout || this.timeout
11422             };
11423
11424             var method = o.method||this.method||(p ? "POST" : "GET");
11425
11426             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11427                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11428             }
11429
11430             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11431                 if(o.autoAbort){
11432                     this.abort();
11433                 }
11434             }else if(this.autoAbort !== false){
11435                 this.abort();
11436             }
11437
11438             if((method == 'GET' && p) || o.xmlData){
11439                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11440                 p = '';
11441             }
11442             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11443             return this.transId;
11444         }else{
11445             Roo.callback(o.callback, o.scope, [o, null, null]);
11446             return null;
11447         }
11448     },
11449
11450     /**
11451      * Determine whether this object has a request outstanding.
11452      * @param {Number} transactionId (Optional) defaults to the last transaction
11453      * @return {Boolean} True if there is an outstanding request.
11454      */
11455     isLoading : function(transId){
11456         if(transId){
11457             return Roo.lib.Ajax.isCallInProgress(transId);
11458         }else{
11459             return this.transId ? true : false;
11460         }
11461     },
11462
11463     /**
11464      * Aborts any outstanding request.
11465      * @param {Number} transactionId (Optional) defaults to the last transaction
11466      */
11467     abort : function(transId){
11468         if(transId || this.isLoading()){
11469             Roo.lib.Ajax.abort(transId || this.transId);
11470         }
11471     },
11472
11473     // private
11474     handleResponse : function(response){
11475         this.transId = false;
11476         var options = response.argument.options;
11477         response.argument = options ? options.argument : null;
11478         this.fireEvent("requestcomplete", this, response, options);
11479         Roo.callback(options.success, options.scope, [response, options]);
11480         Roo.callback(options.callback, options.scope, [options, true, response]);
11481     },
11482
11483     // private
11484     handleFailure : function(response, e){
11485         this.transId = false;
11486         var options = response.argument.options;
11487         response.argument = options ? options.argument : null;
11488         this.fireEvent("requestexception", this, response, options, e);
11489         Roo.callback(options.failure, options.scope, [response, options]);
11490         Roo.callback(options.callback, options.scope, [options, false, response]);
11491     },
11492
11493     // private
11494     doFormUpload : function(o, ps, url){
11495         var id = Roo.id();
11496         var frame = document.createElement('iframe');
11497         frame.id = id;
11498         frame.name = id;
11499         frame.className = 'x-hidden';
11500         if(Roo.isIE){
11501             frame.src = Roo.SSL_SECURE_URL;
11502         }
11503         document.body.appendChild(frame);
11504
11505         if(Roo.isIE){
11506            document.frames[id].name = id;
11507         }
11508
11509         var form = Roo.getDom(o.form);
11510         form.target = id;
11511         form.method = 'POST';
11512         form.enctype = form.encoding = 'multipart/form-data';
11513         if(url){
11514             form.action = url;
11515         }
11516
11517         var hiddens, hd;
11518         if(ps){ // add dynamic params
11519             hiddens = [];
11520             ps = Roo.urlDecode(ps, false);
11521             for(var k in ps){
11522                 if(ps.hasOwnProperty(k)){
11523                     hd = document.createElement('input');
11524                     hd.type = 'hidden';
11525                     hd.name = k;
11526                     hd.value = ps[k];
11527                     form.appendChild(hd);
11528                     hiddens.push(hd);
11529                 }
11530             }
11531         }
11532
11533         function cb(){
11534             var r = {  // bogus response object
11535                 responseText : '',
11536                 responseXML : null
11537             };
11538
11539             r.argument = o ? o.argument : null;
11540
11541             try { //
11542                 var doc;
11543                 if(Roo.isIE){
11544                     doc = frame.contentWindow.document;
11545                 }else {
11546                     doc = (frame.contentDocument || window.frames[id].document);
11547                 }
11548                 if(doc && doc.body){
11549                     r.responseText = doc.body.innerHTML;
11550                 }
11551                 if(doc && doc.XMLDocument){
11552                     r.responseXML = doc.XMLDocument;
11553                 }else {
11554                     r.responseXML = doc;
11555                 }
11556             }
11557             catch(e) {
11558                 // ignore
11559             }
11560
11561             Roo.EventManager.removeListener(frame, 'load', cb, this);
11562
11563             this.fireEvent("requestcomplete", this, r, o);
11564             Roo.callback(o.success, o.scope, [r, o]);
11565             Roo.callback(o.callback, o.scope, [o, true, r]);
11566
11567             setTimeout(function(){document.body.removeChild(frame);}, 100);
11568         }
11569
11570         Roo.EventManager.on(frame, 'load', cb, this);
11571         form.submit();
11572
11573         if(hiddens){ // remove dynamic params
11574             for(var i = 0, len = hiddens.length; i < len; i++){
11575                 form.removeChild(hiddens[i]);
11576             }
11577         }
11578     }
11579 });
11580 /*
11581  * Based on:
11582  * Ext JS Library 1.1.1
11583  * Copyright(c) 2006-2007, Ext JS, LLC.
11584  *
11585  * Originally Released Under LGPL - original licence link has changed is not relivant.
11586  *
11587  * Fork - LGPL
11588  * <script type="text/javascript">
11589  */
11590  
11591 /**
11592  * Global Ajax request class.
11593  * 
11594  * @class Roo.Ajax
11595  * @extends Roo.data.Connection
11596  * @static
11597  * 
11598  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11599  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11600  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11601  * @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)
11602  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11603  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11604  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11605  */
11606 Roo.Ajax = new Roo.data.Connection({
11607     // fix up the docs
11608     /**
11609      * @scope Roo.Ajax
11610      * @type {Boolear} 
11611      */
11612     autoAbort : false,
11613
11614     /**
11615      * Serialize the passed form into a url encoded string
11616      * @scope Roo.Ajax
11617      * @param {String/HTMLElement} form
11618      * @return {String}
11619      */
11620     serializeForm : function(form){
11621         return Roo.lib.Ajax.serializeForm(form);
11622     }
11623 });/*
11624  * Based on:
11625  * Ext JS Library 1.1.1
11626  * Copyright(c) 2006-2007, Ext JS, LLC.
11627  *
11628  * Originally Released Under LGPL - original licence link has changed is not relivant.
11629  *
11630  * Fork - LGPL
11631  * <script type="text/javascript">
11632  */
11633
11634  
11635 /**
11636  * @class Roo.UpdateManager
11637  * @extends Roo.util.Observable
11638  * Provides AJAX-style update for Element object.<br><br>
11639  * Usage:<br>
11640  * <pre><code>
11641  * // Get it from a Roo.Element object
11642  * var el = Roo.get("foo");
11643  * var mgr = el.getUpdateManager();
11644  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11645  * ...
11646  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11647  * <br>
11648  * // or directly (returns the same UpdateManager instance)
11649  * var mgr = new Roo.UpdateManager("myElementId");
11650  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11651  * mgr.on("update", myFcnNeedsToKnow);
11652  * <br>
11653    // short handed call directly from the element object
11654    Roo.get("foo").load({
11655         url: "bar.php",
11656         scripts:true,
11657         params: "for=bar",
11658         text: "Loading Foo..."
11659    });
11660  * </code></pre>
11661  * @constructor
11662  * Create new UpdateManager directly.
11663  * @param {String/HTMLElement/Roo.Element} el The element to update
11664  * @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).
11665  */
11666 Roo.UpdateManager = function(el, forceNew){
11667     el = Roo.get(el);
11668     if(!forceNew && el.updateManager){
11669         return el.updateManager;
11670     }
11671     /**
11672      * The Element object
11673      * @type Roo.Element
11674      */
11675     this.el = el;
11676     /**
11677      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11678      * @type String
11679      */
11680     this.defaultUrl = null;
11681
11682     this.addEvents({
11683         /**
11684          * @event beforeupdate
11685          * Fired before an update is made, return false from your handler and the update is cancelled.
11686          * @param {Roo.Element} el
11687          * @param {String/Object/Function} url
11688          * @param {String/Object} params
11689          */
11690         "beforeupdate": true,
11691         /**
11692          * @event update
11693          * Fired after successful update is made.
11694          * @param {Roo.Element} el
11695          * @param {Object} oResponseObject The response Object
11696          */
11697         "update": true,
11698         /**
11699          * @event failure
11700          * Fired on update failure.
11701          * @param {Roo.Element} el
11702          * @param {Object} oResponseObject The response Object
11703          */
11704         "failure": true
11705     });
11706     var d = Roo.UpdateManager.defaults;
11707     /**
11708      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11709      * @type String
11710      */
11711     this.sslBlankUrl = d.sslBlankUrl;
11712     /**
11713      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11714      * @type Boolean
11715      */
11716     this.disableCaching = d.disableCaching;
11717     /**
11718      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11719      * @type String
11720      */
11721     this.indicatorText = d.indicatorText;
11722     /**
11723      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11724      * @type String
11725      */
11726     this.showLoadIndicator = d.showLoadIndicator;
11727     /**
11728      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11729      * @type Number
11730      */
11731     this.timeout = d.timeout;
11732
11733     /**
11734      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11735      * @type Boolean
11736      */
11737     this.loadScripts = d.loadScripts;
11738
11739     /**
11740      * Transaction object of current executing transaction
11741      */
11742     this.transaction = null;
11743
11744     /**
11745      * @private
11746      */
11747     this.autoRefreshProcId = null;
11748     /**
11749      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11750      * @type Function
11751      */
11752     this.refreshDelegate = this.refresh.createDelegate(this);
11753     /**
11754      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11755      * @type Function
11756      */
11757     this.updateDelegate = this.update.createDelegate(this);
11758     /**
11759      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11760      * @type Function
11761      */
11762     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11763     /**
11764      * @private
11765      */
11766     this.successDelegate = this.processSuccess.createDelegate(this);
11767     /**
11768      * @private
11769      */
11770     this.failureDelegate = this.processFailure.createDelegate(this);
11771
11772     if(!this.renderer){
11773      /**
11774       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11775       */
11776     this.renderer = new Roo.UpdateManager.BasicRenderer();
11777     }
11778     
11779     Roo.UpdateManager.superclass.constructor.call(this);
11780 };
11781
11782 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11783     /**
11784      * Get the Element this UpdateManager is bound to
11785      * @return {Roo.Element} The element
11786      */
11787     getEl : function(){
11788         return this.el;
11789     },
11790     /**
11791      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11792      * @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:
11793 <pre><code>
11794 um.update({<br/>
11795     url: "your-url.php",<br/>
11796     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11797     callback: yourFunction,<br/>
11798     scope: yourObject, //(optional scope)  <br/>
11799     discardUrl: false, <br/>
11800     nocache: false,<br/>
11801     text: "Loading...",<br/>
11802     timeout: 30,<br/>
11803     scripts: false<br/>
11804 });
11805 </code></pre>
11806      * The only required property is url. The optional properties nocache, text and scripts
11807      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11808      * @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}
11809      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11810      * @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.
11811      */
11812     update : function(url, params, callback, discardUrl){
11813         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11814             var method = this.method,
11815                 cfg;
11816             if(typeof url == "object"){ // must be config object
11817                 cfg = url;
11818                 url = cfg.url;
11819                 params = params || cfg.params;
11820                 callback = callback || cfg.callback;
11821                 discardUrl = discardUrl || cfg.discardUrl;
11822                 if(callback && cfg.scope){
11823                     callback = callback.createDelegate(cfg.scope);
11824                 }
11825                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11826                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11827                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11828                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11829                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11830             }
11831             this.showLoading();
11832             if(!discardUrl){
11833                 this.defaultUrl = url;
11834             }
11835             if(typeof url == "function"){
11836                 url = url.call(this);
11837             }
11838
11839             method = method || (params ? "POST" : "GET");
11840             if(method == "GET"){
11841                 url = this.prepareUrl(url);
11842             }
11843
11844             var o = Roo.apply(cfg ||{}, {
11845                 url : url,
11846                 params: params,
11847                 success: this.successDelegate,
11848                 failure: this.failureDelegate,
11849                 callback: undefined,
11850                 timeout: (this.timeout*1000),
11851                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11852             });
11853             Roo.log("updated manager called with timeout of " + o.timeout);
11854             this.transaction = Roo.Ajax.request(o);
11855         }
11856     },
11857
11858     /**
11859      * 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.
11860      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11861      * @param {String/HTMLElement} form The form Id or form element
11862      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11863      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11864      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11865      */
11866     formUpdate : function(form, url, reset, callback){
11867         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11868             if(typeof url == "function"){
11869                 url = url.call(this);
11870             }
11871             form = Roo.getDom(form);
11872             this.transaction = Roo.Ajax.request({
11873                 form: form,
11874                 url:url,
11875                 success: this.successDelegate,
11876                 failure: this.failureDelegate,
11877                 timeout: (this.timeout*1000),
11878                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11879             });
11880             this.showLoading.defer(1, this);
11881         }
11882     },
11883
11884     /**
11885      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11886      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11887      */
11888     refresh : function(callback){
11889         if(this.defaultUrl == null){
11890             return;
11891         }
11892         this.update(this.defaultUrl, null, callback, true);
11893     },
11894
11895     /**
11896      * Set this element to auto refresh.
11897      * @param {Number} interval How often to update (in seconds).
11898      * @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)
11899      * @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}
11900      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11901      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11902      */
11903     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11904         if(refreshNow){
11905             this.update(url || this.defaultUrl, params, callback, true);
11906         }
11907         if(this.autoRefreshProcId){
11908             clearInterval(this.autoRefreshProcId);
11909         }
11910         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11911     },
11912
11913     /**
11914      * Stop auto refresh on this element.
11915      */
11916      stopAutoRefresh : function(){
11917         if(this.autoRefreshProcId){
11918             clearInterval(this.autoRefreshProcId);
11919             delete this.autoRefreshProcId;
11920         }
11921     },
11922
11923     isAutoRefreshing : function(){
11924        return this.autoRefreshProcId ? true : false;
11925     },
11926     /**
11927      * Called to update the element to "Loading" state. Override to perform custom action.
11928      */
11929     showLoading : function(){
11930         if(this.showLoadIndicator){
11931             this.el.update(this.indicatorText);
11932         }
11933     },
11934
11935     /**
11936      * Adds unique parameter to query string if disableCaching = true
11937      * @private
11938      */
11939     prepareUrl : function(url){
11940         if(this.disableCaching){
11941             var append = "_dc=" + (new Date().getTime());
11942             if(url.indexOf("?") !== -1){
11943                 url += "&" + append;
11944             }else{
11945                 url += "?" + append;
11946             }
11947         }
11948         return url;
11949     },
11950
11951     /**
11952      * @private
11953      */
11954     processSuccess : function(response){
11955         this.transaction = null;
11956         if(response.argument.form && response.argument.reset){
11957             try{ // put in try/catch since some older FF releases had problems with this
11958                 response.argument.form.reset();
11959             }catch(e){}
11960         }
11961         if(this.loadScripts){
11962             this.renderer.render(this.el, response, this,
11963                 this.updateComplete.createDelegate(this, [response]));
11964         }else{
11965             this.renderer.render(this.el, response, this);
11966             this.updateComplete(response);
11967         }
11968     },
11969
11970     updateComplete : function(response){
11971         this.fireEvent("update", this.el, response);
11972         if(typeof response.argument.callback == "function"){
11973             response.argument.callback(this.el, true, response);
11974         }
11975     },
11976
11977     /**
11978      * @private
11979      */
11980     processFailure : function(response){
11981         this.transaction = null;
11982         this.fireEvent("failure", this.el, response);
11983         if(typeof response.argument.callback == "function"){
11984             response.argument.callback(this.el, false, response);
11985         }
11986     },
11987
11988     /**
11989      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11990      * @param {Object} renderer The object implementing the render() method
11991      */
11992     setRenderer : function(renderer){
11993         this.renderer = renderer;
11994     },
11995
11996     getRenderer : function(){
11997        return this.renderer;
11998     },
11999
12000     /**
12001      * Set the defaultUrl used for updates
12002      * @param {String/Function} defaultUrl The url or a function to call to get the url
12003      */
12004     setDefaultUrl : function(defaultUrl){
12005         this.defaultUrl = defaultUrl;
12006     },
12007
12008     /**
12009      * Aborts the executing transaction
12010      */
12011     abort : function(){
12012         if(this.transaction){
12013             Roo.Ajax.abort(this.transaction);
12014         }
12015     },
12016
12017     /**
12018      * Returns true if an update is in progress
12019      * @return {Boolean}
12020      */
12021     isUpdating : function(){
12022         if(this.transaction){
12023             return Roo.Ajax.isLoading(this.transaction);
12024         }
12025         return false;
12026     }
12027 });
12028
12029 /**
12030  * @class Roo.UpdateManager.defaults
12031  * @static (not really - but it helps the doc tool)
12032  * The defaults collection enables customizing the default properties of UpdateManager
12033  */
12034    Roo.UpdateManager.defaults = {
12035        /**
12036          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12037          * @type Number
12038          */
12039          timeout : 30,
12040
12041          /**
12042          * True to process scripts by default (Defaults to false).
12043          * @type Boolean
12044          */
12045         loadScripts : false,
12046
12047         /**
12048         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12049         * @type String
12050         */
12051         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12052         /**
12053          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12054          * @type Boolean
12055          */
12056         disableCaching : false,
12057         /**
12058          * Whether to show indicatorText when loading (Defaults to true).
12059          * @type Boolean
12060          */
12061         showLoadIndicator : true,
12062         /**
12063          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12064          * @type String
12065          */
12066         indicatorText : '<div class="loading-indicator">Loading...</div>'
12067    };
12068
12069 /**
12070  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12071  *Usage:
12072  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12073  * @param {String/HTMLElement/Roo.Element} el The element to update
12074  * @param {String} url The url
12075  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12076  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12077  * @static
12078  * @deprecated
12079  * @member Roo.UpdateManager
12080  */
12081 Roo.UpdateManager.updateElement = function(el, url, params, options){
12082     var um = Roo.get(el, true).getUpdateManager();
12083     Roo.apply(um, options);
12084     um.update(url, params, options ? options.callback : null);
12085 };
12086 // alias for backwards compat
12087 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12088 /**
12089  * @class Roo.UpdateManager.BasicRenderer
12090  * Default Content renderer. Updates the elements innerHTML with the responseText.
12091  */
12092 Roo.UpdateManager.BasicRenderer = function(){};
12093
12094 Roo.UpdateManager.BasicRenderer.prototype = {
12095     /**
12096      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12097      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12098      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12099      * @param {Roo.Element} el The element being rendered
12100      * @param {Object} response The YUI Connect response object
12101      * @param {UpdateManager} updateManager The calling update manager
12102      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12103      */
12104      render : function(el, response, updateManager, callback){
12105         el.update(response.responseText, updateManager.loadScripts, callback);
12106     }
12107 };
12108 /*
12109  * Based on:
12110  * Roo JS
12111  * (c)) Alan Knowles
12112  * Licence : LGPL
12113  */
12114
12115
12116 /**
12117  * @class Roo.DomTemplate
12118  * @extends Roo.Template
12119  * An effort at a dom based template engine..
12120  *
12121  * Similar to XTemplate, except it uses dom parsing to create the template..
12122  *
12123  * Supported features:
12124  *
12125  *  Tags:
12126
12127 <pre><code>
12128       {a_variable} - output encoded.
12129       {a_variable.format:("Y-m-d")} - call a method on the variable
12130       {a_variable:raw} - unencoded output
12131       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12132       {a_variable:this.method_on_template(...)} - call a method on the template object.
12133  
12134 </code></pre>
12135  *  The tpl tag:
12136 <pre><code>
12137         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12138         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12139         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12140         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12141   
12142 </code></pre>
12143  *      
12144  */
12145 Roo.DomTemplate = function()
12146 {
12147      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12148      if (this.html) {
12149         this.compile();
12150      }
12151 };
12152
12153
12154 Roo.extend(Roo.DomTemplate, Roo.Template, {
12155     /**
12156      * id counter for sub templates.
12157      */
12158     id : 0,
12159     /**
12160      * flag to indicate if dom parser is inside a pre,
12161      * it will strip whitespace if not.
12162      */
12163     inPre : false,
12164     
12165     /**
12166      * The various sub templates
12167      */
12168     tpls : false,
12169     
12170     
12171     
12172     /**
12173      *
12174      * basic tag replacing syntax
12175      * WORD:WORD()
12176      *
12177      * // you can fake an object call by doing this
12178      *  x.t:(test,tesT) 
12179      * 
12180      */
12181     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12182     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12183     
12184     iterChild : function (node, method) {
12185         
12186         var oldPre = this.inPre;
12187         if (node.tagName == 'PRE') {
12188             this.inPre = true;
12189         }
12190         for( var i = 0; i < node.childNodes.length; i++) {
12191             method.call(this, node.childNodes[i]);
12192         }
12193         this.inPre = oldPre;
12194     },
12195     
12196     
12197     
12198     /**
12199      * compile the template
12200      *
12201      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12202      *
12203      */
12204     compile: function()
12205     {
12206         var s = this.html;
12207         
12208         // covert the html into DOM...
12209         var doc = false;
12210         var div =false;
12211         try {
12212             doc = document.implementation.createHTMLDocument("");
12213             doc.documentElement.innerHTML =   this.html  ;
12214             div = doc.documentElement;
12215         } catch (e) {
12216             // old IE... - nasty -- it causes all sorts of issues.. with
12217             // images getting pulled from server..
12218             div = document.createElement('div');
12219             div.innerHTML = this.html;
12220         }
12221         //doc.documentElement.innerHTML = htmlBody
12222          
12223         
12224         
12225         this.tpls = [];
12226         var _t = this;
12227         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12228         
12229         var tpls = this.tpls;
12230         
12231         // create a top level template from the snippet..
12232         
12233         //Roo.log(div.innerHTML);
12234         
12235         var tpl = {
12236             uid : 'master',
12237             id : this.id++,
12238             attr : false,
12239             value : false,
12240             body : div.innerHTML,
12241             
12242             forCall : false,
12243             execCall : false,
12244             dom : div,
12245             isTop : true
12246             
12247         };
12248         tpls.unshift(tpl);
12249         
12250         
12251         // compile them...
12252         this.tpls = [];
12253         Roo.each(tpls, function(tp){
12254             this.compileTpl(tp);
12255             this.tpls[tp.id] = tp;
12256         }, this);
12257         
12258         this.master = tpls[0];
12259         return this;
12260         
12261         
12262     },
12263     
12264     compileNode : function(node, istop) {
12265         // test for
12266         //Roo.log(node);
12267         
12268         
12269         // skip anything not a tag..
12270         if (node.nodeType != 1) {
12271             if (node.nodeType == 3 && !this.inPre) {
12272                 // reduce white space..
12273                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12274                 
12275             }
12276             return;
12277         }
12278         
12279         var tpl = {
12280             uid : false,
12281             id : false,
12282             attr : false,
12283             value : false,
12284             body : '',
12285             
12286             forCall : false,
12287             execCall : false,
12288             dom : false,
12289             isTop : istop
12290             
12291             
12292         };
12293         
12294         
12295         switch(true) {
12296             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12297             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12298             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12299             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12300             // no default..
12301         }
12302         
12303         
12304         if (!tpl.attr) {
12305             // just itterate children..
12306             this.iterChild(node,this.compileNode);
12307             return;
12308         }
12309         tpl.uid = this.id++;
12310         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12311         node.removeAttribute('roo-'+ tpl.attr);
12312         if (tpl.attr != 'name') {
12313             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12314             node.parentNode.replaceChild(placeholder,  node);
12315         } else {
12316             
12317             var placeholder =  document.createElement('span');
12318             placeholder.className = 'roo-tpl-' + tpl.value;
12319             node.parentNode.replaceChild(placeholder,  node);
12320         }
12321         
12322         // parent now sees '{domtplXXXX}
12323         this.iterChild(node,this.compileNode);
12324         
12325         // we should now have node body...
12326         var div = document.createElement('div');
12327         div.appendChild(node);
12328         tpl.dom = node;
12329         // this has the unfortunate side effect of converting tagged attributes
12330         // eg. href="{...}" into %7C...%7D
12331         // this has been fixed by searching for those combo's although it's a bit hacky..
12332         
12333         
12334         tpl.body = div.innerHTML;
12335         
12336         
12337          
12338         tpl.id = tpl.uid;
12339         switch(tpl.attr) {
12340             case 'for' :
12341                 switch (tpl.value) {
12342                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12343                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12344                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12345                 }
12346                 break;
12347             
12348             case 'exec':
12349                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12350                 break;
12351             
12352             case 'if':     
12353                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12354                 break;
12355             
12356             case 'name':
12357                 tpl.id  = tpl.value; // replace non characters???
12358                 break;
12359             
12360         }
12361         
12362         
12363         this.tpls.push(tpl);
12364         
12365         
12366         
12367     },
12368     
12369     
12370     
12371     
12372     /**
12373      * Compile a segment of the template into a 'sub-template'
12374      *
12375      * 
12376      * 
12377      *
12378      */
12379     compileTpl : function(tpl)
12380     {
12381         var fm = Roo.util.Format;
12382         var useF = this.disableFormats !== true;
12383         
12384         var sep = Roo.isGecko ? "+\n" : ",\n";
12385         
12386         var undef = function(str) {
12387             Roo.debug && Roo.log("Property not found :"  + str);
12388             return '';
12389         };
12390           
12391         //Roo.log(tpl.body);
12392         
12393         
12394         
12395         var fn = function(m, lbrace, name, format, args)
12396         {
12397             //Roo.log("ARGS");
12398             //Roo.log(arguments);
12399             args = args ? args.replace(/\\'/g,"'") : args;
12400             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12401             if (typeof(format) == 'undefined') {
12402                 format =  'htmlEncode'; 
12403             }
12404             if (format == 'raw' ) {
12405                 format = false;
12406             }
12407             
12408             if(name.substr(0, 6) == 'domtpl'){
12409                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12410             }
12411             
12412             // build an array of options to determine if value is undefined..
12413             
12414             // basically get 'xxxx.yyyy' then do
12415             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12416             //    (function () { Roo.log("Property not found"); return ''; })() :
12417             //    ......
12418             
12419             var udef_ar = [];
12420             var lookfor = '';
12421             Roo.each(name.split('.'), function(st) {
12422                 lookfor += (lookfor.length ? '.': '') + st;
12423                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12424             });
12425             
12426             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12427             
12428             
12429             if(format && useF){
12430                 
12431                 args = args ? ',' + args : "";
12432                  
12433                 if(format.substr(0, 5) != "this."){
12434                     format = "fm." + format + '(';
12435                 }else{
12436                     format = 'this.call("'+ format.substr(5) + '", ';
12437                     args = ", values";
12438                 }
12439                 
12440                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12441             }
12442              
12443             if (args && args.length) {
12444                 // called with xxyx.yuu:(test,test)
12445                 // change to ()
12446                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12447             }
12448             // raw.. - :raw modifier..
12449             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12450             
12451         };
12452         var body;
12453         // branched to use + in gecko and [].join() in others
12454         if(Roo.isGecko){
12455             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12456                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12457                     "';};};";
12458         }else{
12459             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12460             body.push(tpl.body.replace(/(\r\n|\n)/g,
12461                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12462             body.push("'].join('');};};");
12463             body = body.join('');
12464         }
12465         
12466         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12467        
12468         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12469         eval(body);
12470         
12471         return this;
12472     },
12473      
12474     /**
12475      * same as applyTemplate, except it's done to one of the subTemplates
12476      * when using named templates, you can do:
12477      *
12478      * var str = pl.applySubTemplate('your-name', values);
12479      *
12480      * 
12481      * @param {Number} id of the template
12482      * @param {Object} values to apply to template
12483      * @param {Object} parent (normaly the instance of this object)
12484      */
12485     applySubTemplate : function(id, values, parent)
12486     {
12487         
12488         
12489         var t = this.tpls[id];
12490         
12491         
12492         try { 
12493             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12494                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12495                 return '';
12496             }
12497         } catch(e) {
12498             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12499             Roo.log(values);
12500           
12501             return '';
12502         }
12503         try { 
12504             
12505             if(t.execCall && t.execCall.call(this, values, parent)){
12506                 return '';
12507             }
12508         } catch(e) {
12509             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12510             Roo.log(values);
12511             return '';
12512         }
12513         
12514         try {
12515             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12516             parent = t.target ? values : parent;
12517             if(t.forCall && vs instanceof Array){
12518                 var buf = [];
12519                 for(var i = 0, len = vs.length; i < len; i++){
12520                     try {
12521                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12522                     } catch (e) {
12523                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12524                         Roo.log(e.body);
12525                         //Roo.log(t.compiled);
12526                         Roo.log(vs[i]);
12527                     }   
12528                 }
12529                 return buf.join('');
12530             }
12531         } catch (e) {
12532             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12533             Roo.log(values);
12534             return '';
12535         }
12536         try {
12537             return t.compiled.call(this, vs, parent);
12538         } catch (e) {
12539             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12540             Roo.log(e.body);
12541             //Roo.log(t.compiled);
12542             Roo.log(values);
12543             return '';
12544         }
12545     },
12546
12547    
12548
12549     applyTemplate : function(values){
12550         return this.master.compiled.call(this, values, {});
12551         //var s = this.subs;
12552     },
12553
12554     apply : function(){
12555         return this.applyTemplate.apply(this, arguments);
12556     }
12557
12558  });
12559
12560 Roo.DomTemplate.from = function(el){
12561     el = Roo.getDom(el);
12562     return new Roo.Domtemplate(el.value || el.innerHTML);
12563 };/*
12564  * Based on:
12565  * Ext JS Library 1.1.1
12566  * Copyright(c) 2006-2007, Ext JS, LLC.
12567  *
12568  * Originally Released Under LGPL - original licence link has changed is not relivant.
12569  *
12570  * Fork - LGPL
12571  * <script type="text/javascript">
12572  */
12573
12574 /**
12575  * @class Roo.util.DelayedTask
12576  * Provides a convenient method of performing setTimeout where a new
12577  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12578  * You can use this class to buffer
12579  * the keypress events for a certain number of milliseconds, and perform only if they stop
12580  * for that amount of time.
12581  * @constructor The parameters to this constructor serve as defaults and are not required.
12582  * @param {Function} fn (optional) The default function to timeout
12583  * @param {Object} scope (optional) The default scope of that timeout
12584  * @param {Array} args (optional) The default Array of arguments
12585  */
12586 Roo.util.DelayedTask = function(fn, scope, args){
12587     var id = null, d, t;
12588
12589     var call = function(){
12590         var now = new Date().getTime();
12591         if(now - t >= d){
12592             clearInterval(id);
12593             id = null;
12594             fn.apply(scope, args || []);
12595         }
12596     };
12597     /**
12598      * Cancels any pending timeout and queues a new one
12599      * @param {Number} delay The milliseconds to delay
12600      * @param {Function} newFn (optional) Overrides function passed to constructor
12601      * @param {Object} newScope (optional) Overrides scope passed to constructor
12602      * @param {Array} newArgs (optional) Overrides args passed to constructor
12603      */
12604     this.delay = function(delay, newFn, newScope, newArgs){
12605         if(id && delay != d){
12606             this.cancel();
12607         }
12608         d = delay;
12609         t = new Date().getTime();
12610         fn = newFn || fn;
12611         scope = newScope || scope;
12612         args = newArgs || args;
12613         if(!id){
12614             id = setInterval(call, d);
12615         }
12616     };
12617
12618     /**
12619      * Cancel the last queued timeout
12620      */
12621     this.cancel = function(){
12622         if(id){
12623             clearInterval(id);
12624             id = null;
12625         }
12626     };
12627 };/*
12628  * Based on:
12629  * Ext JS Library 1.1.1
12630  * Copyright(c) 2006-2007, Ext JS, LLC.
12631  *
12632  * Originally Released Under LGPL - original licence link has changed is not relivant.
12633  *
12634  * Fork - LGPL
12635  * <script type="text/javascript">
12636  */
12637  
12638  
12639 Roo.util.TaskRunner = function(interval){
12640     interval = interval || 10;
12641     var tasks = [], removeQueue = [];
12642     var id = 0;
12643     var running = false;
12644
12645     var stopThread = function(){
12646         running = false;
12647         clearInterval(id);
12648         id = 0;
12649     };
12650
12651     var startThread = function(){
12652         if(!running){
12653             running = true;
12654             id = setInterval(runTasks, interval);
12655         }
12656     };
12657
12658     var removeTask = function(task){
12659         removeQueue.push(task);
12660         if(task.onStop){
12661             task.onStop();
12662         }
12663     };
12664
12665     var runTasks = function(){
12666         if(removeQueue.length > 0){
12667             for(var i = 0, len = removeQueue.length; i < len; i++){
12668                 tasks.remove(removeQueue[i]);
12669             }
12670             removeQueue = [];
12671             if(tasks.length < 1){
12672                 stopThread();
12673                 return;
12674             }
12675         }
12676         var now = new Date().getTime();
12677         for(var i = 0, len = tasks.length; i < len; ++i){
12678             var t = tasks[i];
12679             var itime = now - t.taskRunTime;
12680             if(t.interval <= itime){
12681                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12682                 t.taskRunTime = now;
12683                 if(rt === false || t.taskRunCount === t.repeat){
12684                     removeTask(t);
12685                     return;
12686                 }
12687             }
12688             if(t.duration && t.duration <= (now - t.taskStartTime)){
12689                 removeTask(t);
12690             }
12691         }
12692     };
12693
12694     /**
12695      * Queues a new task.
12696      * @param {Object} task
12697      */
12698     this.start = function(task){
12699         tasks.push(task);
12700         task.taskStartTime = new Date().getTime();
12701         task.taskRunTime = 0;
12702         task.taskRunCount = 0;
12703         startThread();
12704         return task;
12705     };
12706
12707     this.stop = function(task){
12708         removeTask(task);
12709         return task;
12710     };
12711
12712     this.stopAll = function(){
12713         stopThread();
12714         for(var i = 0, len = tasks.length; i < len; i++){
12715             if(tasks[i].onStop){
12716                 tasks[i].onStop();
12717             }
12718         }
12719         tasks = [];
12720         removeQueue = [];
12721     };
12722 };
12723
12724 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12725  * Based on:
12726  * Ext JS Library 1.1.1
12727  * Copyright(c) 2006-2007, Ext JS, LLC.
12728  *
12729  * Originally Released Under LGPL - original licence link has changed is not relivant.
12730  *
12731  * Fork - LGPL
12732  * <script type="text/javascript">
12733  */
12734
12735  
12736 /**
12737  * @class Roo.util.MixedCollection
12738  * @extends Roo.util.Observable
12739  * A Collection class that maintains both numeric indexes and keys and exposes events.
12740  * @constructor
12741  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12742  * collection (defaults to false)
12743  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12744  * and return the key value for that item.  This is used when available to look up the key on items that
12745  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12746  * equivalent to providing an implementation for the {@link #getKey} method.
12747  */
12748 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12749     this.items = [];
12750     this.map = {};
12751     this.keys = [];
12752     this.length = 0;
12753     this.addEvents({
12754         /**
12755          * @event clear
12756          * Fires when the collection is cleared.
12757          */
12758         "clear" : true,
12759         /**
12760          * @event add
12761          * Fires when an item is added to the collection.
12762          * @param {Number} index The index at which the item was added.
12763          * @param {Object} o The item added.
12764          * @param {String} key The key associated with the added item.
12765          */
12766         "add" : true,
12767         /**
12768          * @event replace
12769          * Fires when an item is replaced in the collection.
12770          * @param {String} key he key associated with the new added.
12771          * @param {Object} old The item being replaced.
12772          * @param {Object} new The new item.
12773          */
12774         "replace" : true,
12775         /**
12776          * @event remove
12777          * Fires when an item is removed from the collection.
12778          * @param {Object} o The item being removed.
12779          * @param {String} key (optional) The key associated with the removed item.
12780          */
12781         "remove" : true,
12782         "sort" : true
12783     });
12784     this.allowFunctions = allowFunctions === true;
12785     if(keyFn){
12786         this.getKey = keyFn;
12787     }
12788     Roo.util.MixedCollection.superclass.constructor.call(this);
12789 };
12790
12791 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12792     allowFunctions : false,
12793     
12794 /**
12795  * Adds an item to the collection.
12796  * @param {String} key The key to associate with the item
12797  * @param {Object} o The item to add.
12798  * @return {Object} The item added.
12799  */
12800     add : function(key, o){
12801         if(arguments.length == 1){
12802             o = arguments[0];
12803             key = this.getKey(o);
12804         }
12805         if(typeof key == "undefined" || key === null){
12806             this.length++;
12807             this.items.push(o);
12808             this.keys.push(null);
12809         }else{
12810             var old = this.map[key];
12811             if(old){
12812                 return this.replace(key, o);
12813             }
12814             this.length++;
12815             this.items.push(o);
12816             this.map[key] = o;
12817             this.keys.push(key);
12818         }
12819         this.fireEvent("add", this.length-1, o, key);
12820         return o;
12821     },
12822        
12823 /**
12824   * MixedCollection has a generic way to fetch keys if you implement getKey.
12825 <pre><code>
12826 // normal way
12827 var mc = new Roo.util.MixedCollection();
12828 mc.add(someEl.dom.id, someEl);
12829 mc.add(otherEl.dom.id, otherEl);
12830 //and so on
12831
12832 // using getKey
12833 var mc = new Roo.util.MixedCollection();
12834 mc.getKey = function(el){
12835    return el.dom.id;
12836 };
12837 mc.add(someEl);
12838 mc.add(otherEl);
12839
12840 // or via the constructor
12841 var mc = new Roo.util.MixedCollection(false, function(el){
12842    return el.dom.id;
12843 });
12844 mc.add(someEl);
12845 mc.add(otherEl);
12846 </code></pre>
12847  * @param o {Object} The item for which to find the key.
12848  * @return {Object} The key for the passed item.
12849  */
12850     getKey : function(o){
12851          return o.id; 
12852     },
12853    
12854 /**
12855  * Replaces an item in the collection.
12856  * @param {String} key The key associated with the item to replace, or the item to replace.
12857  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12858  * @return {Object}  The new item.
12859  */
12860     replace : function(key, o){
12861         if(arguments.length == 1){
12862             o = arguments[0];
12863             key = this.getKey(o);
12864         }
12865         var old = this.item(key);
12866         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12867              return this.add(key, o);
12868         }
12869         var index = this.indexOfKey(key);
12870         this.items[index] = o;
12871         this.map[key] = o;
12872         this.fireEvent("replace", key, old, o);
12873         return o;
12874     },
12875    
12876 /**
12877  * Adds all elements of an Array or an Object to the collection.
12878  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12879  * an Array of values, each of which are added to the collection.
12880  */
12881     addAll : function(objs){
12882         if(arguments.length > 1 || objs instanceof Array){
12883             var args = arguments.length > 1 ? arguments : objs;
12884             for(var i = 0, len = args.length; i < len; i++){
12885                 this.add(args[i]);
12886             }
12887         }else{
12888             for(var key in objs){
12889                 if(this.allowFunctions || typeof objs[key] != "function"){
12890                     this.add(key, objs[key]);
12891                 }
12892             }
12893         }
12894     },
12895    
12896 /**
12897  * Executes the specified function once for every item in the collection, passing each
12898  * item as the first and only parameter. returning false from the function will stop the iteration.
12899  * @param {Function} fn The function to execute for each item.
12900  * @param {Object} scope (optional) The scope in which to execute the function.
12901  */
12902     each : function(fn, scope){
12903         var items = [].concat(this.items); // each safe for removal
12904         for(var i = 0, len = items.length; i < len; i++){
12905             if(fn.call(scope || items[i], items[i], i, len) === false){
12906                 break;
12907             }
12908         }
12909     },
12910    
12911 /**
12912  * Executes the specified function once for every key in the collection, passing each
12913  * key, and its associated item as the first two parameters.
12914  * @param {Function} fn The function to execute for each item.
12915  * @param {Object} scope (optional) The scope in which to execute the function.
12916  */
12917     eachKey : function(fn, scope){
12918         for(var i = 0, len = this.keys.length; i < len; i++){
12919             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12920         }
12921     },
12922    
12923 /**
12924  * Returns the first item in the collection which elicits a true return value from the
12925  * passed selection function.
12926  * @param {Function} fn The selection function to execute for each item.
12927  * @param {Object} scope (optional) The scope in which to execute the function.
12928  * @return {Object} The first item in the collection which returned true from the selection function.
12929  */
12930     find : function(fn, scope){
12931         for(var i = 0, len = this.items.length; i < len; i++){
12932             if(fn.call(scope || window, this.items[i], this.keys[i])){
12933                 return this.items[i];
12934             }
12935         }
12936         return null;
12937     },
12938    
12939 /**
12940  * Inserts an item at the specified index in the collection.
12941  * @param {Number} index The index to insert the item at.
12942  * @param {String} key The key to associate with the new item, or the item itself.
12943  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12944  * @return {Object} The item inserted.
12945  */
12946     insert : function(index, key, o){
12947         if(arguments.length == 2){
12948             o = arguments[1];
12949             key = this.getKey(o);
12950         }
12951         if(index >= this.length){
12952             return this.add(key, o);
12953         }
12954         this.length++;
12955         this.items.splice(index, 0, o);
12956         if(typeof key != "undefined" && key != null){
12957             this.map[key] = o;
12958         }
12959         this.keys.splice(index, 0, key);
12960         this.fireEvent("add", index, o, key);
12961         return o;
12962     },
12963    
12964 /**
12965  * Removed an item from the collection.
12966  * @param {Object} o The item to remove.
12967  * @return {Object} The item removed.
12968  */
12969     remove : function(o){
12970         return this.removeAt(this.indexOf(o));
12971     },
12972    
12973 /**
12974  * Remove an item from a specified index in the collection.
12975  * @param {Number} index The index within the collection of the item to remove.
12976  */
12977     removeAt : function(index){
12978         if(index < this.length && index >= 0){
12979             this.length--;
12980             var o = this.items[index];
12981             this.items.splice(index, 1);
12982             var key = this.keys[index];
12983             if(typeof key != "undefined"){
12984                 delete this.map[key];
12985             }
12986             this.keys.splice(index, 1);
12987             this.fireEvent("remove", o, key);
12988         }
12989     },
12990    
12991 /**
12992  * Removed an item associated with the passed key fom the collection.
12993  * @param {String} key The key of the item to remove.
12994  */
12995     removeKey : function(key){
12996         return this.removeAt(this.indexOfKey(key));
12997     },
12998    
12999 /**
13000  * Returns the number of items in the collection.
13001  * @return {Number} the number of items in the collection.
13002  */
13003     getCount : function(){
13004         return this.length; 
13005     },
13006    
13007 /**
13008  * Returns index within the collection of the passed Object.
13009  * @param {Object} o The item to find the index of.
13010  * @return {Number} index of the item.
13011  */
13012     indexOf : function(o){
13013         if(!this.items.indexOf){
13014             for(var i = 0, len = this.items.length; i < len; i++){
13015                 if(this.items[i] == o) return i;
13016             }
13017             return -1;
13018         }else{
13019             return this.items.indexOf(o);
13020         }
13021     },
13022    
13023 /**
13024  * Returns index within the collection of the passed key.
13025  * @param {String} key The key to find the index of.
13026  * @return {Number} index of the key.
13027  */
13028     indexOfKey : function(key){
13029         if(!this.keys.indexOf){
13030             for(var i = 0, len = this.keys.length; i < len; i++){
13031                 if(this.keys[i] == key) return i;
13032             }
13033             return -1;
13034         }else{
13035             return this.keys.indexOf(key);
13036         }
13037     },
13038    
13039 /**
13040  * Returns the item associated with the passed key OR index. Key has priority over index.
13041  * @param {String/Number} key The key or index of the item.
13042  * @return {Object} The item associated with the passed key.
13043  */
13044     item : function(key){
13045         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13046         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13047     },
13048     
13049 /**
13050  * Returns the item at the specified index.
13051  * @param {Number} index The index of the item.
13052  * @return {Object}
13053  */
13054     itemAt : function(index){
13055         return this.items[index];
13056     },
13057     
13058 /**
13059  * Returns the item associated with the passed key.
13060  * @param {String/Number} key The key of the item.
13061  * @return {Object} The item associated with the passed key.
13062  */
13063     key : function(key){
13064         return this.map[key];
13065     },
13066    
13067 /**
13068  * Returns true if the collection contains the passed Object as an item.
13069  * @param {Object} o  The Object to look for in the collection.
13070  * @return {Boolean} True if the collection contains the Object as an item.
13071  */
13072     contains : function(o){
13073         return this.indexOf(o) != -1;
13074     },
13075    
13076 /**
13077  * Returns true if the collection contains the passed Object as a key.
13078  * @param {String} key The key to look for in the collection.
13079  * @return {Boolean} True if the collection contains the Object as a key.
13080  */
13081     containsKey : function(key){
13082         return typeof this.map[key] != "undefined";
13083     },
13084    
13085 /**
13086  * Removes all items from the collection.
13087  */
13088     clear : function(){
13089         this.length = 0;
13090         this.items = [];
13091         this.keys = [];
13092         this.map = {};
13093         this.fireEvent("clear");
13094     },
13095    
13096 /**
13097  * Returns the first item in the collection.
13098  * @return {Object} the first item in the collection..
13099  */
13100     first : function(){
13101         return this.items[0]; 
13102     },
13103    
13104 /**
13105  * Returns the last item in the collection.
13106  * @return {Object} the last item in the collection..
13107  */
13108     last : function(){
13109         return this.items[this.length-1];   
13110     },
13111     
13112     _sort : function(property, dir, fn){
13113         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13114         fn = fn || function(a, b){
13115             return a-b;
13116         };
13117         var c = [], k = this.keys, items = this.items;
13118         for(var i = 0, len = items.length; i < len; i++){
13119             c[c.length] = {key: k[i], value: items[i], index: i};
13120         }
13121         c.sort(function(a, b){
13122             var v = fn(a[property], b[property]) * dsc;
13123             if(v == 0){
13124                 v = (a.index < b.index ? -1 : 1);
13125             }
13126             return v;
13127         });
13128         for(var i = 0, len = c.length; i < len; i++){
13129             items[i] = c[i].value;
13130             k[i] = c[i].key;
13131         }
13132         this.fireEvent("sort", this);
13133     },
13134     
13135     /**
13136      * Sorts this collection with the passed comparison function
13137      * @param {String} direction (optional) "ASC" or "DESC"
13138      * @param {Function} fn (optional) comparison function
13139      */
13140     sort : function(dir, fn){
13141         this._sort("value", dir, fn);
13142     },
13143     
13144     /**
13145      * Sorts this collection by keys
13146      * @param {String} direction (optional) "ASC" or "DESC"
13147      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13148      */
13149     keySort : function(dir, fn){
13150         this._sort("key", dir, fn || function(a, b){
13151             return String(a).toUpperCase()-String(b).toUpperCase();
13152         });
13153     },
13154     
13155     /**
13156      * Returns a range of items in this collection
13157      * @param {Number} startIndex (optional) defaults to 0
13158      * @param {Number} endIndex (optional) default to the last item
13159      * @return {Array} An array of items
13160      */
13161     getRange : function(start, end){
13162         var items = this.items;
13163         if(items.length < 1){
13164             return [];
13165         }
13166         start = start || 0;
13167         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13168         var r = [];
13169         if(start <= end){
13170             for(var i = start; i <= end; i++) {
13171                     r[r.length] = items[i];
13172             }
13173         }else{
13174             for(var i = start; i >= end; i--) {
13175                     r[r.length] = items[i];
13176             }
13177         }
13178         return r;
13179     },
13180         
13181     /**
13182      * Filter the <i>objects</i> in this collection by a specific property. 
13183      * Returns a new collection that has been filtered.
13184      * @param {String} property A property on your objects
13185      * @param {String/RegExp} value Either string that the property values 
13186      * should start with or a RegExp to test against the property
13187      * @return {MixedCollection} The new filtered collection
13188      */
13189     filter : function(property, value){
13190         if(!value.exec){ // not a regex
13191             value = String(value);
13192             if(value.length == 0){
13193                 return this.clone();
13194             }
13195             value = new RegExp("^" + Roo.escapeRe(value), "i");
13196         }
13197         return this.filterBy(function(o){
13198             return o && value.test(o[property]);
13199         });
13200         },
13201     
13202     /**
13203      * Filter by a function. * Returns a new collection that has been filtered.
13204      * The passed function will be called with each 
13205      * object in the collection. If the function returns true, the value is included 
13206      * otherwise it is filtered.
13207      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13208      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13209      * @return {MixedCollection} The new filtered collection
13210      */
13211     filterBy : function(fn, scope){
13212         var r = new Roo.util.MixedCollection();
13213         r.getKey = this.getKey;
13214         var k = this.keys, it = this.items;
13215         for(var i = 0, len = it.length; i < len; i++){
13216             if(fn.call(scope||this, it[i], k[i])){
13217                                 r.add(k[i], it[i]);
13218                         }
13219         }
13220         return r;
13221     },
13222     
13223     /**
13224      * Creates a duplicate of this collection
13225      * @return {MixedCollection}
13226      */
13227     clone : function(){
13228         var r = new Roo.util.MixedCollection();
13229         var k = this.keys, it = this.items;
13230         for(var i = 0, len = it.length; i < len; i++){
13231             r.add(k[i], it[i]);
13232         }
13233         r.getKey = this.getKey;
13234         return r;
13235     }
13236 });
13237 /**
13238  * Returns the item associated with the passed key or index.
13239  * @method
13240  * @param {String/Number} key The key or index of the item.
13241  * @return {Object} The item associated with the passed key.
13242  */
13243 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13244  * Based on:
13245  * Ext JS Library 1.1.1
13246  * Copyright(c) 2006-2007, Ext JS, LLC.
13247  *
13248  * Originally Released Under LGPL - original licence link has changed is not relivant.
13249  *
13250  * Fork - LGPL
13251  * <script type="text/javascript">
13252  */
13253 /**
13254  * @class Roo.util.JSON
13255  * Modified version of Douglas Crockford"s json.js that doesn"t
13256  * mess with the Object prototype 
13257  * http://www.json.org/js.html
13258  * @singleton
13259  */
13260 Roo.util.JSON = new (function(){
13261     var useHasOwn = {}.hasOwnProperty ? true : false;
13262     
13263     // crashes Safari in some instances
13264     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13265     
13266     var pad = function(n) {
13267         return n < 10 ? "0" + n : n;
13268     };
13269     
13270     var m = {
13271         "\b": '\\b',
13272         "\t": '\\t',
13273         "\n": '\\n',
13274         "\f": '\\f',
13275         "\r": '\\r',
13276         '"' : '\\"',
13277         "\\": '\\\\'
13278     };
13279
13280     var encodeString = function(s){
13281         if (/["\\\x00-\x1f]/.test(s)) {
13282             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13283                 var c = m[b];
13284                 if(c){
13285                     return c;
13286                 }
13287                 c = b.charCodeAt();
13288                 return "\\u00" +
13289                     Math.floor(c / 16).toString(16) +
13290                     (c % 16).toString(16);
13291             }) + '"';
13292         }
13293         return '"' + s + '"';
13294     };
13295     
13296     var encodeArray = function(o){
13297         var a = ["["], b, i, l = o.length, v;
13298             for (i = 0; i < l; i += 1) {
13299                 v = o[i];
13300                 switch (typeof v) {
13301                     case "undefined":
13302                     case "function":
13303                     case "unknown":
13304                         break;
13305                     default:
13306                         if (b) {
13307                             a.push(',');
13308                         }
13309                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13310                         b = true;
13311                 }
13312             }
13313             a.push("]");
13314             return a.join("");
13315     };
13316     
13317     var encodeDate = function(o){
13318         return '"' + o.getFullYear() + "-" +
13319                 pad(o.getMonth() + 1) + "-" +
13320                 pad(o.getDate()) + "T" +
13321                 pad(o.getHours()) + ":" +
13322                 pad(o.getMinutes()) + ":" +
13323                 pad(o.getSeconds()) + '"';
13324     };
13325     
13326     /**
13327      * Encodes an Object, Array or other value
13328      * @param {Mixed} o The variable to encode
13329      * @return {String} The JSON string
13330      */
13331     this.encode = function(o)
13332     {
13333         // should this be extended to fully wrap stringify..
13334         
13335         if(typeof o == "undefined" || o === null){
13336             return "null";
13337         }else if(o instanceof Array){
13338             return encodeArray(o);
13339         }else if(o instanceof Date){
13340             return encodeDate(o);
13341         }else if(typeof o == "string"){
13342             return encodeString(o);
13343         }else if(typeof o == "number"){
13344             return isFinite(o) ? String(o) : "null";
13345         }else if(typeof o == "boolean"){
13346             return String(o);
13347         }else {
13348             var a = ["{"], b, i, v;
13349             for (i in o) {
13350                 if(!useHasOwn || o.hasOwnProperty(i)) {
13351                     v = o[i];
13352                     switch (typeof v) {
13353                     case "undefined":
13354                     case "function":
13355                     case "unknown":
13356                         break;
13357                     default:
13358                         if(b){
13359                             a.push(',');
13360                         }
13361                         a.push(this.encode(i), ":",
13362                                 v === null ? "null" : this.encode(v));
13363                         b = true;
13364                     }
13365                 }
13366             }
13367             a.push("}");
13368             return a.join("");
13369         }
13370     };
13371     
13372     /**
13373      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13374      * @param {String} json The JSON string
13375      * @return {Object} The resulting object
13376      */
13377     this.decode = function(json){
13378         
13379         return  /** eval:var:json */ eval("(" + json + ')');
13380     };
13381 })();
13382 /** 
13383  * Shorthand for {@link Roo.util.JSON#encode}
13384  * @member Roo encode 
13385  * @method */
13386 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13387 /** 
13388  * Shorthand for {@link Roo.util.JSON#decode}
13389  * @member Roo decode 
13390  * @method */
13391 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13392 /*
13393  * Based on:
13394  * Ext JS Library 1.1.1
13395  * Copyright(c) 2006-2007, Ext JS, LLC.
13396  *
13397  * Originally Released Under LGPL - original licence link has changed is not relivant.
13398  *
13399  * Fork - LGPL
13400  * <script type="text/javascript">
13401  */
13402  
13403 /**
13404  * @class Roo.util.Format
13405  * Reusable data formatting functions
13406  * @singleton
13407  */
13408 Roo.util.Format = function(){
13409     var trimRe = /^\s+|\s+$/g;
13410     return {
13411         /**
13412          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13413          * @param {String} value The string to truncate
13414          * @param {Number} length The maximum length to allow before truncating
13415          * @return {String} The converted text
13416          */
13417         ellipsis : function(value, len){
13418             if(value && value.length > len){
13419                 return value.substr(0, len-3)+"...";
13420             }
13421             return value;
13422         },
13423
13424         /**
13425          * Checks a reference and converts it to empty string if it is undefined
13426          * @param {Mixed} value Reference to check
13427          * @return {Mixed} Empty string if converted, otherwise the original value
13428          */
13429         undef : function(value){
13430             return typeof value != "undefined" ? value : "";
13431         },
13432
13433         /**
13434          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13435          * @param {String} value The string to encode
13436          * @return {String} The encoded text
13437          */
13438         htmlEncode : function(value){
13439             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13440         },
13441
13442         /**
13443          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13444          * @param {String} value The string to decode
13445          * @return {String} The decoded text
13446          */
13447         htmlDecode : function(value){
13448             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13449         },
13450
13451         /**
13452          * Trims any whitespace from either side of a string
13453          * @param {String} value The text to trim
13454          * @return {String} The trimmed text
13455          */
13456         trim : function(value){
13457             return String(value).replace(trimRe, "");
13458         },
13459
13460         /**
13461          * Returns a substring from within an original string
13462          * @param {String} value The original text
13463          * @param {Number} start The start index of the substring
13464          * @param {Number} length The length of the substring
13465          * @return {String} The substring
13466          */
13467         substr : function(value, start, length){
13468             return String(value).substr(start, length);
13469         },
13470
13471         /**
13472          * Converts a string to all lower case letters
13473          * @param {String} value The text to convert
13474          * @return {String} The converted text
13475          */
13476         lowercase : function(value){
13477             return String(value).toLowerCase();
13478         },
13479
13480         /**
13481          * Converts a string to all upper case letters
13482          * @param {String} value The text to convert
13483          * @return {String} The converted text
13484          */
13485         uppercase : function(value){
13486             return String(value).toUpperCase();
13487         },
13488
13489         /**
13490          * Converts the first character only of a string to upper case
13491          * @param {String} value The text to convert
13492          * @return {String} The converted text
13493          */
13494         capitalize : function(value){
13495             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13496         },
13497
13498         // private
13499         call : function(value, fn){
13500             if(arguments.length > 2){
13501                 var args = Array.prototype.slice.call(arguments, 2);
13502                 args.unshift(value);
13503                  
13504                 return /** eval:var:value */  eval(fn).apply(window, args);
13505             }else{
13506                 /** eval:var:value */
13507                 return /** eval:var:value */ eval(fn).call(window, value);
13508             }
13509         },
13510
13511        
13512         /**
13513          * safer version of Math.toFixed..??/
13514          * @param {Number/String} value The numeric value to format
13515          * @param {Number/String} value Decimal places 
13516          * @return {String} The formatted currency string
13517          */
13518         toFixed : function(v, n)
13519         {
13520             // why not use to fixed - precision is buggered???
13521             if (!n) {
13522                 return Math.round(v-0);
13523             }
13524             var fact = Math.pow(10,n+1);
13525             v = (Math.round((v-0)*fact))/fact;
13526             var z = (''+fact).substring(2);
13527             if (v == Math.floor(v)) {
13528                 return Math.floor(v) + '.' + z;
13529             }
13530             
13531             // now just padd decimals..
13532             var ps = String(v).split('.');
13533             var fd = (ps[1] + z);
13534             var r = fd.substring(0,n); 
13535             var rm = fd.substring(n); 
13536             if (rm < 5) {
13537                 return ps[0] + '.' + r;
13538             }
13539             r*=1; // turn it into a number;
13540             r++;
13541             if (String(r).length != n) {
13542                 ps[0]*=1;
13543                 ps[0]++;
13544                 r = String(r).substring(1); // chop the end off.
13545             }
13546             
13547             return ps[0] + '.' + r;
13548              
13549         },
13550         
13551         /**
13552          * Format a number as US currency
13553          * @param {Number/String} value The numeric value to format
13554          * @return {String} The formatted currency string
13555          */
13556         usMoney : function(v){
13557             return '$' + Roo.util.Format.number(v);
13558         },
13559         
13560         /**
13561          * Format a number
13562          * eventually this should probably emulate php's number_format
13563          * @param {Number/String} value The numeric value to format
13564          * @param {Number} decimals number of decimal places
13565          * @return {String} The formatted currency string
13566          */
13567         number : function(v,decimals)
13568         {
13569             // multiply and round.
13570             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13571             var mul = Math.pow(10, decimals);
13572             var zero = String(mul).substring(1);
13573             v = (Math.round((v-0)*mul))/mul;
13574             
13575             // if it's '0' number.. then
13576             
13577             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13578             v = String(v);
13579             var ps = v.split('.');
13580             var whole = ps[0];
13581             
13582             
13583             var r = /(\d+)(\d{3})/;
13584             // add comma's
13585             while (r.test(whole)) {
13586                 whole = whole.replace(r, '$1' + ',' + '$2');
13587             }
13588             
13589             
13590             var sub = ps[1] ?
13591                     // has decimals..
13592                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13593                     // does not have decimals
13594                     (decimals ? ('.' + zero) : '');
13595             
13596             
13597             return whole + sub ;
13598         },
13599         
13600         /**
13601          * Parse a value into a formatted date using the specified format pattern.
13602          * @param {Mixed} value The value to format
13603          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13604          * @return {String} The formatted date string
13605          */
13606         date : function(v, format){
13607             if(!v){
13608                 return "";
13609             }
13610             if(!(v instanceof Date)){
13611                 v = new Date(Date.parse(v));
13612             }
13613             return v.dateFormat(format || Roo.util.Format.defaults.date);
13614         },
13615
13616         /**
13617          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13618          * @param {String} format Any valid date format string
13619          * @return {Function} The date formatting function
13620          */
13621         dateRenderer : function(format){
13622             return function(v){
13623                 return Roo.util.Format.date(v, format);  
13624             };
13625         },
13626
13627         // private
13628         stripTagsRE : /<\/?[^>]+>/gi,
13629         
13630         /**
13631          * Strips all HTML tags
13632          * @param {Mixed} value The text from which to strip tags
13633          * @return {String} The stripped text
13634          */
13635         stripTags : function(v){
13636             return !v ? v : String(v).replace(this.stripTagsRE, "");
13637         }
13638     };
13639 }();
13640 Roo.util.Format.defaults = {
13641     date : 'd/M/Y'
13642 };/*
13643  * Based on:
13644  * Ext JS Library 1.1.1
13645  * Copyright(c) 2006-2007, Ext JS, LLC.
13646  *
13647  * Originally Released Under LGPL - original licence link has changed is not relivant.
13648  *
13649  * Fork - LGPL
13650  * <script type="text/javascript">
13651  */
13652
13653
13654  
13655
13656 /**
13657  * @class Roo.MasterTemplate
13658  * @extends Roo.Template
13659  * Provides a template that can have child templates. The syntax is:
13660 <pre><code>
13661 var t = new Roo.MasterTemplate(
13662         '&lt;select name="{name}"&gt;',
13663                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13664         '&lt;/select&gt;'
13665 );
13666 t.add('options', {value: 'foo', text: 'bar'});
13667 // or you can add multiple child elements in one shot
13668 t.addAll('options', [
13669     {value: 'foo', text: 'bar'},
13670     {value: 'foo2', text: 'bar2'},
13671     {value: 'foo3', text: 'bar3'}
13672 ]);
13673 // then append, applying the master template values
13674 t.append('my-form', {name: 'my-select'});
13675 </code></pre>
13676 * A name attribute for the child template is not required if you have only one child
13677 * template or you want to refer to them by index.
13678  */
13679 Roo.MasterTemplate = function(){
13680     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13681     this.originalHtml = this.html;
13682     var st = {};
13683     var m, re = this.subTemplateRe;
13684     re.lastIndex = 0;
13685     var subIndex = 0;
13686     while(m = re.exec(this.html)){
13687         var name = m[1], content = m[2];
13688         st[subIndex] = {
13689             name: name,
13690             index: subIndex,
13691             buffer: [],
13692             tpl : new Roo.Template(content)
13693         };
13694         if(name){
13695             st[name] = st[subIndex];
13696         }
13697         st[subIndex].tpl.compile();
13698         st[subIndex].tpl.call = this.call.createDelegate(this);
13699         subIndex++;
13700     }
13701     this.subCount = subIndex;
13702     this.subs = st;
13703 };
13704 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13705     /**
13706     * The regular expression used to match sub templates
13707     * @type RegExp
13708     * @property
13709     */
13710     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13711
13712     /**
13713      * Applies the passed values to a child template.
13714      * @param {String/Number} name (optional) The name or index of the child template
13715      * @param {Array/Object} values The values to be applied to the template
13716      * @return {MasterTemplate} this
13717      */
13718      add : function(name, values){
13719         if(arguments.length == 1){
13720             values = arguments[0];
13721             name = 0;
13722         }
13723         var s = this.subs[name];
13724         s.buffer[s.buffer.length] = s.tpl.apply(values);
13725         return this;
13726     },
13727
13728     /**
13729      * Applies all the passed values to a child template.
13730      * @param {String/Number} name (optional) The name or index of the child template
13731      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13732      * @param {Boolean} reset (optional) True to reset the template first
13733      * @return {MasterTemplate} this
13734      */
13735     fill : function(name, values, reset){
13736         var a = arguments;
13737         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13738             values = a[0];
13739             name = 0;
13740             reset = a[1];
13741         }
13742         if(reset){
13743             this.reset();
13744         }
13745         for(var i = 0, len = values.length; i < len; i++){
13746             this.add(name, values[i]);
13747         }
13748         return this;
13749     },
13750
13751     /**
13752      * Resets the template for reuse
13753      * @return {MasterTemplate} this
13754      */
13755      reset : function(){
13756         var s = this.subs;
13757         for(var i = 0; i < this.subCount; i++){
13758             s[i].buffer = [];
13759         }
13760         return this;
13761     },
13762
13763     applyTemplate : function(values){
13764         var s = this.subs;
13765         var replaceIndex = -1;
13766         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13767             return s[++replaceIndex].buffer.join("");
13768         });
13769         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13770     },
13771
13772     apply : function(){
13773         return this.applyTemplate.apply(this, arguments);
13774     },
13775
13776     compile : function(){return this;}
13777 });
13778
13779 /**
13780  * Alias for fill().
13781  * @method
13782  */
13783 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13784  /**
13785  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13786  * var tpl = Roo.MasterTemplate.from('element-id');
13787  * @param {String/HTMLElement} el
13788  * @param {Object} config
13789  * @static
13790  */
13791 Roo.MasterTemplate.from = function(el, config){
13792     el = Roo.getDom(el);
13793     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13794 };/*
13795  * Based on:
13796  * Ext JS Library 1.1.1
13797  * Copyright(c) 2006-2007, Ext JS, LLC.
13798  *
13799  * Originally Released Under LGPL - original licence link has changed is not relivant.
13800  *
13801  * Fork - LGPL
13802  * <script type="text/javascript">
13803  */
13804
13805  
13806 /**
13807  * @class Roo.util.CSS
13808  * Utility class for manipulating CSS rules
13809  * @singleton
13810  */
13811 Roo.util.CSS = function(){
13812         var rules = null;
13813         var doc = document;
13814
13815     var camelRe = /(-[a-z])/gi;
13816     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13817
13818    return {
13819    /**
13820     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13821     * tag and appended to the HEAD of the document.
13822     * @param {String|Object} cssText The text containing the css rules
13823     * @param {String} id An id to add to the stylesheet for later removal
13824     * @return {StyleSheet}
13825     */
13826     createStyleSheet : function(cssText, id){
13827         var ss;
13828         var head = doc.getElementsByTagName("head")[0];
13829         var nrules = doc.createElement("style");
13830         nrules.setAttribute("type", "text/css");
13831         if(id){
13832             nrules.setAttribute("id", id);
13833         }
13834         if (typeof(cssText) != 'string') {
13835             // support object maps..
13836             // not sure if this a good idea.. 
13837             // perhaps it should be merged with the general css handling
13838             // and handle js style props.
13839             var cssTextNew = [];
13840             for(var n in cssText) {
13841                 var citems = [];
13842                 for(var k in cssText[n]) {
13843                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13844                 }
13845                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13846                 
13847             }
13848             cssText = cssTextNew.join("\n");
13849             
13850         }
13851        
13852        
13853        if(Roo.isIE){
13854            head.appendChild(nrules);
13855            ss = nrules.styleSheet;
13856            ss.cssText = cssText;
13857        }else{
13858            try{
13859                 nrules.appendChild(doc.createTextNode(cssText));
13860            }catch(e){
13861                nrules.cssText = cssText; 
13862            }
13863            head.appendChild(nrules);
13864            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13865        }
13866        this.cacheStyleSheet(ss);
13867        return ss;
13868    },
13869
13870    /**
13871     * Removes a style or link tag by id
13872     * @param {String} id The id of the tag
13873     */
13874    removeStyleSheet : function(id){
13875        var existing = doc.getElementById(id);
13876        if(existing){
13877            existing.parentNode.removeChild(existing);
13878        }
13879    },
13880
13881    /**
13882     * Dynamically swaps an existing stylesheet reference for a new one
13883     * @param {String} id The id of an existing link tag to remove
13884     * @param {String} url The href of the new stylesheet to include
13885     */
13886    swapStyleSheet : function(id, url){
13887        this.removeStyleSheet(id);
13888        var ss = doc.createElement("link");
13889        ss.setAttribute("rel", "stylesheet");
13890        ss.setAttribute("type", "text/css");
13891        ss.setAttribute("id", id);
13892        ss.setAttribute("href", url);
13893        doc.getElementsByTagName("head")[0].appendChild(ss);
13894    },
13895    
13896    /**
13897     * Refresh the rule cache if you have dynamically added stylesheets
13898     * @return {Object} An object (hash) of rules indexed by selector
13899     */
13900    refreshCache : function(){
13901        return this.getRules(true);
13902    },
13903
13904    // private
13905    cacheStyleSheet : function(stylesheet){
13906        if(!rules){
13907            rules = {};
13908        }
13909        try{// try catch for cross domain access issue
13910            var ssRules = stylesheet.cssRules || stylesheet.rules;
13911            for(var j = ssRules.length-1; j >= 0; --j){
13912                rules[ssRules[j].selectorText] = ssRules[j];
13913            }
13914        }catch(e){}
13915    },
13916    
13917    /**
13918     * Gets all css rules for the document
13919     * @param {Boolean} refreshCache true to refresh the internal cache
13920     * @return {Object} An object (hash) of rules indexed by selector
13921     */
13922    getRules : function(refreshCache){
13923                 if(rules == null || refreshCache){
13924                         rules = {};
13925                         var ds = doc.styleSheets;
13926                         for(var i =0, len = ds.length; i < len; i++){
13927                             try{
13928                         this.cacheStyleSheet(ds[i]);
13929                     }catch(e){} 
13930                 }
13931                 }
13932                 return rules;
13933         },
13934         
13935         /**
13936     * Gets an an individual CSS rule by selector(s)
13937     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13938     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13939     * @return {CSSRule} The CSS rule or null if one is not found
13940     */
13941    getRule : function(selector, refreshCache){
13942                 var rs = this.getRules(refreshCache);
13943                 if(!(selector instanceof Array)){
13944                     return rs[selector];
13945                 }
13946                 for(var i = 0; i < selector.length; i++){
13947                         if(rs[selector[i]]){
13948                                 return rs[selector[i]];
13949                         }
13950                 }
13951                 return null;
13952         },
13953         
13954         
13955         /**
13956     * Updates a rule property
13957     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13958     * @param {String} property The css property
13959     * @param {String} value The new value for the property
13960     * @return {Boolean} true If a rule was found and updated
13961     */
13962    updateRule : function(selector, property, value){
13963                 if(!(selector instanceof Array)){
13964                         var rule = this.getRule(selector);
13965                         if(rule){
13966                                 rule.style[property.replace(camelRe, camelFn)] = value;
13967                                 return true;
13968                         }
13969                 }else{
13970                         for(var i = 0; i < selector.length; i++){
13971                                 if(this.updateRule(selector[i], property, value)){
13972                                         return true;
13973                                 }
13974                         }
13975                 }
13976                 return false;
13977         }
13978    };   
13979 }();/*
13980  * Based on:
13981  * Ext JS Library 1.1.1
13982  * Copyright(c) 2006-2007, Ext JS, LLC.
13983  *
13984  * Originally Released Under LGPL - original licence link has changed is not relivant.
13985  *
13986  * Fork - LGPL
13987  * <script type="text/javascript">
13988  */
13989
13990  
13991
13992 /**
13993  * @class Roo.util.ClickRepeater
13994  * @extends Roo.util.Observable
13995  * 
13996  * A wrapper class which can be applied to any element. Fires a "click" event while the
13997  * mouse is pressed. The interval between firings may be specified in the config but
13998  * defaults to 10 milliseconds.
13999  * 
14000  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14001  * 
14002  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14003  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14004  * Similar to an autorepeat key delay.
14005  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14006  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14007  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14008  *           "interval" and "delay" are ignored. "immediate" is honored.
14009  * @cfg {Boolean} preventDefault True to prevent the default click event
14010  * @cfg {Boolean} stopDefault True to stop the default click event
14011  * 
14012  * @history
14013  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14014  *     2007-02-02 jvs Renamed to ClickRepeater
14015  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14016  *
14017  *  @constructor
14018  * @param {String/HTMLElement/Element} el The element to listen on
14019  * @param {Object} config
14020  **/
14021 Roo.util.ClickRepeater = function(el, config)
14022 {
14023     this.el = Roo.get(el);
14024     this.el.unselectable();
14025
14026     Roo.apply(this, config);
14027
14028     this.addEvents({
14029     /**
14030      * @event mousedown
14031      * Fires when the mouse button is depressed.
14032      * @param {Roo.util.ClickRepeater} this
14033      */
14034         "mousedown" : true,
14035     /**
14036      * @event click
14037      * Fires on a specified interval during the time the element is pressed.
14038      * @param {Roo.util.ClickRepeater} this
14039      */
14040         "click" : true,
14041     /**
14042      * @event mouseup
14043      * Fires when the mouse key is released.
14044      * @param {Roo.util.ClickRepeater} this
14045      */
14046         "mouseup" : true
14047     });
14048
14049     this.el.on("mousedown", this.handleMouseDown, this);
14050     if(this.preventDefault || this.stopDefault){
14051         this.el.on("click", function(e){
14052             if(this.preventDefault){
14053                 e.preventDefault();
14054             }
14055             if(this.stopDefault){
14056                 e.stopEvent();
14057             }
14058         }, this);
14059     }
14060
14061     // allow inline handler
14062     if(this.handler){
14063         this.on("click", this.handler,  this.scope || this);
14064     }
14065
14066     Roo.util.ClickRepeater.superclass.constructor.call(this);
14067 };
14068
14069 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14070     interval : 20,
14071     delay: 250,
14072     preventDefault : true,
14073     stopDefault : false,
14074     timer : 0,
14075
14076     // private
14077     handleMouseDown : function(){
14078         clearTimeout(this.timer);
14079         this.el.blur();
14080         if(this.pressClass){
14081             this.el.addClass(this.pressClass);
14082         }
14083         this.mousedownTime = new Date();
14084
14085         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14086         this.el.on("mouseout", this.handleMouseOut, this);
14087
14088         this.fireEvent("mousedown", this);
14089         this.fireEvent("click", this);
14090         
14091         this.timer = this.click.defer(this.delay || this.interval, this);
14092     },
14093
14094     // private
14095     click : function(){
14096         this.fireEvent("click", this);
14097         this.timer = this.click.defer(this.getInterval(), this);
14098     },
14099
14100     // private
14101     getInterval: function(){
14102         if(!this.accelerate){
14103             return this.interval;
14104         }
14105         var pressTime = this.mousedownTime.getElapsed();
14106         if(pressTime < 500){
14107             return 400;
14108         }else if(pressTime < 1700){
14109             return 320;
14110         }else if(pressTime < 2600){
14111             return 250;
14112         }else if(pressTime < 3500){
14113             return 180;
14114         }else if(pressTime < 4400){
14115             return 140;
14116         }else if(pressTime < 5300){
14117             return 80;
14118         }else if(pressTime < 6200){
14119             return 50;
14120         }else{
14121             return 10;
14122         }
14123     },
14124
14125     // private
14126     handleMouseOut : function(){
14127         clearTimeout(this.timer);
14128         if(this.pressClass){
14129             this.el.removeClass(this.pressClass);
14130         }
14131         this.el.on("mouseover", this.handleMouseReturn, this);
14132     },
14133
14134     // private
14135     handleMouseReturn : function(){
14136         this.el.un("mouseover", this.handleMouseReturn);
14137         if(this.pressClass){
14138             this.el.addClass(this.pressClass);
14139         }
14140         this.click();
14141     },
14142
14143     // private
14144     handleMouseUp : function(){
14145         clearTimeout(this.timer);
14146         this.el.un("mouseover", this.handleMouseReturn);
14147         this.el.un("mouseout", this.handleMouseOut);
14148         Roo.get(document).un("mouseup", this.handleMouseUp);
14149         this.el.removeClass(this.pressClass);
14150         this.fireEvent("mouseup", this);
14151     }
14152 });/*
14153  * Based on:
14154  * Ext JS Library 1.1.1
14155  * Copyright(c) 2006-2007, Ext JS, LLC.
14156  *
14157  * Originally Released Under LGPL - original licence link has changed is not relivant.
14158  *
14159  * Fork - LGPL
14160  * <script type="text/javascript">
14161  */
14162
14163  
14164 /**
14165  * @class Roo.KeyNav
14166  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14167  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14168  * way to implement custom navigation schemes for any UI component.</p>
14169  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14170  * pageUp, pageDown, del, home, end.  Usage:</p>
14171  <pre><code>
14172 var nav = new Roo.KeyNav("my-element", {
14173     "left" : function(e){
14174         this.moveLeft(e.ctrlKey);
14175     },
14176     "right" : function(e){
14177         this.moveRight(e.ctrlKey);
14178     },
14179     "enter" : function(e){
14180         this.save();
14181     },
14182     scope : this
14183 });
14184 </code></pre>
14185  * @constructor
14186  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14187  * @param {Object} config The config
14188  */
14189 Roo.KeyNav = function(el, config){
14190     this.el = Roo.get(el);
14191     Roo.apply(this, config);
14192     if(!this.disabled){
14193         this.disabled = true;
14194         this.enable();
14195     }
14196 };
14197
14198 Roo.KeyNav.prototype = {
14199     /**
14200      * @cfg {Boolean} disabled
14201      * True to disable this KeyNav instance (defaults to false)
14202      */
14203     disabled : false,
14204     /**
14205      * @cfg {String} defaultEventAction
14206      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14207      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14208      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14209      */
14210     defaultEventAction: "stopEvent",
14211     /**
14212      * @cfg {Boolean} forceKeyDown
14213      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14214      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14215      * handle keydown instead of keypress.
14216      */
14217     forceKeyDown : false,
14218
14219     // private
14220     prepareEvent : function(e){
14221         var k = e.getKey();
14222         var h = this.keyToHandler[k];
14223         //if(h && this[h]){
14224         //    e.stopPropagation();
14225         //}
14226         if(Roo.isSafari && h && k >= 37 && k <= 40){
14227             e.stopEvent();
14228         }
14229     },
14230
14231     // private
14232     relay : function(e){
14233         var k = e.getKey();
14234         var h = this.keyToHandler[k];
14235         if(h && this[h]){
14236             if(this.doRelay(e, this[h], h) !== true){
14237                 e[this.defaultEventAction]();
14238             }
14239         }
14240     },
14241
14242     // private
14243     doRelay : function(e, h, hname){
14244         return h.call(this.scope || this, e);
14245     },
14246
14247     // possible handlers
14248     enter : false,
14249     left : false,
14250     right : false,
14251     up : false,
14252     down : false,
14253     tab : false,
14254     esc : false,
14255     pageUp : false,
14256     pageDown : false,
14257     del : false,
14258     home : false,
14259     end : false,
14260
14261     // quick lookup hash
14262     keyToHandler : {
14263         37 : "left",
14264         39 : "right",
14265         38 : "up",
14266         40 : "down",
14267         33 : "pageUp",
14268         34 : "pageDown",
14269         46 : "del",
14270         36 : "home",
14271         35 : "end",
14272         13 : "enter",
14273         27 : "esc",
14274         9  : "tab"
14275     },
14276
14277         /**
14278          * Enable this KeyNav
14279          */
14280         enable: function(){
14281                 if(this.disabled){
14282             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14283             // the EventObject will normalize Safari automatically
14284             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14285                 this.el.on("keydown", this.relay,  this);
14286             }else{
14287                 this.el.on("keydown", this.prepareEvent,  this);
14288                 this.el.on("keypress", this.relay,  this);
14289             }
14290                     this.disabled = false;
14291                 }
14292         },
14293
14294         /**
14295          * Disable this KeyNav
14296          */
14297         disable: function(){
14298                 if(!this.disabled){
14299                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14300                 this.el.un("keydown", this.relay);
14301             }else{
14302                 this.el.un("keydown", this.prepareEvent);
14303                 this.el.un("keypress", this.relay);
14304             }
14305                     this.disabled = true;
14306                 }
14307         }
14308 };/*
14309  * Based on:
14310  * Ext JS Library 1.1.1
14311  * Copyright(c) 2006-2007, Ext JS, LLC.
14312  *
14313  * Originally Released Under LGPL - original licence link has changed is not relivant.
14314  *
14315  * Fork - LGPL
14316  * <script type="text/javascript">
14317  */
14318
14319  
14320 /**
14321  * @class Roo.KeyMap
14322  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14323  * The constructor accepts the same config object as defined by {@link #addBinding}.
14324  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14325  * combination it will call the function with this signature (if the match is a multi-key
14326  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14327  * A KeyMap can also handle a string representation of keys.<br />
14328  * Usage:
14329  <pre><code>
14330 // map one key by key code
14331 var map = new Roo.KeyMap("my-element", {
14332     key: 13, // or Roo.EventObject.ENTER
14333     fn: myHandler,
14334     scope: myObject
14335 });
14336
14337 // map multiple keys to one action by string
14338 var map = new Roo.KeyMap("my-element", {
14339     key: "a\r\n\t",
14340     fn: myHandler,
14341     scope: myObject
14342 });
14343
14344 // map multiple keys to multiple actions by strings and array of codes
14345 var map = new Roo.KeyMap("my-element", [
14346     {
14347         key: [10,13],
14348         fn: function(){ alert("Return was pressed"); }
14349     }, {
14350         key: "abc",
14351         fn: function(){ alert('a, b or c was pressed'); }
14352     }, {
14353         key: "\t",
14354         ctrl:true,
14355         shift:true,
14356         fn: function(){ alert('Control + shift + tab was pressed.'); }
14357     }
14358 ]);
14359 </code></pre>
14360  * <b>Note: A KeyMap starts enabled</b>
14361  * @constructor
14362  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14363  * @param {Object} config The config (see {@link #addBinding})
14364  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14365  */
14366 Roo.KeyMap = function(el, config, eventName){
14367     this.el  = Roo.get(el);
14368     this.eventName = eventName || "keydown";
14369     this.bindings = [];
14370     if(config){
14371         this.addBinding(config);
14372     }
14373     this.enable();
14374 };
14375
14376 Roo.KeyMap.prototype = {
14377     /**
14378      * True to stop the event from bubbling and prevent the default browser action if the
14379      * key was handled by the KeyMap (defaults to false)
14380      * @type Boolean
14381      */
14382     stopEvent : false,
14383
14384     /**
14385      * Add a new binding to this KeyMap. The following config object properties are supported:
14386      * <pre>
14387 Property    Type             Description
14388 ----------  ---------------  ----------------------------------------------------------------------
14389 key         String/Array     A single keycode or an array of keycodes to handle
14390 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14391 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14392 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14393 fn          Function         The function to call when KeyMap finds the expected key combination
14394 scope       Object           The scope of the callback function
14395 </pre>
14396      *
14397      * Usage:
14398      * <pre><code>
14399 // Create a KeyMap
14400 var map = new Roo.KeyMap(document, {
14401     key: Roo.EventObject.ENTER,
14402     fn: handleKey,
14403     scope: this
14404 });
14405
14406 //Add a new binding to the existing KeyMap later
14407 map.addBinding({
14408     key: 'abc',
14409     shift: true,
14410     fn: handleKey,
14411     scope: this
14412 });
14413 </code></pre>
14414      * @param {Object/Array} config A single KeyMap config or an array of configs
14415      */
14416         addBinding : function(config){
14417         if(config instanceof Array){
14418             for(var i = 0, len = config.length; i < len; i++){
14419                 this.addBinding(config[i]);
14420             }
14421             return;
14422         }
14423         var keyCode = config.key,
14424             shift = config.shift, 
14425             ctrl = config.ctrl, 
14426             alt = config.alt,
14427             fn = config.fn,
14428             scope = config.scope;
14429         if(typeof keyCode == "string"){
14430             var ks = [];
14431             var keyString = keyCode.toUpperCase();
14432             for(var j = 0, len = keyString.length; j < len; j++){
14433                 ks.push(keyString.charCodeAt(j));
14434             }
14435             keyCode = ks;
14436         }
14437         var keyArray = keyCode instanceof Array;
14438         var handler = function(e){
14439             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14440                 var k = e.getKey();
14441                 if(keyArray){
14442                     for(var i = 0, len = keyCode.length; i < len; i++){
14443                         if(keyCode[i] == k){
14444                           if(this.stopEvent){
14445                               e.stopEvent();
14446                           }
14447                           fn.call(scope || window, k, e);
14448                           return;
14449                         }
14450                     }
14451                 }else{
14452                     if(k == keyCode){
14453                         if(this.stopEvent){
14454                            e.stopEvent();
14455                         }
14456                         fn.call(scope || window, k, e);
14457                     }
14458                 }
14459             }
14460         };
14461         this.bindings.push(handler);  
14462         },
14463
14464     /**
14465      * Shorthand for adding a single key listener
14466      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14467      * following options:
14468      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14469      * @param {Function} fn The function to call
14470      * @param {Object} scope (optional) The scope of the function
14471      */
14472     on : function(key, fn, scope){
14473         var keyCode, shift, ctrl, alt;
14474         if(typeof key == "object" && !(key instanceof Array)){
14475             keyCode = key.key;
14476             shift = key.shift;
14477             ctrl = key.ctrl;
14478             alt = key.alt;
14479         }else{
14480             keyCode = key;
14481         }
14482         this.addBinding({
14483             key: keyCode,
14484             shift: shift,
14485             ctrl: ctrl,
14486             alt: alt,
14487             fn: fn,
14488             scope: scope
14489         })
14490     },
14491
14492     // private
14493     handleKeyDown : function(e){
14494             if(this.enabled){ //just in case
14495             var b = this.bindings;
14496             for(var i = 0, len = b.length; i < len; i++){
14497                 b[i].call(this, e);
14498             }
14499             }
14500         },
14501         
14502         /**
14503          * Returns true if this KeyMap is enabled
14504          * @return {Boolean} 
14505          */
14506         isEnabled : function(){
14507             return this.enabled;  
14508         },
14509         
14510         /**
14511          * Enables this KeyMap
14512          */
14513         enable: function(){
14514                 if(!this.enabled){
14515                     this.el.on(this.eventName, this.handleKeyDown, this);
14516                     this.enabled = true;
14517                 }
14518         },
14519
14520         /**
14521          * Disable this KeyMap
14522          */
14523         disable: function(){
14524                 if(this.enabled){
14525                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14526                     this.enabled = false;
14527                 }
14528         }
14529 };/*
14530  * Based on:
14531  * Ext JS Library 1.1.1
14532  * Copyright(c) 2006-2007, Ext JS, LLC.
14533  *
14534  * Originally Released Under LGPL - original licence link has changed is not relivant.
14535  *
14536  * Fork - LGPL
14537  * <script type="text/javascript">
14538  */
14539
14540  
14541 /**
14542  * @class Roo.util.TextMetrics
14543  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14544  * wide, in pixels, a given block of text will be.
14545  * @singleton
14546  */
14547 Roo.util.TextMetrics = function(){
14548     var shared;
14549     return {
14550         /**
14551          * Measures the size of the specified text
14552          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14553          * that can affect the size of the rendered text
14554          * @param {String} text The text to measure
14555          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14556          * in order to accurately measure the text height
14557          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14558          */
14559         measure : function(el, text, fixedWidth){
14560             if(!shared){
14561                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14562             }
14563             shared.bind(el);
14564             shared.setFixedWidth(fixedWidth || 'auto');
14565             return shared.getSize(text);
14566         },
14567
14568         /**
14569          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14570          * the overhead of multiple calls to initialize the style properties on each measurement.
14571          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14572          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14573          * in order to accurately measure the text height
14574          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14575          */
14576         createInstance : function(el, fixedWidth){
14577             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14578         }
14579     };
14580 }();
14581
14582  
14583
14584 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14585     var ml = new Roo.Element(document.createElement('div'));
14586     document.body.appendChild(ml.dom);
14587     ml.position('absolute');
14588     ml.setLeftTop(-1000, -1000);
14589     ml.hide();
14590
14591     if(fixedWidth){
14592         ml.setWidth(fixedWidth);
14593     }
14594      
14595     var instance = {
14596         /**
14597          * Returns the size of the specified text based on the internal element's style and width properties
14598          * @memberOf Roo.util.TextMetrics.Instance#
14599          * @param {String} text The text to measure
14600          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14601          */
14602         getSize : function(text){
14603             ml.update(text);
14604             var s = ml.getSize();
14605             ml.update('');
14606             return s;
14607         },
14608
14609         /**
14610          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14611          * that can affect the size of the rendered text
14612          * @memberOf Roo.util.TextMetrics.Instance#
14613          * @param {String/HTMLElement} el The element, dom node or id
14614          */
14615         bind : function(el){
14616             ml.setStyle(
14617                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14618             );
14619         },
14620
14621         /**
14622          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14623          * to set a fixed width in order to accurately measure the text height.
14624          * @memberOf Roo.util.TextMetrics.Instance#
14625          * @param {Number} width The width to set on the element
14626          */
14627         setFixedWidth : function(width){
14628             ml.setWidth(width);
14629         },
14630
14631         /**
14632          * Returns the measured width of the specified text
14633          * @memberOf Roo.util.TextMetrics.Instance#
14634          * @param {String} text The text to measure
14635          * @return {Number} width The width in pixels
14636          */
14637         getWidth : function(text){
14638             ml.dom.style.width = 'auto';
14639             return this.getSize(text).width;
14640         },
14641
14642         /**
14643          * Returns the measured height of the specified text.  For multiline text, be sure to call
14644          * {@link #setFixedWidth} if necessary.
14645          * @memberOf Roo.util.TextMetrics.Instance#
14646          * @param {String} text The text to measure
14647          * @return {Number} height The height in pixels
14648          */
14649         getHeight : function(text){
14650             return this.getSize(text).height;
14651         }
14652     };
14653
14654     instance.bind(bindTo);
14655
14656     return instance;
14657 };
14658
14659 // backwards compat
14660 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14661  * Based on:
14662  * Ext JS Library 1.1.1
14663  * Copyright(c) 2006-2007, Ext JS, LLC.
14664  *
14665  * Originally Released Under LGPL - original licence link has changed is not relivant.
14666  *
14667  * Fork - LGPL
14668  * <script type="text/javascript">
14669  */
14670
14671 /**
14672  * @class Roo.state.Provider
14673  * Abstract base class for state provider implementations. This class provides methods
14674  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14675  * Provider interface.
14676  */
14677 Roo.state.Provider = function(){
14678     /**
14679      * @event statechange
14680      * Fires when a state change occurs.
14681      * @param {Provider} this This state provider
14682      * @param {String} key The state key which was changed
14683      * @param {String} value The encoded value for the state
14684      */
14685     this.addEvents({
14686         "statechange": true
14687     });
14688     this.state = {};
14689     Roo.state.Provider.superclass.constructor.call(this);
14690 };
14691 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14692     /**
14693      * Returns the current value for a key
14694      * @param {String} name The key name
14695      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14696      * @return {Mixed} The state data
14697      */
14698     get : function(name, defaultValue){
14699         return typeof this.state[name] == "undefined" ?
14700             defaultValue : this.state[name];
14701     },
14702     
14703     /**
14704      * Clears a value from the state
14705      * @param {String} name The key name
14706      */
14707     clear : function(name){
14708         delete this.state[name];
14709         this.fireEvent("statechange", this, name, null);
14710     },
14711     
14712     /**
14713      * Sets the value for a key
14714      * @param {String} name The key name
14715      * @param {Mixed} value The value to set
14716      */
14717     set : function(name, value){
14718         this.state[name] = value;
14719         this.fireEvent("statechange", this, name, value);
14720     },
14721     
14722     /**
14723      * Decodes a string previously encoded with {@link #encodeValue}.
14724      * @param {String} value The value to decode
14725      * @return {Mixed} The decoded value
14726      */
14727     decodeValue : function(cookie){
14728         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14729         var matches = re.exec(unescape(cookie));
14730         if(!matches || !matches[1]) return; // non state cookie
14731         var type = matches[1];
14732         var v = matches[2];
14733         switch(type){
14734             case "n":
14735                 return parseFloat(v);
14736             case "d":
14737                 return new Date(Date.parse(v));
14738             case "b":
14739                 return (v == "1");
14740             case "a":
14741                 var all = [];
14742                 var values = v.split("^");
14743                 for(var i = 0, len = values.length; i < len; i++){
14744                     all.push(this.decodeValue(values[i]));
14745                 }
14746                 return all;
14747            case "o":
14748                 var all = {};
14749                 var values = v.split("^");
14750                 for(var i = 0, len = values.length; i < len; i++){
14751                     var kv = values[i].split("=");
14752                     all[kv[0]] = this.decodeValue(kv[1]);
14753                 }
14754                 return all;
14755            default:
14756                 return v;
14757         }
14758     },
14759     
14760     /**
14761      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14762      * @param {Mixed} value The value to encode
14763      * @return {String} The encoded value
14764      */
14765     encodeValue : function(v){
14766         var enc;
14767         if(typeof v == "number"){
14768             enc = "n:" + v;
14769         }else if(typeof v == "boolean"){
14770             enc = "b:" + (v ? "1" : "0");
14771         }else if(v instanceof Date){
14772             enc = "d:" + v.toGMTString();
14773         }else if(v instanceof Array){
14774             var flat = "";
14775             for(var i = 0, len = v.length; i < len; i++){
14776                 flat += this.encodeValue(v[i]);
14777                 if(i != len-1) flat += "^";
14778             }
14779             enc = "a:" + flat;
14780         }else if(typeof v == "object"){
14781             var flat = "";
14782             for(var key in v){
14783                 if(typeof v[key] != "function"){
14784                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14785                 }
14786             }
14787             enc = "o:" + flat.substring(0, flat.length-1);
14788         }else{
14789             enc = "s:" + v;
14790         }
14791         return escape(enc);        
14792     }
14793 });
14794
14795 /*
14796  * Based on:
14797  * Ext JS Library 1.1.1
14798  * Copyright(c) 2006-2007, Ext JS, LLC.
14799  *
14800  * Originally Released Under LGPL - original licence link has changed is not relivant.
14801  *
14802  * Fork - LGPL
14803  * <script type="text/javascript">
14804  */
14805 /**
14806  * @class Roo.state.Manager
14807  * This is the global state manager. By default all components that are "state aware" check this class
14808  * for state information if you don't pass them a custom state provider. In order for this class
14809  * to be useful, it must be initialized with a provider when your application initializes.
14810  <pre><code>
14811 // in your initialization function
14812 init : function(){
14813    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14814    ...
14815    // supposed you have a {@link Roo.BorderLayout}
14816    var layout = new Roo.BorderLayout(...);
14817    layout.restoreState();
14818    // or a {Roo.BasicDialog}
14819    var dialog = new Roo.BasicDialog(...);
14820    dialog.restoreState();
14821  </code></pre>
14822  * @singleton
14823  */
14824 Roo.state.Manager = function(){
14825     var provider = new Roo.state.Provider();
14826     
14827     return {
14828         /**
14829          * Configures the default state provider for your application
14830          * @param {Provider} stateProvider The state provider to set
14831          */
14832         setProvider : function(stateProvider){
14833             provider = stateProvider;
14834         },
14835         
14836         /**
14837          * Returns the current value for a key
14838          * @param {String} name The key name
14839          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14840          * @return {Mixed} The state data
14841          */
14842         get : function(key, defaultValue){
14843             return provider.get(key, defaultValue);
14844         },
14845         
14846         /**
14847          * Sets the value for a key
14848          * @param {String} name The key name
14849          * @param {Mixed} value The state data
14850          */
14851          set : function(key, value){
14852             provider.set(key, value);
14853         },
14854         
14855         /**
14856          * Clears a value from the state
14857          * @param {String} name The key name
14858          */
14859         clear : function(key){
14860             provider.clear(key);
14861         },
14862         
14863         /**
14864          * Gets the currently configured state provider
14865          * @return {Provider} The state provider
14866          */
14867         getProvider : function(){
14868             return provider;
14869         }
14870     };
14871 }();
14872 /*
14873  * Based on:
14874  * Ext JS Library 1.1.1
14875  * Copyright(c) 2006-2007, Ext JS, LLC.
14876  *
14877  * Originally Released Under LGPL - original licence link has changed is not relivant.
14878  *
14879  * Fork - LGPL
14880  * <script type="text/javascript">
14881  */
14882 /**
14883  * @class Roo.state.CookieProvider
14884  * @extends Roo.state.Provider
14885  * The default Provider implementation which saves state via cookies.
14886  * <br />Usage:
14887  <pre><code>
14888    var cp = new Roo.state.CookieProvider({
14889        path: "/cgi-bin/",
14890        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14891        domain: "roojs.com"
14892    })
14893    Roo.state.Manager.setProvider(cp);
14894  </code></pre>
14895  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14896  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14897  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14898  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14899  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14900  * domain the page is running on including the 'www' like 'www.roojs.com')
14901  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14902  * @constructor
14903  * Create a new CookieProvider
14904  * @param {Object} config The configuration object
14905  */
14906 Roo.state.CookieProvider = function(config){
14907     Roo.state.CookieProvider.superclass.constructor.call(this);
14908     this.path = "/";
14909     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14910     this.domain = null;
14911     this.secure = false;
14912     Roo.apply(this, config);
14913     this.state = this.readCookies();
14914 };
14915
14916 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14917     // private
14918     set : function(name, value){
14919         if(typeof value == "undefined" || value === null){
14920             this.clear(name);
14921             return;
14922         }
14923         this.setCookie(name, value);
14924         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14925     },
14926
14927     // private
14928     clear : function(name){
14929         this.clearCookie(name);
14930         Roo.state.CookieProvider.superclass.clear.call(this, name);
14931     },
14932
14933     // private
14934     readCookies : function(){
14935         var cookies = {};
14936         var c = document.cookie + ";";
14937         var re = /\s?(.*?)=(.*?);/g;
14938         var matches;
14939         while((matches = re.exec(c)) != null){
14940             var name = matches[1];
14941             var value = matches[2];
14942             if(name && name.substring(0,3) == "ys-"){
14943                 cookies[name.substr(3)] = this.decodeValue(value);
14944             }
14945         }
14946         return cookies;
14947     },
14948
14949     // private
14950     setCookie : function(name, value){
14951         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14952            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14953            ((this.path == null) ? "" : ("; path=" + this.path)) +
14954            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14955            ((this.secure == true) ? "; secure" : "");
14956     },
14957
14958     // private
14959     clearCookie : function(name){
14960         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14961            ((this.path == null) ? "" : ("; path=" + this.path)) +
14962            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14963            ((this.secure == true) ? "; secure" : "");
14964     }
14965 });/*
14966  * Based on:
14967  * Ext JS Library 1.1.1
14968  * Copyright(c) 2006-2007, Ext JS, LLC.
14969  *
14970  * Originally Released Under LGPL - original licence link has changed is not relivant.
14971  *
14972  * Fork - LGPL
14973  * <script type="text/javascript">
14974  */
14975  
14976
14977 /**
14978  * @class Roo.ComponentMgr
14979  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14980  * @singleton
14981  */
14982 Roo.ComponentMgr = function(){
14983     var all = new Roo.util.MixedCollection();
14984
14985     return {
14986         /**
14987          * Registers a component.
14988          * @param {Roo.Component} c The component
14989          */
14990         register : function(c){
14991             all.add(c);
14992         },
14993
14994         /**
14995          * Unregisters a component.
14996          * @param {Roo.Component} c The component
14997          */
14998         unregister : function(c){
14999             all.remove(c);
15000         },
15001
15002         /**
15003          * Returns a component by id
15004          * @param {String} id The component id
15005          */
15006         get : function(id){
15007             return all.get(id);
15008         },
15009
15010         /**
15011          * Registers a function that will be called when a specified component is added to ComponentMgr
15012          * @param {String} id The component id
15013          * @param {Funtction} fn The callback function
15014          * @param {Object} scope The scope of the callback
15015          */
15016         onAvailable : function(id, fn, scope){
15017             all.on("add", function(index, o){
15018                 if(o.id == id){
15019                     fn.call(scope || o, o);
15020                     all.un("add", fn, scope);
15021                 }
15022             });
15023         }
15024     };
15025 }();/*
15026  * Based on:
15027  * Ext JS Library 1.1.1
15028  * Copyright(c) 2006-2007, Ext JS, LLC.
15029  *
15030  * Originally Released Under LGPL - original licence link has changed is not relivant.
15031  *
15032  * Fork - LGPL
15033  * <script type="text/javascript">
15034  */
15035  
15036 /**
15037  * @class Roo.Component
15038  * @extends Roo.util.Observable
15039  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15040  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15041  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15042  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15043  * All visual components (widgets) that require rendering into a layout should subclass Component.
15044  * @constructor
15045  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15046  * element and its id used as the component id.  If a string is passed, it is assumed to be the id of an existing element
15047  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15048  */
15049 Roo.Component = function(config){
15050     config = config || {};
15051     if(config.tagName || config.dom || typeof config == "string"){ // element object
15052         config = {el: config, id: config.id || config};
15053     }
15054     this.initialConfig = config;
15055
15056     Roo.apply(this, config);
15057     this.addEvents({
15058         /**
15059          * @event disable
15060          * Fires after the component is disabled.
15061              * @param {Roo.Component} this
15062              */
15063         disable : true,
15064         /**
15065          * @event enable
15066          * Fires after the component is enabled.
15067              * @param {Roo.Component} this
15068              */
15069         enable : true,
15070         /**
15071          * @event beforeshow
15072          * Fires before the component is shown.  Return false to stop the show.
15073              * @param {Roo.Component} this
15074              */
15075         beforeshow : true,
15076         /**
15077          * @event show
15078          * Fires after the component is shown.
15079              * @param {Roo.Component} this
15080              */
15081         show : true,
15082         /**
15083          * @event beforehide
15084          * Fires before the component is hidden. Return false to stop the hide.
15085              * @param {Roo.Component} this
15086              */
15087         beforehide : true,
15088         /**
15089          * @event hide
15090          * Fires after the component is hidden.
15091              * @param {Roo.Component} this
15092              */
15093         hide : true,
15094         /**
15095          * @event beforerender
15096          * Fires before the component is rendered. Return false to stop the render.
15097              * @param {Roo.Component} this
15098              */
15099         beforerender : true,
15100         /**
15101          * @event render
15102          * Fires after the component is rendered.
15103              * @param {Roo.Component} this
15104              */
15105         render : true,
15106         /**
15107          * @event beforedestroy
15108          * Fires before the component is destroyed. Return false to stop the destroy.
15109              * @param {Roo.Component} this
15110              */
15111         beforedestroy : true,
15112         /**
15113          * @event destroy
15114          * Fires after the component is destroyed.
15115              * @param {Roo.Component} this
15116              */
15117         destroy : true
15118     });
15119     if(!this.id){
15120         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15121     }
15122     Roo.ComponentMgr.register(this);
15123     Roo.Component.superclass.constructor.call(this);
15124     this.initComponent();
15125     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15126         this.render(this.renderTo);
15127         delete this.renderTo;
15128     }
15129 };
15130
15131 /** @private */
15132 Roo.Component.AUTO_ID = 1000;
15133
15134 Roo.extend(Roo.Component, Roo.util.Observable, {
15135     /**
15136      * @scope Roo.Component.prototype
15137      * @type {Boolean}
15138      * true if this component is hidden. Read-only.
15139      */
15140     hidden : false,
15141     /**
15142      * @type {Boolean}
15143      * true if this component is disabled. Read-only.
15144      */
15145     disabled : false,
15146     /**
15147      * @type {Boolean}
15148      * true if this component has been rendered. Read-only.
15149      */
15150     rendered : false,
15151     
15152     /** @cfg {String} disableClass
15153      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15154      */
15155     disabledClass : "x-item-disabled",
15156         /** @cfg {Boolean} allowDomMove
15157          * Whether the component can move the Dom node when rendering (defaults to true).
15158          */
15159     allowDomMove : true,
15160     /** @cfg {String} hideMode
15161      * How this component should hidden. Supported values are
15162      * "visibility" (css visibility), "offsets" (negative offset position) and
15163      * "display" (css display) - defaults to "display".
15164      */
15165     hideMode: 'display',
15166
15167     /** @private */
15168     ctype : "Roo.Component",
15169
15170     /**
15171      * @cfg {String} actionMode 
15172      * which property holds the element that used for  hide() / show() / disable() / enable()
15173      * default is 'el' 
15174      */
15175     actionMode : "el",
15176
15177     /** @private */
15178     getActionEl : function(){
15179         return this[this.actionMode];
15180     },
15181
15182     initComponent : Roo.emptyFn,
15183     /**
15184      * If this is a lazy rendering component, render it to its container element.
15185      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15186      */
15187     render : function(container, position){
15188         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15189             if(!container && this.el){
15190                 this.el = Roo.get(this.el);
15191                 container = this.el.dom.parentNode;
15192                 this.allowDomMove = false;
15193             }
15194             this.container = Roo.get(container);
15195             this.rendered = true;
15196             if(position !== undefined){
15197                 if(typeof position == 'number'){
15198                     position = this.container.dom.childNodes[position];
15199                 }else{
15200                     position = Roo.getDom(position);
15201                 }
15202             }
15203             this.onRender(this.container, position || null);
15204             if(this.cls){
15205                 this.el.addClass(this.cls);
15206                 delete this.cls;
15207             }
15208             if(this.style){
15209                 this.el.applyStyles(this.style);
15210                 delete this.style;
15211             }
15212             this.fireEvent("render", this);
15213             this.afterRender(this.container);
15214             if(this.hidden){
15215                 this.hide();
15216             }
15217             if(this.disabled){
15218                 this.disable();
15219             }
15220         }
15221         return this;
15222     },
15223
15224     /** @private */
15225     // default function is not really useful
15226     onRender : function(ct, position){
15227         if(this.el){
15228             this.el = Roo.get(this.el);
15229             if(this.allowDomMove !== false){
15230                 ct.dom.insertBefore(this.el.dom, position);
15231             }
15232         }
15233     },
15234
15235     /** @private */
15236     getAutoCreate : function(){
15237         var cfg = typeof this.autoCreate == "object" ?
15238                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15239         if(this.id && !cfg.id){
15240             cfg.id = this.id;
15241         }
15242         return cfg;
15243     },
15244
15245     /** @private */
15246     afterRender : Roo.emptyFn,
15247
15248     /**
15249      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15250      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15251      */
15252     destroy : function(){
15253         if(this.fireEvent("beforedestroy", this) !== false){
15254             this.purgeListeners();
15255             this.beforeDestroy();
15256             if(this.rendered){
15257                 this.el.removeAllListeners();
15258                 this.el.remove();
15259                 if(this.actionMode == "container"){
15260                     this.container.remove();
15261                 }
15262             }
15263             this.onDestroy();
15264             Roo.ComponentMgr.unregister(this);
15265             this.fireEvent("destroy", this);
15266         }
15267     },
15268
15269         /** @private */
15270     beforeDestroy : function(){
15271
15272     },
15273
15274         /** @private */
15275         onDestroy : function(){
15276
15277     },
15278
15279     /**
15280      * Returns the underlying {@link Roo.Element}.
15281      * @return {Roo.Element} The element
15282      */
15283     getEl : function(){
15284         return this.el;
15285     },
15286
15287     /**
15288      * Returns the id of this component.
15289      * @return {String}
15290      */
15291     getId : function(){
15292         return this.id;
15293     },
15294
15295     /**
15296      * Try to focus this component.
15297      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15298      * @return {Roo.Component} this
15299      */
15300     focus : function(selectText){
15301         if(this.rendered){
15302             this.el.focus();
15303             if(selectText === true){
15304                 this.el.dom.select();
15305             }
15306         }
15307         return this;
15308     },
15309
15310     /** @private */
15311     blur : function(){
15312         if(this.rendered){
15313             this.el.blur();
15314         }
15315         return this;
15316     },
15317
15318     /**
15319      * Disable this component.
15320      * @return {Roo.Component} this
15321      */
15322     disable : function(){
15323         if(this.rendered){
15324             this.onDisable();
15325         }
15326         this.disabled = true;
15327         this.fireEvent("disable", this);
15328         return this;
15329     },
15330
15331         // private
15332     onDisable : function(){
15333         this.getActionEl().addClass(this.disabledClass);
15334         this.el.dom.disabled = true;
15335     },
15336
15337     /**
15338      * Enable this component.
15339      * @return {Roo.Component} this
15340      */
15341     enable : function(){
15342         if(this.rendered){
15343             this.onEnable();
15344         }
15345         this.disabled = false;
15346         this.fireEvent("enable", this);
15347         return this;
15348     },
15349
15350         // private
15351     onEnable : function(){
15352         this.getActionEl().removeClass(this.disabledClass);
15353         this.el.dom.disabled = false;
15354     },
15355
15356     /**
15357      * Convenience function for setting disabled/enabled by boolean.
15358      * @param {Boolean} disabled
15359      */
15360     setDisabled : function(disabled){
15361         this[disabled ? "disable" : "enable"]();
15362     },
15363
15364     /**
15365      * Show this component.
15366      * @return {Roo.Component} this
15367      */
15368     show: function(){
15369         if(this.fireEvent("beforeshow", this) !== false){
15370             this.hidden = false;
15371             if(this.rendered){
15372                 this.onShow();
15373             }
15374             this.fireEvent("show", this);
15375         }
15376         return this;
15377     },
15378
15379     // private
15380     onShow : function(){
15381         var ae = this.getActionEl();
15382         if(this.hideMode == 'visibility'){
15383             ae.dom.style.visibility = "visible";
15384         }else if(this.hideMode == 'offsets'){
15385             ae.removeClass('x-hidden');
15386         }else{
15387             ae.dom.style.display = "";
15388         }
15389     },
15390
15391     /**
15392      * Hide this component.
15393      * @return {Roo.Component} this
15394      */
15395     hide: function(){
15396         if(this.fireEvent("beforehide", this) !== false){
15397             this.hidden = true;
15398             if(this.rendered){
15399                 this.onHide();
15400             }
15401             this.fireEvent("hide", this);
15402         }
15403         return this;
15404     },
15405
15406     // private
15407     onHide : function(){
15408         var ae = this.getActionEl();
15409         if(this.hideMode == 'visibility'){
15410             ae.dom.style.visibility = "hidden";
15411         }else if(this.hideMode == 'offsets'){
15412             ae.addClass('x-hidden');
15413         }else{
15414             ae.dom.style.display = "none";
15415         }
15416     },
15417
15418     /**
15419      * Convenience function to hide or show this component by boolean.
15420      * @param {Boolean} visible True to show, false to hide
15421      * @return {Roo.Component} this
15422      */
15423     setVisible: function(visible){
15424         if(visible) {
15425             this.show();
15426         }else{
15427             this.hide();
15428         }
15429         return this;
15430     },
15431
15432     /**
15433      * Returns true if this component is visible.
15434      */
15435     isVisible : function(){
15436         return this.getActionEl().isVisible();
15437     },
15438
15439     cloneConfig : function(overrides){
15440         overrides = overrides || {};
15441         var id = overrides.id || Roo.id();
15442         var cfg = Roo.applyIf(overrides, this.initialConfig);
15443         cfg.id = id; // prevent dup id
15444         return new this.constructor(cfg);
15445     }
15446 });/*
15447  * Based on:
15448  * Ext JS Library 1.1.1
15449  * Copyright(c) 2006-2007, Ext JS, LLC.
15450  *
15451  * Originally Released Under LGPL - original licence link has changed is not relivant.
15452  *
15453  * Fork - LGPL
15454  * <script type="text/javascript">
15455  */
15456
15457 /**
15458  * @class Roo.BoxComponent
15459  * @extends Roo.Component
15460  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15461  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15462  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15463  * layout containers.
15464  * @constructor
15465  * @param {Roo.Element/String/Object} config The configuration options.
15466  */
15467 Roo.BoxComponent = function(config){
15468     Roo.Component.call(this, config);
15469     this.addEvents({
15470         /**
15471          * @event resize
15472          * Fires after the component is resized.
15473              * @param {Roo.Component} this
15474              * @param {Number} adjWidth The box-adjusted width that was set
15475              * @param {Number} adjHeight The box-adjusted height that was set
15476              * @param {Number} rawWidth The width that was originally specified
15477              * @param {Number} rawHeight The height that was originally specified
15478              */
15479         resize : true,
15480         /**
15481          * @event move
15482          * Fires after the component is moved.
15483              * @param {Roo.Component} this
15484              * @param {Number} x The new x position
15485              * @param {Number} y The new y position
15486              */
15487         move : true
15488     });
15489 };
15490
15491 Roo.extend(Roo.BoxComponent, Roo.Component, {
15492     // private, set in afterRender to signify that the component has been rendered
15493     boxReady : false,
15494     // private, used to defer height settings to subclasses
15495     deferHeight: false,
15496     /** @cfg {Number} width
15497      * width (optional) size of component
15498      */
15499      /** @cfg {Number} height
15500      * height (optional) size of component
15501      */
15502      
15503     /**
15504      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15505      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15506      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15507      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15508      * @return {Roo.BoxComponent} this
15509      */
15510     setSize : function(w, h){
15511         // support for standard size objects
15512         if(typeof w == 'object'){
15513             h = w.height;
15514             w = w.width;
15515         }
15516         // not rendered
15517         if(!this.boxReady){
15518             this.width = w;
15519             this.height = h;
15520             return this;
15521         }
15522
15523         // prevent recalcs when not needed
15524         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15525             return this;
15526         }
15527         this.lastSize = {width: w, height: h};
15528
15529         var adj = this.adjustSize(w, h);
15530         var aw = adj.width, ah = adj.height;
15531         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15532             var rz = this.getResizeEl();
15533             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15534                 rz.setSize(aw, ah);
15535             }else if(!this.deferHeight && ah !== undefined){
15536                 rz.setHeight(ah);
15537             }else if(aw !== undefined){
15538                 rz.setWidth(aw);
15539             }
15540             this.onResize(aw, ah, w, h);
15541             this.fireEvent('resize', this, aw, ah, w, h);
15542         }
15543         return this;
15544     },
15545
15546     /**
15547      * Gets the current size of the component's underlying element.
15548      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15549      */
15550     getSize : function(){
15551         return this.el.getSize();
15552     },
15553
15554     /**
15555      * Gets the current XY position of the component's underlying element.
15556      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15557      * @return {Array} The XY position of the element (e.g., [100, 200])
15558      */
15559     getPosition : function(local){
15560         if(local === true){
15561             return [this.el.getLeft(true), this.el.getTop(true)];
15562         }
15563         return this.xy || this.el.getXY();
15564     },
15565
15566     /**
15567      * Gets the current box measurements of the component's underlying element.
15568      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15569      * @returns {Object} box An object in the format {x, y, width, height}
15570      */
15571     getBox : function(local){
15572         var s = this.el.getSize();
15573         if(local){
15574             s.x = this.el.getLeft(true);
15575             s.y = this.el.getTop(true);
15576         }else{
15577             var xy = this.xy || this.el.getXY();
15578             s.x = xy[0];
15579             s.y = xy[1];
15580         }
15581         return s;
15582     },
15583
15584     /**
15585      * Sets the current box measurements of the component's underlying element.
15586      * @param {Object} box An object in the format {x, y, width, height}
15587      * @returns {Roo.BoxComponent} this
15588      */
15589     updateBox : function(box){
15590         this.setSize(box.width, box.height);
15591         this.setPagePosition(box.x, box.y);
15592         return this;
15593     },
15594
15595     // protected
15596     getResizeEl : function(){
15597         return this.resizeEl || this.el;
15598     },
15599
15600     // protected
15601     getPositionEl : function(){
15602         return this.positionEl || this.el;
15603     },
15604
15605     /**
15606      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15607      * This method fires the move event.
15608      * @param {Number} left The new left
15609      * @param {Number} top The new top
15610      * @returns {Roo.BoxComponent} this
15611      */
15612     setPosition : function(x, y){
15613         this.x = x;
15614         this.y = y;
15615         if(!this.boxReady){
15616             return this;
15617         }
15618         var adj = this.adjustPosition(x, y);
15619         var ax = adj.x, ay = adj.y;
15620
15621         var el = this.getPositionEl();
15622         if(ax !== undefined || ay !== undefined){
15623             if(ax !== undefined && ay !== undefined){
15624                 el.setLeftTop(ax, ay);
15625             }else if(ax !== undefined){
15626                 el.setLeft(ax);
15627             }else if(ay !== undefined){
15628                 el.setTop(ay);
15629             }
15630             this.onPosition(ax, ay);
15631             this.fireEvent('move', this, ax, ay);
15632         }
15633         return this;
15634     },
15635
15636     /**
15637      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15638      * This method fires the move event.
15639      * @param {Number} x The new x position
15640      * @param {Number} y The new y position
15641      * @returns {Roo.BoxComponent} this
15642      */
15643     setPagePosition : function(x, y){
15644         this.pageX = x;
15645         this.pageY = y;
15646         if(!this.boxReady){
15647             return;
15648         }
15649         if(x === undefined || y === undefined){ // cannot translate undefined points
15650             return;
15651         }
15652         var p = this.el.translatePoints(x, y);
15653         this.setPosition(p.left, p.top);
15654         return this;
15655     },
15656
15657     // private
15658     onRender : function(ct, position){
15659         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15660         if(this.resizeEl){
15661             this.resizeEl = Roo.get(this.resizeEl);
15662         }
15663         if(this.positionEl){
15664             this.positionEl = Roo.get(this.positionEl);
15665         }
15666     },
15667
15668     // private
15669     afterRender : function(){
15670         Roo.BoxComponent.superclass.afterRender.call(this);
15671         this.boxReady = true;
15672         this.setSize(this.width, this.height);
15673         if(this.x || this.y){
15674             this.setPosition(this.x, this.y);
15675         }
15676         if(this.pageX || this.pageY){
15677             this.setPagePosition(this.pageX, this.pageY);
15678         }
15679     },
15680
15681     /**
15682      * Force the component's size to recalculate based on the underlying element's current height and width.
15683      * @returns {Roo.BoxComponent} this
15684      */
15685     syncSize : function(){
15686         delete this.lastSize;
15687         this.setSize(this.el.getWidth(), this.el.getHeight());
15688         return this;
15689     },
15690
15691     /**
15692      * Called after the component is resized, this method is empty by default but can be implemented by any
15693      * subclass that needs to perform custom logic after a resize occurs.
15694      * @param {Number} adjWidth The box-adjusted width that was set
15695      * @param {Number} adjHeight The box-adjusted height that was set
15696      * @param {Number} rawWidth The width that was originally specified
15697      * @param {Number} rawHeight The height that was originally specified
15698      */
15699     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15700
15701     },
15702
15703     /**
15704      * Called after the component is moved, this method is empty by default but can be implemented by any
15705      * subclass that needs to perform custom logic after a move occurs.
15706      * @param {Number} x The new x position
15707      * @param {Number} y The new y position
15708      */
15709     onPosition : function(x, y){
15710
15711     },
15712
15713     // private
15714     adjustSize : function(w, h){
15715         if(this.autoWidth){
15716             w = 'auto';
15717         }
15718         if(this.autoHeight){
15719             h = 'auto';
15720         }
15721         return {width : w, height: h};
15722     },
15723
15724     // private
15725     adjustPosition : function(x, y){
15726         return {x : x, y: y};
15727     }
15728 });/*
15729  * Original code for Roojs - LGPL
15730  * <script type="text/javascript">
15731  */
15732  
15733 /**
15734  * @class Roo.XComponent
15735  * A delayed Element creator...
15736  * Or a way to group chunks of interface together.
15737  * 
15738  * Mypart.xyx = new Roo.XComponent({
15739
15740     parent : 'Mypart.xyz', // empty == document.element.!!
15741     order : '001',
15742     name : 'xxxx'
15743     region : 'xxxx'
15744     disabled : function() {} 
15745      
15746     tree : function() { // return an tree of xtype declared components
15747         var MODULE = this;
15748         return 
15749         {
15750             xtype : 'NestedLayoutPanel',
15751             // technicall
15752         }
15753      ]
15754  *})
15755  *
15756  *
15757  * It can be used to build a big heiracy, with parent etc.
15758  * or you can just use this to render a single compoent to a dom element
15759  * MYPART.render(Roo.Element | String(id) | dom_element )
15760  * 
15761  * @extends Roo.util.Observable
15762  * @constructor
15763  * @param cfg {Object} configuration of component
15764  * 
15765  */
15766 Roo.XComponent = function(cfg) {
15767     Roo.apply(this, cfg);
15768     this.addEvents({ 
15769         /**
15770              * @event built
15771              * Fires when this the componnt is built
15772              * @param {Roo.XComponent} c the component
15773              */
15774         'built' : true
15775         
15776     });
15777     this.region = this.region || 'center'; // default..
15778     Roo.XComponent.register(this);
15779     this.modules = false;
15780     this.el = false; // where the layout goes..
15781     
15782     
15783 }
15784 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15785     /**
15786      * @property el
15787      * The created element (with Roo.factory())
15788      * @type {Roo.Layout}
15789      */
15790     el  : false,
15791     
15792     /**
15793      * @property el
15794      * for BC  - use el in new code
15795      * @type {Roo.Layout}
15796      */
15797     panel : false,
15798     
15799     /**
15800      * @property layout
15801      * for BC  - use el in new code
15802      * @type {Roo.Layout}
15803      */
15804     layout : false,
15805     
15806      /**
15807      * @cfg {Function|boolean} disabled
15808      * If this module is disabled by some rule, return true from the funtion
15809      */
15810     disabled : false,
15811     
15812     /**
15813      * @cfg {String} parent 
15814      * Name of parent element which it get xtype added to..
15815      */
15816     parent: false,
15817     
15818     /**
15819      * @cfg {String} order
15820      * Used to set the order in which elements are created (usefull for multiple tabs)
15821      */
15822     
15823     order : false,
15824     /**
15825      * @cfg {String} name
15826      * String to display while loading.
15827      */
15828     name : false,
15829     /**
15830      * @cfg {String} region
15831      * Region to render component to (defaults to center)
15832      */
15833     region : 'center',
15834     
15835     /**
15836      * @cfg {Array} items
15837      * A single item array - the first element is the root of the tree..
15838      * It's done this way to stay compatible with the Xtype system...
15839      */
15840     items : false,
15841     
15842     /**
15843      * @property _tree
15844      * The method that retuns the tree of parts that make up this compoennt 
15845      * @type {function}
15846      */
15847     _tree  : false,
15848     
15849      /**
15850      * render
15851      * render element to dom or tree
15852      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15853      */
15854     
15855     render : function(el)
15856     {
15857         
15858         el = el || false;
15859         var hp = this.parent ? 1 : 0;
15860         
15861         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15862             // if parent is a '#.....' string, then let's use that..
15863             var ename = this.parent.substr(1)
15864             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15865             el = Roo.get(ename);
15866             if (!el && !this.parent) {
15867                 Roo.log("Warning - element can not be found :#" + ename );
15868                 return;
15869             }
15870         }
15871         var tree = this._tree ? this._tree() : this.tree();
15872
15873         
15874         if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15875             //el = Roo.get(document.body);
15876             this.parent = { el : true };
15877         }
15878             
15879             
15880         
15881         if (!this.parent) {
15882             
15883             Roo.log("no parent - creating one");
15884             
15885             el = el ? Roo.get(el) : false;      
15886             
15887             // it's a top level one..
15888             this.parent =  {
15889                 el : new Roo.BorderLayout(el || document.body, {
15890                 
15891                      center: {
15892                          titlebar: false,
15893                          autoScroll:false,
15894                          closeOnTab: true,
15895                          tabPosition: 'top',
15896                           //resizeTabs: true,
15897                          alwaysShowTabs: el && hp? false :  true,
15898                          hideTabs: el || !hp ? true :  false,
15899                          minTabWidth: 140
15900                      }
15901                  })
15902             }
15903         }
15904         
15905                 if (!this.parent.el) {
15906                         // probably an old style ctor, which has been disabled.
15907                         return;
15908                         
15909                 }
15910                 // The 'tree' method is  '_tree now' 
15911             
15912         tree.region = tree.region || this.region;
15913         
15914         if (this.parent.el === true) {
15915             // bootstrap... - body..
15916             this.parent.el = Roo.factory(tree);
15917         }
15918         
15919         this.el = this.parent.el.addxtype(tree);
15920         this.fireEvent('built', this);
15921         
15922         this.panel = this.el;
15923         this.layout = this.panel.layout;
15924                 this.parentLayout = this.parent.layout  || false;  
15925          
15926     }
15927     
15928 });
15929
15930 Roo.apply(Roo.XComponent, {
15931     /**
15932      * @property  hideProgress
15933      * true to disable the building progress bar.. usefull on single page renders.
15934      * @type Boolean
15935      */
15936     hideProgress : false,
15937     /**
15938      * @property  buildCompleted
15939      * True when the builder has completed building the interface.
15940      * @type Boolean
15941      */
15942     buildCompleted : false,
15943      
15944     /**
15945      * @property  topModule
15946      * the upper most module - uses document.element as it's constructor.
15947      * @type Object
15948      */
15949      
15950     topModule  : false,
15951       
15952     /**
15953      * @property  modules
15954      * array of modules to be created by registration system.
15955      * @type {Array} of Roo.XComponent
15956      */
15957     
15958     modules : [],
15959     /**
15960      * @property  elmodules
15961      * array of modules to be created by which use #ID 
15962      * @type {Array} of Roo.XComponent
15963      */
15964      
15965     elmodules : [],
15966
15967      /**
15968      * @property  build_from_html
15969      * Build elements from html - used by bootstrap HTML stuff 
15970      *    - this is cleared after build is completed
15971      * @type {boolean} true  (default false)
15972      */
15973      
15974     build_from_html : false,
15975
15976     /**
15977      * Register components to be built later.
15978      *
15979      * This solves the following issues
15980      * - Building is not done on page load, but after an authentication process has occured.
15981      * - Interface elements are registered on page load
15982      * - Parent Interface elements may not be loaded before child, so this handles that..
15983      * 
15984      *
15985      * example:
15986      * 
15987      * MyApp.register({
15988           order : '000001',
15989           module : 'Pman.Tab.projectMgr',
15990           region : 'center',
15991           parent : 'Pman.layout',
15992           disabled : false,  // or use a function..
15993         })
15994      
15995      * * @param {Object} details about module
15996      */
15997     register : function(obj) {
15998                 
15999         Roo.XComponent.event.fireEvent('register', obj);
16000         switch(typeof(obj.disabled) ) {
16001                 
16002             case 'undefined':
16003                 break;
16004             
16005             case 'function':
16006                 if ( obj.disabled() ) {
16007                         return;
16008                 }
16009                 break;
16010             
16011             default:
16012                 if (obj.disabled) {
16013                         return;
16014                 }
16015                 break;
16016         }
16017                 
16018         this.modules.push(obj);
16019          
16020     },
16021     /**
16022      * convert a string to an object..
16023      * eg. 'AAA.BBB' -> finds AAA.BBB
16024
16025      */
16026     
16027     toObject : function(str)
16028     {
16029         if (!str || typeof(str) == 'object') {
16030             return str;
16031         }
16032         if (str.substring(0,1) == '#') {
16033             return str;
16034         }
16035
16036         var ar = str.split('.');
16037         var rt, o;
16038         rt = ar.shift();
16039             /** eval:var:o */
16040         try {
16041             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16042         } catch (e) {
16043             throw "Module not found : " + str;
16044         }
16045         
16046         if (o === false) {
16047             throw "Module not found : " + str;
16048         }
16049         Roo.each(ar, function(e) {
16050             if (typeof(o[e]) == 'undefined') {
16051                 throw "Module not found : " + str;
16052             }
16053             o = o[e];
16054         });
16055         
16056         return o;
16057         
16058     },
16059     
16060     
16061     /**
16062      * move modules into their correct place in the tree..
16063      * 
16064      */
16065     preBuild : function ()
16066     {
16067         var _t = this;
16068         Roo.each(this.modules , function (obj)
16069         {
16070             Roo.XComponent.event.fireEvent('beforebuild', obj);
16071             
16072             var opar = obj.parent;
16073             try { 
16074                 obj.parent = this.toObject(opar);
16075             } catch(e) {
16076                 Roo.log("parent:toObject failed: " + e.toString());
16077                 return;
16078             }
16079             
16080             if (!obj.parent) {
16081                 Roo.debug && Roo.log("GOT top level module");
16082                 Roo.debug && Roo.log(obj);
16083                 obj.modules = new Roo.util.MixedCollection(false, 
16084                     function(o) { return o.order + '' }
16085                 );
16086                 this.topModule = obj;
16087                 return;
16088             }
16089                         // parent is a string (usually a dom element name..)
16090             if (typeof(obj.parent) == 'string') {
16091                 this.elmodules.push(obj);
16092                 return;
16093             }
16094             if (obj.parent.constructor != Roo.XComponent) {
16095                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16096             }
16097             if (!obj.parent.modules) {
16098                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16099                     function(o) { return o.order + '' }
16100                 );
16101             }
16102             if (obj.parent.disabled) {
16103                 obj.disabled = true;
16104             }
16105             obj.parent.modules.add(obj);
16106         }, this);
16107     },
16108     
16109      /**
16110      * make a list of modules to build.
16111      * @return {Array} list of modules. 
16112      */ 
16113     
16114     buildOrder : function()
16115     {
16116         var _this = this;
16117         var cmp = function(a,b) {   
16118             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16119         };
16120         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16121             throw "No top level modules to build";
16122         }
16123         
16124         // make a flat list in order of modules to build.
16125         var mods = this.topModule ? [ this.topModule ] : [];
16126                 
16127         
16128         // elmodules (is a list of DOM based modules )
16129         Roo.each(this.elmodules, function(e) {
16130             mods.push(e);
16131             if (!this.topModule &&
16132                 typeof(e.parent) == 'string' &&
16133                 e.parent.substring(0,1) == '#' &&
16134                 Roo.get(e.parent.substr(1))
16135                ) {
16136                 
16137                 _this.topModule = e;
16138             }
16139             
16140         });
16141
16142         
16143         // add modules to their parents..
16144         var addMod = function(m) {
16145             Roo.debug && Roo.log("build Order: add: " + m.name);
16146                 
16147             mods.push(m);
16148             if (m.modules && !m.disabled) {
16149                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16150                 m.modules.keySort('ASC',  cmp );
16151                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16152     
16153                 m.modules.each(addMod);
16154             } else {
16155                 Roo.debug && Roo.log("build Order: no child modules");
16156             }
16157             // not sure if this is used any more..
16158             if (m.finalize) {
16159                 m.finalize.name = m.name + " (clean up) ";
16160                 mods.push(m.finalize);
16161             }
16162             
16163         }
16164         if (this.topModule && this.topModule.modules) { 
16165             this.topModule.modules.keySort('ASC',  cmp );
16166             this.topModule.modules.each(addMod);
16167         } 
16168         return mods;
16169     },
16170     
16171      /**
16172      * Build the registered modules.
16173      * @param {Object} parent element.
16174      * @param {Function} optional method to call after module has been added.
16175      * 
16176      */ 
16177    
16178     build : function(opts) 
16179     {
16180         
16181         if (typeof(opts) != 'undefined') {
16182             Roo.apply(this,opts);
16183         }
16184         
16185         this.preBuild();
16186         var mods = this.buildOrder();
16187       
16188         //this.allmods = mods;
16189         //Roo.debug && Roo.log(mods);
16190         //return;
16191         if (!mods.length) { // should not happen
16192             throw "NO modules!!!";
16193         }
16194         
16195         
16196         var msg = "Building Interface...";
16197         // flash it up as modal - so we store the mask!?
16198         if (!this.hideProgress && Roo.MessageBox) {
16199             Roo.MessageBox.show({ title: 'loading' });
16200             Roo.MessageBox.show({
16201                title: "Please wait...",
16202                msg: msg,
16203                width:450,
16204                progress:true,
16205                closable:false,
16206                modal: false
16207               
16208             });
16209         }
16210         var total = mods.length;
16211         
16212         var _this = this;
16213         var progressRun = function() {
16214             if (!mods.length) {
16215                 Roo.debug && Roo.log('hide?');
16216                 if (!this.hideProgress && Roo.MessageBox) {
16217                     Roo.MessageBox.hide();
16218                 }
16219                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16220                 
16221                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16222                 
16223                 // THE END...
16224                 return false;   
16225             }
16226             
16227             var m = mods.shift();
16228             
16229             
16230             Roo.debug && Roo.log(m);
16231             // not sure if this is supported any more.. - modules that are are just function
16232             if (typeof(m) == 'function') { 
16233                 m.call(this);
16234                 return progressRun.defer(10, _this);
16235             } 
16236             
16237             
16238             msg = "Building Interface " + (total  - mods.length) + 
16239                     " of " + total + 
16240                     (m.name ? (' - ' + m.name) : '');
16241                         Roo.debug && Roo.log(msg);
16242             if (!this.hideProgress &&  Roo.MessageBox) { 
16243                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16244             }
16245             
16246          
16247             // is the module disabled?
16248             var disabled = (typeof(m.disabled) == 'function') ?
16249                 m.disabled.call(m.module.disabled) : m.disabled;    
16250             
16251             
16252             if (disabled) {
16253                 return progressRun(); // we do not update the display!
16254             }
16255             
16256             // now build 
16257             
16258                         
16259                         
16260             m.render();
16261             // it's 10 on top level, and 1 on others??? why...
16262             return progressRun.defer(10, _this);
16263              
16264         }
16265         progressRun.defer(1, _this);
16266      
16267         
16268         
16269     },
16270         
16271         
16272         /**
16273          * Event Object.
16274          *
16275          *
16276          */
16277         event: false, 
16278     /**
16279          * wrapper for event.on - aliased later..  
16280          * Typically use to register a event handler for register:
16281          *
16282          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16283          *
16284          */
16285     on : false
16286    
16287     
16288     
16289 });
16290
16291 Roo.XComponent.event = new Roo.util.Observable({
16292                 events : { 
16293                         /**
16294                          * @event register
16295                          * Fires when an Component is registered,
16296                          * set the disable property on the Component to stop registration.
16297                          * @param {Roo.XComponent} c the component being registerd.
16298                          * 
16299                          */
16300                         'register' : true,
16301             /**
16302                          * @event beforebuild
16303                          * Fires before each Component is built
16304                          * can be used to apply permissions.
16305                          * @param {Roo.XComponent} c the component being registerd.
16306                          * 
16307                          */
16308                         'beforebuild' : true,
16309                         /**
16310                          * @event buildcomplete
16311                          * Fires on the top level element when all elements have been built
16312                          * @param {Roo.XComponent} the top level component.
16313                          */
16314                         'buildcomplete' : true
16315                         
16316                 }
16317 });
16318
16319 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16320