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                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             Roo.log('ns');
303             Roo.log(ns);
304             if (c.constructor == ns[c.xtype]) {// already created...
305                 return c;
306             }
307             if (ns[c.xtype]) {
308                 Roo.log("Roo.Factory(" + c.xtype + ")");
309                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
310                 var ret = new ns[c.xtype](c);
311                 ret.xns = false;
312                 return ret;
313             }
314             c.xns = false; // prevent recursion..
315             return c;
316         },
317          /**
318          * Logs to console if it can.
319          *
320          * @param {String|Object} string
321          * @method log
322          */
323         log : function(s)
324         {
325             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
326                 return; // alerT?
327             }
328             console.log(s);
329             
330         },
331         /**
332          * 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.
333          * @param {Object} o
334          * @return {String}
335          */
336         urlEncode : function(o){
337             if(!o){
338                 return "";
339             }
340             var buf = [];
341             for(var key in o){
342                 var ov = o[key], k = Roo.encodeURIComponent(key);
343                 var type = typeof ov;
344                 if(type == 'undefined'){
345                     buf.push(k, "=&");
346                 }else if(type != "function" && type != "object"){
347                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
348                 }else if(ov instanceof Array){
349                     if (ov.length) {
350                             for(var i = 0, len = ov.length; i < len; i++) {
351                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
352                             }
353                         } else {
354                             buf.push(k, "=&");
355                         }
356                 }
357             }
358             buf.pop();
359             return buf.join("");
360         },
361          /**
362          * Safe version of encodeURIComponent
363          * @param {String} data 
364          * @return {String} 
365          */
366         
367         encodeURIComponent : function (data)
368         {
369             try {
370                 return encodeURIComponent(data);
371             } catch(e) {} // should be an uri encode error.
372             
373             if (data == '' || data == null){
374                return '';
375             }
376             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
377             function nibble_to_hex(nibble){
378                 var chars = '0123456789ABCDEF';
379                 return chars.charAt(nibble);
380             }
381             data = data.toString();
382             var buffer = '';
383             for(var i=0; i<data.length; i++){
384                 var c = data.charCodeAt(i);
385                 var bs = new Array();
386                 if (c > 0x10000){
387                         // 4 bytes
388                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
389                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
390                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
391                     bs[3] = 0x80 | (c & 0x3F);
392                 }else if (c > 0x800){
393                          // 3 bytes
394                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
395                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
396                     bs[2] = 0x80 | (c & 0x3F);
397                 }else if (c > 0x80){
398                        // 2 bytes
399                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
400                     bs[1] = 0x80 | (c & 0x3F);
401                 }else{
402                         // 1 byte
403                     bs[0] = c;
404                 }
405                 for(var j=0; j<bs.length; j++){
406                     var b = bs[j];
407                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
408                             + nibble_to_hex(b &0x0F);
409                     buffer += '%'+hex;
410                }
411             }
412             return buffer;    
413              
414         },
415
416         /**
417          * 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]}.
418          * @param {String} string
419          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
420          * @return {Object} A literal with members
421          */
422         urlDecode : function(string, overwrite){
423             if(!string || !string.length){
424                 return {};
425             }
426             var obj = {};
427             var pairs = string.split('&');
428             var pair, name, value;
429             for(var i = 0, len = pairs.length; i < len; i++){
430                 pair = pairs[i].split('=');
431                 name = decodeURIComponent(pair[0]);
432                 value = decodeURIComponent(pair[1]);
433                 if(overwrite !== true){
434                     if(typeof obj[name] == "undefined"){
435                         obj[name] = value;
436                     }else if(typeof obj[name] == "string"){
437                         obj[name] = [obj[name]];
438                         obj[name].push(value);
439                     }else{
440                         obj[name].push(value);
441                     }
442                 }else{
443                     obj[name] = value;
444                 }
445             }
446             return obj;
447         },
448
449         /**
450          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
451          * passed array is not really an array, your function is called once with it.
452          * The supplied function is called with (Object item, Number index, Array allItems).
453          * @param {Array/NodeList/Mixed} array
454          * @param {Function} fn
455          * @param {Object} scope
456          */
457         each : function(array, fn, scope){
458             if(typeof array.length == "undefined" || typeof array == "string"){
459                 array = [array];
460             }
461             for(var i = 0, len = array.length; i < len; i++){
462                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
463             }
464         },
465
466         // deprecated
467         combine : function(){
468             var as = arguments, l = as.length, r = [];
469             for(var i = 0; i < l; i++){
470                 var a = as[i];
471                 if(a instanceof Array){
472                     r = r.concat(a);
473                 }else if(a.length !== undefined && !a.substr){
474                     r = r.concat(Array.prototype.slice.call(a, 0));
475                 }else{
476                     r.push(a);
477                 }
478             }
479             return r;
480         },
481
482         /**
483          * Escapes the passed string for use in a regular expression
484          * @param {String} str
485          * @return {String}
486          */
487         escapeRe : function(s) {
488             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489         },
490
491         // internal
492         callback : function(cb, scope, args, delay){
493             if(typeof cb == "function"){
494                 if(delay){
495                     cb.defer(delay, scope, args || []);
496                 }else{
497                     cb.apply(scope, args || []);
498                 }
499             }
500         },
501
502         /**
503          * Return the dom node for the passed string (id), dom node, or Roo.Element
504          * @param {String/HTMLElement/Roo.Element} el
505          * @return HTMLElement
506          */
507         getDom : function(el){
508             if(!el){
509                 return null;
510             }
511             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512         },
513
514         /**
515         * Shorthand for {@link Roo.ComponentMgr#get}
516         * @param {String} id
517         * @return Roo.Component
518         */
519         getCmp : function(id){
520             return Roo.ComponentMgr.get(id);
521         },
522          
523         num : function(v, defaultValue){
524             if(typeof v != 'number'){
525                 return defaultValue;
526             }
527             return v;
528         },
529
530         destroy : function(){
531             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532                 var as = a[i];
533                 if(as){
534                     if(as.dom){
535                         as.removeAllListeners();
536                         as.remove();
537                         continue;
538                     }
539                     if(typeof as.purgeListeners == 'function'){
540                         as.purgeListeners();
541                     }
542                     if(typeof as.destroy == 'function'){
543                         as.destroy();
544                     }
545                 }
546             }
547         },
548
549         // inpired by a similar function in mootools library
550         /**
551          * Returns the type of object that is passed in. If the object passed in is null or undefined it
552          * return false otherwise it returns one of the following values:<ul>
553          * <li><b>string</b>: If the object passed is a string</li>
554          * <li><b>number</b>: If the object passed is a number</li>
555          * <li><b>boolean</b>: If the object passed is a boolean value</li>
556          * <li><b>function</b>: If the object passed is a function reference</li>
557          * <li><b>object</b>: If the object passed is an object</li>
558          * <li><b>array</b>: If the object passed is an array</li>
559          * <li><b>regexp</b>: If the object passed is a regular expression</li>
560          * <li><b>element</b>: If the object passed is a DOM Element</li>
561          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
562          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
563          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
564          * @param {Mixed} object
565          * @return {String}
566          */
567         type : function(o){
568             if(o === undefined || o === null){
569                 return false;
570             }
571             if(o.htmlElement){
572                 return 'element';
573             }
574             var t = typeof o;
575             if(t == 'object' && o.nodeName) {
576                 switch(o.nodeType) {
577                     case 1: return 'element';
578                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
579                 }
580             }
581             if(t == 'object' || t == 'function') {
582                 switch(o.constructor) {
583                     case Array: return 'array';
584                     case RegExp: return 'regexp';
585                 }
586                 if(typeof o.length == 'number' && typeof o.item == 'function') {
587                     return 'nodelist';
588                 }
589             }
590             return t;
591         },
592
593         /**
594          * Returns true if the passed value is null, undefined or an empty string (optional).
595          * @param {Mixed} value The value to test
596          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
597          * @return {Boolean}
598          */
599         isEmpty : function(v, allowBlank){
600             return v === null || v === undefined || (!allowBlank ? v === '' : false);
601         },
602         
603         /** @type Boolean */
604         isOpera : isOpera,
605         /** @type Boolean */
606         isSafari : isSafari,
607         /** @type Boolean */
608         isIE : isIE,
609         /** @type Boolean */
610         isIE7 : isIE7,
611         /** @type Boolean */
612         isGecko : isGecko,
613         /** @type Boolean */
614         isBorderBox : isBorderBox,
615         /** @type Boolean */
616         isWindows : isWindows,
617         /** @type Boolean */
618         isLinux : isLinux,
619         /** @type Boolean */
620         isMac : isMac,
621         /** @type Boolean */
622         isTouch : isTouch,
623
624         /**
625          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
626          * you may want to set this to true.
627          * @type Boolean
628          */
629         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
630         
631         
632                 
633         /**
634          * Selects a single element as a Roo Element
635          * This is about as close as you can get to jQuery's $('do crazy stuff')
636          * @param {String} selector The selector/xpath query
637          * @param {Node} root (optional) The start of the query (defaults to document).
638          * @return {Roo.Element}
639          */
640         selectNode : function(selector, root) 
641         {
642             var node = Roo.DomQuery.selectNode(selector,root);
643             return node ? Roo.get(node) : new Roo.Element(false);
644         }
645         
646     });
647
648
649 })();
650
651 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
652                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
653 /*
654  * Based on:
655  * Ext JS Library 1.1.1
656  * Copyright(c) 2006-2007, Ext JS, LLC.
657  *
658  * Originally Released Under LGPL - original licence link has changed is not relivant.
659  *
660  * Fork - LGPL
661  * <script type="text/javascript">
662  */
663
664 (function() {    
665     // wrappedn so fnCleanup is not in global scope...
666     if(Roo.isIE) {
667         function fnCleanUp() {
668             var p = Function.prototype;
669             delete p.createSequence;
670             delete p.defer;
671             delete p.createDelegate;
672             delete p.createCallback;
673             delete p.createInterceptor;
674
675             window.detachEvent("onunload", fnCleanUp);
676         }
677         window.attachEvent("onunload", fnCleanUp);
678     }
679 })();
680
681
682 /**
683  * @class Function
684  * These functions are available on every Function object (any JavaScript function).
685  */
686 Roo.apply(Function.prototype, {
687      /**
688      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
689      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
690      * Will create a function that is bound to those 2 args.
691      * @return {Function} The new function
692     */
693     createCallback : function(/*args...*/){
694         // make args available, in function below
695         var args = arguments;
696         var method = this;
697         return function() {
698             return method.apply(window, args);
699         };
700     },
701
702     /**
703      * Creates a delegate (callback) that sets the scope to obj.
704      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
705      * Will create a function that is automatically scoped to this.
706      * @param {Object} obj (optional) The object for which the scope is set
707      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
708      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
709      *                                             if a number the args are inserted at the specified position
710      * @return {Function} The new function
711      */
712     createDelegate : function(obj, args, appendArgs){
713         var method = this;
714         return function() {
715             var callArgs = args || arguments;
716             if(appendArgs === true){
717                 callArgs = Array.prototype.slice.call(arguments, 0);
718                 callArgs = callArgs.concat(args);
719             }else if(typeof appendArgs == "number"){
720                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
721                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
722                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
723             }
724             return method.apply(obj || window, callArgs);
725         };
726     },
727
728     /**
729      * Calls this function after the number of millseconds specified.
730      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
731      * @param {Object} obj (optional) The object for which the scope is set
732      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
733      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
734      *                                             if a number the args are inserted at the specified position
735      * @return {Number} The timeout id that can be used with clearTimeout
736      */
737     defer : function(millis, obj, args, appendArgs){
738         var fn = this.createDelegate(obj, args, appendArgs);
739         if(millis){
740             return setTimeout(fn, millis);
741         }
742         fn();
743         return 0;
744     },
745     /**
746      * Create a combined function call sequence of the original function + the passed function.
747      * The resulting function returns the results of the original function.
748      * The passed fcn is called with the parameters of the original function
749      * @param {Function} fcn The function to sequence
750      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
751      * @return {Function} The new function
752      */
753     createSequence : function(fcn, scope){
754         if(typeof fcn != "function"){
755             return this;
756         }
757         var method = this;
758         return function() {
759             var retval = method.apply(this || window, arguments);
760             fcn.apply(scope || this || window, arguments);
761             return retval;
762         };
763     },
764
765     /**
766      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
767      * The resulting function returns the results of the original function.
768      * The passed fcn is called with the parameters of the original function.
769      * @addon
770      * @param {Function} fcn The function to call before the original
771      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
772      * @return {Function} The new function
773      */
774     createInterceptor : function(fcn, scope){
775         if(typeof fcn != "function"){
776             return this;
777         }
778         var method = this;
779         return function() {
780             fcn.target = this;
781             fcn.method = method;
782             if(fcn.apply(scope || this || window, arguments) === false){
783                 return;
784             }
785             return method.apply(this || window, arguments);
786         };
787     }
788 });
789 /*
790  * Based on:
791  * Ext JS Library 1.1.1
792  * Copyright(c) 2006-2007, Ext JS, LLC.
793  *
794  * Originally Released Under LGPL - original licence link has changed is not relivant.
795  *
796  * Fork - LGPL
797  * <script type="text/javascript">
798  */
799
800 Roo.applyIf(String, {
801     
802     /** @scope String */
803     
804     /**
805      * Escapes the passed string for ' and \
806      * @param {String} string The string to escape
807      * @return {String} The escaped string
808      * @static
809      */
810     escape : function(string) {
811         return string.replace(/('|\\)/g, "\\$1");
812     },
813
814     /**
815      * Pads the left side of a string with a specified character.  This is especially useful
816      * for normalizing number and date strings.  Example usage:
817      * <pre><code>
818 var s = String.leftPad('123', 5, '0');
819 // s now contains the string: '00123'
820 </code></pre>
821      * @param {String} string The original string
822      * @param {Number} size The total length of the output string
823      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
824      * @return {String} The padded string
825      * @static
826      */
827     leftPad : function (val, size, ch) {
828         var result = new String(val);
829         if(ch === null || ch === undefined || ch === '') {
830             ch = " ";
831         }
832         while (result.length < size) {
833             result = ch + result;
834         }
835         return result;
836     },
837
838     /**
839      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
840      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
841      * <pre><code>
842 var cls = 'my-class', text = 'Some text';
843 var s = String.format('<div class="{0}">{1}</div>', cls, text);
844 // s now contains the string: '<div class="my-class">Some text</div>'
845 </code></pre>
846      * @param {String} string The tokenized string to be formatted
847      * @param {String} value1 The value to replace token {0}
848      * @param {String} value2 Etc...
849      * @return {String} The formatted string
850      * @static
851      */
852     format : function(format){
853         var args = Array.prototype.slice.call(arguments, 1);
854         return format.replace(/\{(\d+)\}/g, function(m, i){
855             return Roo.util.Format.htmlEncode(args[i]);
856         });
857     }
858 });
859
860 /**
861  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
862  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
863  * they are already different, the first value passed in is returned.  Note that this method returns the new value
864  * but does not change the current string.
865  * <pre><code>
866 // alternate sort directions
867 sort = sort.toggle('ASC', 'DESC');
868
869 // instead of conditional logic:
870 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
871 </code></pre>
872  * @param {String} value The value to compare to the current string
873  * @param {String} other The new value to use if the string already equals the first value passed in
874  * @return {String} The new value
875  */
876  
877 String.prototype.toggle = function(value, other){
878     return this == value ? other : value;
879 };/*
880  * Based on:
881  * Ext JS Library 1.1.1
882  * Copyright(c) 2006-2007, Ext JS, LLC.
883  *
884  * Originally Released Under LGPL - original licence link has changed is not relivant.
885  *
886  * Fork - LGPL
887  * <script type="text/javascript">
888  */
889
890  /**
891  * @class Number
892  */
893 Roo.applyIf(Number.prototype, {
894     /**
895      * Checks whether or not the current number is within a desired range.  If the number is already within the
896      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
897      * exceeded.  Note that this method returns the constrained value but does not change the current number.
898      * @param {Number} min The minimum number in the range
899      * @param {Number} max The maximum number in the range
900      * @return {Number} The constrained value if outside the range, otherwise the current value
901      */
902     constrain : function(min, max){
903         return Math.min(Math.max(this, min), max);
904     }
905 });/*
906  * Based on:
907  * Ext JS Library 1.1.1
908  * Copyright(c) 2006-2007, Ext JS, LLC.
909  *
910  * Originally Released Under LGPL - original licence link has changed is not relivant.
911  *
912  * Fork - LGPL
913  * <script type="text/javascript">
914  */
915  /**
916  * @class Array
917  */
918 Roo.applyIf(Array.prototype, {
919     /**
920      * Checks whether or not the specified object exists in the array.
921      * @param {Object} o The object to check for
922      * @return {Number} The index of o in the array (or -1 if it is not found)
923      */
924     indexOf : function(o){
925        for (var i = 0, len = this.length; i < len; i++){
926               if(this[i] == o) return i;
927        }
928            return -1;
929     },
930
931     /**
932      * Removes the specified object from the array.  If the object is not found nothing happens.
933      * @param {Object} o The object to remove
934      */
935     remove : function(o){
936        var index = this.indexOf(o);
937        if(index != -1){
938            this.splice(index, 1);
939        }
940     },
941     /**
942      * Map (JS 1.6 compatibility)
943      * @param {Function} function  to call
944      */
945     map : function(fun )
946     {
947         var len = this.length >>> 0;
948         if (typeof fun != "function")
949             throw new TypeError();
950
951         var res = new Array(len);
952         var thisp = arguments[1];
953         for (var i = 0; i < len; i++)
954         {
955             if (i in this)
956                 res[i] = fun.call(thisp, this[i], i, this);
957         }
958
959         return res;
960     }
961     
962 });
963
964
965  /*
966  * Based on:
967  * Ext JS Library 1.1.1
968  * Copyright(c) 2006-2007, Ext JS, LLC.
969  *
970  * Originally Released Under LGPL - original licence link has changed is not relivant.
971  *
972  * Fork - LGPL
973  * <script type="text/javascript">
974  */
975
976 /**
977  * @class Date
978  *
979  * The date parsing and format syntax is a subset of
980  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
981  * supported will provide results equivalent to their PHP versions.
982  *
983  * Following is the list of all currently supported formats:
984  *<pre>
985 Sample date:
986 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
987
988 Format  Output      Description
989 ------  ----------  --------------------------------------------------------------
990   d      10         Day of the month, 2 digits with leading zeros
991   D      Wed        A textual representation of a day, three letters
992   j      10         Day of the month without leading zeros
993   l      Wednesday  A full textual representation of the day of the week
994   S      th         English ordinal day of month suffix, 2 chars (use with j)
995   w      3          Numeric representation of the day of the week
996   z      9          The julian date, or day of the year (0-365)
997   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
998   F      January    A full textual representation of the month
999   m      01         Numeric representation of a month, with leading zeros
1000   M      Jan        Month name abbreviation, three letters
1001   n      1          Numeric representation of a month, without leading zeros
1002   t      31         Number of days in the given month
1003   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1004   Y      2007       A full numeric representation of a year, 4 digits
1005   y      07         A two digit representation of a year
1006   a      pm         Lowercase Ante meridiem and Post meridiem
1007   A      PM         Uppercase Ante meridiem and Post meridiem
1008   g      3          12-hour format of an hour without leading zeros
1009   G      15         24-hour format of an hour without leading zeros
1010   h      03         12-hour format of an hour with leading zeros
1011   H      15         24-hour format of an hour with leading zeros
1012   i      05         Minutes with leading zeros
1013   s      01         Seconds, with leading zeros
1014   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1015   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1016   T      CST        Timezone setting of the machine running the code
1017   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1018 </pre>
1019  *
1020  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1021  * <pre><code>
1022 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1023 document.write(dt.format('Y-m-d'));                         //2007-01-10
1024 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1025 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
1026  </code></pre>
1027  *
1028  * Here are some standard date/time patterns that you might find helpful.  They
1029  * are not part of the source of Date.js, but to use them you can simply copy this
1030  * block of code into any script that is included after Date.js and they will also become
1031  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1032  * <pre><code>
1033 Date.patterns = {
1034     ISO8601Long:"Y-m-d H:i:s",
1035     ISO8601Short:"Y-m-d",
1036     ShortDate: "n/j/Y",
1037     LongDate: "l, F d, Y",
1038     FullDateTime: "l, F d, Y g:i:s A",
1039     MonthDay: "F d",
1040     ShortTime: "g:i A",
1041     LongTime: "g:i:s A",
1042     SortableDateTime: "Y-m-d\\TH:i:s",
1043     UniversalSortableDateTime: "Y-m-d H:i:sO",
1044     YearMonth: "F, Y"
1045 };
1046 </code></pre>
1047  *
1048  * Example usage:
1049  * <pre><code>
1050 var dt = new Date();
1051 document.write(dt.format(Date.patterns.ShortDate));
1052  </code></pre>
1053  */
1054
1055 /*
1056  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1057  * They generate precompiled functions from date formats instead of parsing and
1058  * processing the pattern every time you format a date.  These functions are available
1059  * on every Date object (any javascript function).
1060  *
1061  * The original article and download are here:
1062  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1063  *
1064  */
1065  
1066  
1067  // was in core
1068 /**
1069  Returns the number of milliseconds between this date and date
1070  @param {Date} date (optional) Defaults to now
1071  @return {Number} The diff in milliseconds
1072  @member Date getElapsed
1073  */
1074 Date.prototype.getElapsed = function(date) {
1075         return Math.abs((date || new Date()).getTime()-this.getTime());
1076 };
1077 // was in date file..
1078
1079
1080 // private
1081 Date.parseFunctions = {count:0};
1082 // private
1083 Date.parseRegexes = [];
1084 // private
1085 Date.formatFunctions = {count:0};
1086
1087 // private
1088 Date.prototype.dateFormat = function(format) {
1089     if (Date.formatFunctions[format] == null) {
1090         Date.createNewFormat(format);
1091     }
1092     var func = Date.formatFunctions[format];
1093     return this[func]();
1094 };
1095
1096
1097 /**
1098  * Formats a date given the supplied format string
1099  * @param {String} format The format string
1100  * @return {String} The formatted date
1101  * @method
1102  */
1103 Date.prototype.format = Date.prototype.dateFormat;
1104
1105 // private
1106 Date.createNewFormat = function(format) {
1107     var funcName = "format" + Date.formatFunctions.count++;
1108     Date.formatFunctions[format] = funcName;
1109     var code = "Date.prototype." + funcName + " = function(){return ";
1110     var special = false;
1111     var ch = '';
1112     for (var i = 0; i < format.length; ++i) {
1113         ch = format.charAt(i);
1114         if (!special && ch == "\\") {
1115             special = true;
1116         }
1117         else if (special) {
1118             special = false;
1119             code += "'" + String.escape(ch) + "' + ";
1120         }
1121         else {
1122             code += Date.getFormatCode(ch);
1123         }
1124     }
1125     /** eval:var:zzzzzzzzzzzzz */
1126     eval(code.substring(0, code.length - 3) + ";}");
1127 };
1128
1129 // private
1130 Date.getFormatCode = function(character) {
1131     switch (character) {
1132     case "d":
1133         return "String.leftPad(this.getDate(), 2, '0') + ";
1134     case "D":
1135         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1136     case "j":
1137         return "this.getDate() + ";
1138     case "l":
1139         return "Date.dayNames[this.getDay()] + ";
1140     case "S":
1141         return "this.getSuffix() + ";
1142     case "w":
1143         return "this.getDay() + ";
1144     case "z":
1145         return "this.getDayOfYear() + ";
1146     case "W":
1147         return "this.getWeekOfYear() + ";
1148     case "F":
1149         return "Date.monthNames[this.getMonth()] + ";
1150     case "m":
1151         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1152     case "M":
1153         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1154     case "n":
1155         return "(this.getMonth() + 1) + ";
1156     case "t":
1157         return "this.getDaysInMonth() + ";
1158     case "L":
1159         return "(this.isLeapYear() ? 1 : 0) + ";
1160     case "Y":
1161         return "this.getFullYear() + ";
1162     case "y":
1163         return "('' + this.getFullYear()).substring(2, 4) + ";
1164     case "a":
1165         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1166     case "A":
1167         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1168     case "g":
1169         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1170     case "G":
1171         return "this.getHours() + ";
1172     case "h":
1173         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1174     case "H":
1175         return "String.leftPad(this.getHours(), 2, '0') + ";
1176     case "i":
1177         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1178     case "s":
1179         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1180     case "O":
1181         return "this.getGMTOffset() + ";
1182     case "P":
1183         return "this.getGMTColonOffset() + ";
1184     case "T":
1185         return "this.getTimezone() + ";
1186     case "Z":
1187         return "(this.getTimezoneOffset() * -60) + ";
1188     default:
1189         return "'" + String.escape(character) + "' + ";
1190     }
1191 };
1192
1193 /**
1194  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1195  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1196  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1197  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1198  * string or the parse operation will fail.
1199  * Example Usage:
1200 <pre><code>
1201 //dt = Fri May 25 2007 (current date)
1202 var dt = new Date();
1203
1204 //dt = Thu May 25 2006 (today's month/day in 2006)
1205 dt = Date.parseDate("2006", "Y");
1206
1207 //dt = Sun Jan 15 2006 (all date parts specified)
1208 dt = Date.parseDate("2006-1-15", "Y-m-d");
1209
1210 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1211 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1212 </code></pre>
1213  * @param {String} input The unparsed date as a string
1214  * @param {String} format The format the date is in
1215  * @return {Date} The parsed date
1216  * @static
1217  */
1218 Date.parseDate = function(input, format) {
1219     if (Date.parseFunctions[format] == null) {
1220         Date.createParser(format);
1221     }
1222     var func = Date.parseFunctions[format];
1223     return Date[func](input);
1224 };
1225 /**
1226  * @private
1227  */
1228 Date.createParser = function(format) {
1229     var funcName = "parse" + Date.parseFunctions.count++;
1230     var regexNum = Date.parseRegexes.length;
1231     var currentGroup = 1;
1232     Date.parseFunctions[format] = funcName;
1233
1234     var code = "Date." + funcName + " = function(input){\n"
1235         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1236         + "var d = new Date();\n"
1237         + "y = d.getFullYear();\n"
1238         + "m = d.getMonth();\n"
1239         + "d = d.getDate();\n"
1240         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1241         + "if (results && results.length > 0) {";
1242     var regex = "";
1243
1244     var special = false;
1245     var ch = '';
1246     for (var i = 0; i < format.length; ++i) {
1247         ch = format.charAt(i);
1248         if (!special && ch == "\\") {
1249             special = true;
1250         }
1251         else if (special) {
1252             special = false;
1253             regex += String.escape(ch);
1254         }
1255         else {
1256             var obj = Date.formatCodeToRegex(ch, currentGroup);
1257             currentGroup += obj.g;
1258             regex += obj.s;
1259             if (obj.g && obj.c) {
1260                 code += obj.c;
1261             }
1262         }
1263     }
1264
1265     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1266         + "{v = new Date(y, m, d, h, i, s);}\n"
1267         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1268         + "{v = new Date(y, m, d, h, i);}\n"
1269         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1270         + "{v = new Date(y, m, d, h);}\n"
1271         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1272         + "{v = new Date(y, m, d);}\n"
1273         + "else if (y >= 0 && m >= 0)\n"
1274         + "{v = new Date(y, m);}\n"
1275         + "else if (y >= 0)\n"
1276         + "{v = new Date(y);}\n"
1277         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1278         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1279         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1280         + ";}";
1281
1282     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1283     /** eval:var:zzzzzzzzzzzzz */
1284     eval(code);
1285 };
1286
1287 // private
1288 Date.formatCodeToRegex = function(character, currentGroup) {
1289     switch (character) {
1290     case "D":
1291         return {g:0,
1292         c:null,
1293         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1294     case "j":
1295         return {g:1,
1296             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1297             s:"(\\d{1,2})"}; // day of month without leading zeroes
1298     case "d":
1299         return {g:1,
1300             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1301             s:"(\\d{2})"}; // day of month with leading zeroes
1302     case "l":
1303         return {g:0,
1304             c:null,
1305             s:"(?:" + Date.dayNames.join("|") + ")"};
1306     case "S":
1307         return {g:0,
1308             c:null,
1309             s:"(?:st|nd|rd|th)"};
1310     case "w":
1311         return {g:0,
1312             c:null,
1313             s:"\\d"};
1314     case "z":
1315         return {g:0,
1316             c:null,
1317             s:"(?:\\d{1,3})"};
1318     case "W":
1319         return {g:0,
1320             c:null,
1321             s:"(?:\\d{2})"};
1322     case "F":
1323         return {g:1,
1324             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1325             s:"(" + Date.monthNames.join("|") + ")"};
1326     case "M":
1327         return {g:1,
1328             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1329             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1330     case "n":
1331         return {g:1,
1332             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1333             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1334     case "m":
1335         return {g:1,
1336             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1337             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1338     case "t":
1339         return {g:0,
1340             c:null,
1341             s:"\\d{1,2}"};
1342     case "L":
1343         return {g:0,
1344             c:null,
1345             s:"(?:1|0)"};
1346     case "Y":
1347         return {g:1,
1348             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349             s:"(\\d{4})"};
1350     case "y":
1351         return {g:1,
1352             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1353                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354             s:"(\\d{1,2})"};
1355     case "a":
1356         return {g:1,
1357             c:"if (results[" + currentGroup + "] == 'am') {\n"
1358                 + "if (h == 12) { h = 0; }\n"
1359                 + "} else { if (h < 12) { h += 12; }}",
1360             s:"(am|pm)"};
1361     case "A":
1362         return {g:1,
1363             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1364                 + "if (h == 12) { h = 0; }\n"
1365                 + "} else { if (h < 12) { h += 12; }}",
1366             s:"(AM|PM)"};
1367     case "g":
1368     case "G":
1369         return {g:1,
1370             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1372     case "h":
1373     case "H":
1374         return {g:1,
1375             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1376             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1377     case "i":
1378         return {g:1,
1379             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380             s:"(\\d{2})"};
1381     case "s":
1382         return {g:1,
1383             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1384             s:"(\\d{2})"};
1385     case "O":
1386         return {g:1,
1387             c:[
1388                 "o = results[", currentGroup, "];\n",
1389                 "var sn = o.substring(0,1);\n", // get + / - sign
1390                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1391                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1392                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1393                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1394             ].join(""),
1395             s:"([+\-]\\d{2,4})"};
1396     
1397     
1398     case "P":
1399         return {g:1,
1400                 c:[
1401                    "o = results[", currentGroup, "];\n",
1402                    "var sn = o.substring(0,1);\n",
1403                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1404                    "var mn = o.substring(4,6) % 60;\n",
1405                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1406                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407             ].join(""),
1408             s:"([+\-]\\d{4})"};
1409     case "T":
1410         return {g:0,
1411             c:null,
1412             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1413     case "Z":
1414         return {g:1,
1415             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1416                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1417             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418     default:
1419         return {g:0,
1420             c:null,
1421             s:String.escape(character)};
1422     }
1423 };
1424
1425 /**
1426  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1427  * @return {String} The abbreviated timezone name (e.g. 'CST')
1428  */
1429 Date.prototype.getTimezone = function() {
1430     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 };
1432
1433 /**
1434  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1435  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1436  */
1437 Date.prototype.getGMTOffset = function() {
1438     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1439         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1440         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 };
1442
1443 /**
1444  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1445  * @return {String} 2-characters representing hours and 2-characters representing minutes
1446  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1447  */
1448 Date.prototype.getGMTColonOffset = function() {
1449         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1450                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1451                 + ":"
1452                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 }
1454
1455 /**
1456  * Get the numeric day number of the year, adjusted for leap year.
1457  * @return {Number} 0 through 364 (365 in leap years)
1458  */
1459 Date.prototype.getDayOfYear = function() {
1460     var num = 0;
1461     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1462     for (var i = 0; i < this.getMonth(); ++i) {
1463         num += Date.daysInMonth[i];
1464     }
1465     return num + this.getDate() - 1;
1466 };
1467
1468 /**
1469  * Get the string representation of the numeric week number of the year
1470  * (equivalent to the format specifier 'W').
1471  * @return {String} '00' through '52'
1472  */
1473 Date.prototype.getWeekOfYear = function() {
1474     // Skip to Thursday of this week
1475     var now = this.getDayOfYear() + (4 - this.getDay());
1476     // Find the first Thursday of the year
1477     var jan1 = new Date(this.getFullYear(), 0, 1);
1478     var then = (7 - jan1.getDay() + 4);
1479     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 };
1481
1482 /**
1483  * Whether or not the current date is in a leap year.
1484  * @return {Boolean} True if the current date is in a leap year, else false
1485  */
1486 Date.prototype.isLeapYear = function() {
1487     var year = this.getFullYear();
1488     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 };
1490
1491 /**
1492  * Get the first day of the current month, adjusted for leap year.  The returned value
1493  * is the numeric day index within the week (0-6) which can be used in conjunction with
1494  * the {@link #monthNames} array to retrieve the textual day name.
1495  * Example:
1496  *<pre><code>
1497 var dt = new Date('1/10/2007');
1498 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1499 </code></pre>
1500  * @return {Number} The day number (0-6)
1501  */
1502 Date.prototype.getFirstDayOfMonth = function() {
1503     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1504     return (day < 0) ? (day + 7) : day;
1505 };
1506
1507 /**
1508  * Get the last day of the current month, adjusted for leap year.  The returned value
1509  * is the numeric day index within the week (0-6) which can be used in conjunction with
1510  * the {@link #monthNames} array to retrieve the textual day name.
1511  * Example:
1512  *<pre><code>
1513 var dt = new Date('1/10/2007');
1514 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1515 </code></pre>
1516  * @return {Number} The day number (0-6)
1517  */
1518 Date.prototype.getLastDayOfMonth = function() {
1519     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1520     return (day < 0) ? (day + 7) : day;
1521 };
1522
1523
1524 /**
1525  * Get the first date of this date's month
1526  * @return {Date}
1527  */
1528 Date.prototype.getFirstDateOfMonth = function() {
1529     return new Date(this.getFullYear(), this.getMonth(), 1);
1530 };
1531
1532 /**
1533  * Get the last date of this date's month
1534  * @return {Date}
1535  */
1536 Date.prototype.getLastDateOfMonth = function() {
1537     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1538 };
1539 /**
1540  * Get the number of days in the current month, adjusted for leap year.
1541  * @return {Number} The number of days in the month
1542  */
1543 Date.prototype.getDaysInMonth = function() {
1544     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1545     return Date.daysInMonth[this.getMonth()];
1546 };
1547
1548 /**
1549  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1550  * @return {String} 'st, 'nd', 'rd' or 'th'
1551  */
1552 Date.prototype.getSuffix = function() {
1553     switch (this.getDate()) {
1554         case 1:
1555         case 21:
1556         case 31:
1557             return "st";
1558         case 2:
1559         case 22:
1560             return "nd";
1561         case 3:
1562         case 23:
1563             return "rd";
1564         default:
1565             return "th";
1566     }
1567 };
1568
1569 // private
1570 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1571
1572 /**
1573  * An array of textual month names.
1574  * Override these values for international dates, for example...
1575  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1576  * @type Array
1577  * @static
1578  */
1579 Date.monthNames =
1580    ["January",
1581     "February",
1582     "March",
1583     "April",
1584     "May",
1585     "June",
1586     "July",
1587     "August",
1588     "September",
1589     "October",
1590     "November",
1591     "December"];
1592
1593 /**
1594  * An array of textual day names.
1595  * Override these values for international dates, for example...
1596  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1597  * @type Array
1598  * @static
1599  */
1600 Date.dayNames =
1601    ["Sunday",
1602     "Monday",
1603     "Tuesday",
1604     "Wednesday",
1605     "Thursday",
1606     "Friday",
1607     "Saturday"];
1608
1609 // private
1610 Date.y2kYear = 50;
1611 // private
1612 Date.monthNumbers = {
1613     Jan:0,
1614     Feb:1,
1615     Mar:2,
1616     Apr:3,
1617     May:4,
1618     Jun:5,
1619     Jul:6,
1620     Aug:7,
1621     Sep:8,
1622     Oct:9,
1623     Nov:10,
1624     Dec:11};
1625
1626 /**
1627  * Creates and returns a new Date instance with the exact same date value as the called instance.
1628  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1629  * variable will also be changed.  When the intention is to create a new variable that will not
1630  * modify the original instance, you should create a clone.
1631  *
1632  * Example of correctly cloning a date:
1633  * <pre><code>
1634 //wrong way:
1635 var orig = new Date('10/1/2006');
1636 var copy = orig;
1637 copy.setDate(5);
1638 document.write(orig);  //returns 'Thu Oct 05 2006'!
1639
1640 //correct way:
1641 var orig = new Date('10/1/2006');
1642 var copy = orig.clone();
1643 copy.setDate(5);
1644 document.write(orig);  //returns 'Thu Oct 01 2006'
1645 </code></pre>
1646  * @return {Date} The new Date instance
1647  */
1648 Date.prototype.clone = function() {
1649         return new Date(this.getTime());
1650 };
1651
1652 /**
1653  * Clears any time information from this date
1654  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1655  @return {Date} this or the clone
1656  */
1657 Date.prototype.clearTime = function(clone){
1658     if(clone){
1659         return this.clone().clearTime();
1660     }
1661     this.setHours(0);
1662     this.setMinutes(0);
1663     this.setSeconds(0);
1664     this.setMilliseconds(0);
1665     return this;
1666 };
1667
1668 // private
1669 // safari setMonth is broken
1670 if(Roo.isSafari){
1671     Date.brokenSetMonth = Date.prototype.setMonth;
1672         Date.prototype.setMonth = function(num){
1673                 if(num <= -1){
1674                         var n = Math.ceil(-num);
1675                         var back_year = Math.ceil(n/12);
1676                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1677                         this.setFullYear(this.getFullYear() - back_year);
1678                         return Date.brokenSetMonth.call(this, month);
1679                 } else {
1680                         return Date.brokenSetMonth.apply(this, arguments);
1681                 }
1682         };
1683 }
1684
1685 /** Date interval constant 
1686 * @static 
1687 * @type String */
1688 Date.MILLI = "ms";
1689 /** Date interval constant 
1690 * @static 
1691 * @type String */
1692 Date.SECOND = "s";
1693 /** Date interval constant 
1694 * @static 
1695 * @type String */
1696 Date.MINUTE = "mi";
1697 /** Date interval constant 
1698 * @static 
1699 * @type String */
1700 Date.HOUR = "h";
1701 /** Date interval constant 
1702 * @static 
1703 * @type String */
1704 Date.DAY = "d";
1705 /** Date interval constant 
1706 * @static 
1707 * @type String */
1708 Date.MONTH = "mo";
1709 /** Date interval constant 
1710 * @static 
1711 * @type String */
1712 Date.YEAR = "y";
1713
1714 /**
1715  * Provides a convenient method of performing basic date arithmetic.  This method
1716  * does not modify the Date instance being called - it creates and returns
1717  * a new Date instance containing the resulting date value.
1718  *
1719  * Examples:
1720  * <pre><code>
1721 //Basic usage:
1722 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1723 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1724
1725 //Negative values will subtract correctly:
1726 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1727 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1728
1729 //You can even chain several calls together in one line!
1730 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1731 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1732  </code></pre>
1733  *
1734  * @param {String} interval   A valid date interval enum value
1735  * @param {Number} value      The amount to add to the current date
1736  * @return {Date} The new Date instance
1737  */
1738 Date.prototype.add = function(interval, value){
1739   var d = this.clone();
1740   if (!interval || value === 0) return d;
1741   switch(interval.toLowerCase()){
1742     case Date.MILLI:
1743       d.setMilliseconds(this.getMilliseconds() + value);
1744       break;
1745     case Date.SECOND:
1746       d.setSeconds(this.getSeconds() + value);
1747       break;
1748     case Date.MINUTE:
1749       d.setMinutes(this.getMinutes() + value);
1750       break;
1751     case Date.HOUR:
1752       d.setHours(this.getHours() + value);
1753       break;
1754     case Date.DAY:
1755       d.setDate(this.getDate() + value);
1756       break;
1757     case Date.MONTH:
1758       var day = this.getDate();
1759       if(day > 28){
1760           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1761       }
1762       d.setDate(day);
1763       d.setMonth(this.getMonth() + value);
1764       break;
1765     case Date.YEAR:
1766       d.setFullYear(this.getFullYear() + value);
1767       break;
1768   }
1769   return d;
1770 };
1771 /*
1772  * Based on:
1773  * Ext JS Library 1.1.1
1774  * Copyright(c) 2006-2007, Ext JS, LLC.
1775  *
1776  * Originally Released Under LGPL - original licence link has changed is not relivant.
1777  *
1778  * Fork - LGPL
1779  * <script type="text/javascript">
1780  */
1781
1782 /**
1783  * @class Roo.lib.Dom
1784  * @static
1785  * 
1786  * Dom utils (from YIU afaik)
1787  * 
1788  **/
1789 Roo.lib.Dom = {
1790     /**
1791      * Get the view width
1792      * @param {Boolean} full True will get the full document, otherwise it's the view width
1793      * @return {Number} The width
1794      */
1795      
1796     getViewWidth : function(full) {
1797         return full ? this.getDocumentWidth() : this.getViewportWidth();
1798     },
1799     /**
1800      * Get the view height
1801      * @param {Boolean} full True will get the full document, otherwise it's the view height
1802      * @return {Number} The height
1803      */
1804     getViewHeight : function(full) {
1805         return full ? this.getDocumentHeight() : this.getViewportHeight();
1806     },
1807
1808     getDocumentHeight: function() {
1809         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1810         return Math.max(scrollHeight, this.getViewportHeight());
1811     },
1812
1813     getDocumentWidth: function() {
1814         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1815         return Math.max(scrollWidth, this.getViewportWidth());
1816     },
1817
1818     getViewportHeight: function() {
1819         var height = self.innerHeight;
1820         var mode = document.compatMode;
1821
1822         if ((mode || Roo.isIE) && !Roo.isOpera) {
1823             height = (mode == "CSS1Compat") ?
1824                      document.documentElement.clientHeight :
1825                      document.body.clientHeight;
1826         }
1827
1828         return height;
1829     },
1830
1831     getViewportWidth: function() {
1832         var width = self.innerWidth;
1833         var mode = document.compatMode;
1834
1835         if (mode || Roo.isIE) {
1836             width = (mode == "CSS1Compat") ?
1837                     document.documentElement.clientWidth :
1838                     document.body.clientWidth;
1839         }
1840         return width;
1841     },
1842
1843     isAncestor : function(p, c) {
1844         p = Roo.getDom(p);
1845         c = Roo.getDom(c);
1846         if (!p || !c) {
1847             return false;
1848         }
1849
1850         if (p.contains && !Roo.isSafari) {
1851             return p.contains(c);
1852         } else if (p.compareDocumentPosition) {
1853             return !!(p.compareDocumentPosition(c) & 16);
1854         } else {
1855             var parent = c.parentNode;
1856             while (parent) {
1857                 if (parent == p) {
1858                     return true;
1859                 }
1860                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1861                     return false;
1862                 }
1863                 parent = parent.parentNode;
1864             }
1865             return false;
1866         }
1867     },
1868
1869     getRegion : function(el) {
1870         return Roo.lib.Region.getRegion(el);
1871     },
1872
1873     getY : function(el) {
1874         return this.getXY(el)[1];
1875     },
1876
1877     getX : function(el) {
1878         return this.getXY(el)[0];
1879     },
1880
1881     getXY : function(el) {
1882         var p, pe, b, scroll, bd = document.body;
1883         el = Roo.getDom(el);
1884         var fly = Roo.lib.AnimBase.fly;
1885         if (el.getBoundingClientRect) {
1886             b = el.getBoundingClientRect();
1887             scroll = fly(document).getScroll();
1888             return [b.left + scroll.left, b.top + scroll.top];
1889         }
1890         var x = 0, y = 0;
1891
1892         p = el;
1893
1894         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1895
1896         while (p) {
1897
1898             x += p.offsetLeft;
1899             y += p.offsetTop;
1900
1901             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1902                 hasAbsolute = true;
1903             }
1904
1905             if (Roo.isGecko) {
1906                 pe = fly(p);
1907
1908                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1909                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1910
1911
1912                 x += bl;
1913                 y += bt;
1914
1915
1916                 if (p != el && pe.getStyle('overflow') != 'visible') {
1917                     x += bl;
1918                     y += bt;
1919                 }
1920             }
1921             p = p.offsetParent;
1922         }
1923
1924         if (Roo.isSafari && hasAbsolute) {
1925             x -= bd.offsetLeft;
1926             y -= bd.offsetTop;
1927         }
1928
1929         if (Roo.isGecko && !hasAbsolute) {
1930             var dbd = fly(bd);
1931             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1932             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933         }
1934
1935         p = el.parentNode;
1936         while (p && p != bd) {
1937             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1938                 x -= p.scrollLeft;
1939                 y -= p.scrollTop;
1940             }
1941             p = p.parentNode;
1942         }
1943         return [x, y];
1944     },
1945  
1946   
1947
1948
1949     setXY : function(el, xy) {
1950         el = Roo.fly(el, '_setXY');
1951         el.position();
1952         var pts = el.translatePoints(xy);
1953         if (xy[0] !== false) {
1954             el.dom.style.left = pts.left + "px";
1955         }
1956         if (xy[1] !== false) {
1957             el.dom.style.top = pts.top + "px";
1958         }
1959     },
1960
1961     setX : function(el, x) {
1962         this.setXY(el, [x, false]);
1963     },
1964
1965     setY : function(el, y) {
1966         this.setXY(el, [false, y]);
1967     }
1968 };
1969 /*
1970  * Portions of this file are based on pieces of Yahoo User Interface Library
1971  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1972  * YUI licensed under the BSD License:
1973  * http://developer.yahoo.net/yui/license.txt
1974  * <script type="text/javascript">
1975  *
1976  */
1977
1978 Roo.lib.Event = function() {
1979     var loadComplete = false;
1980     var listeners = [];
1981     var unloadListeners = [];
1982     var retryCount = 0;
1983     var onAvailStack = [];
1984     var counter = 0;
1985     var lastError = null;
1986
1987     return {
1988         POLL_RETRYS: 200,
1989         POLL_INTERVAL: 20,
1990         EL: 0,
1991         TYPE: 1,
1992         FN: 2,
1993         WFN: 3,
1994         OBJ: 3,
1995         ADJ_SCOPE: 4,
1996         _interval: null,
1997
1998         startInterval: function() {
1999             if (!this._interval) {
2000                 var self = this;
2001                 var callback = function() {
2002                     self._tryPreloadAttach();
2003                 };
2004                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2005
2006             }
2007         },
2008
2009         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2010             onAvailStack.push({ id:         p_id,
2011                 fn:         p_fn,
2012                 obj:        p_obj,
2013                 override:   p_override,
2014                 checkReady: false    });
2015
2016             retryCount = this.POLL_RETRYS;
2017             this.startInterval();
2018         },
2019
2020
2021         addListener: function(el, eventName, fn) {
2022             el = Roo.getDom(el);
2023             if (!el || !fn) {
2024                 return false;
2025             }
2026
2027             if ("unload" == eventName) {
2028                 unloadListeners[unloadListeners.length] =
2029                 [el, eventName, fn];
2030                 return true;
2031             }
2032
2033             var wrappedFn = function(e) {
2034                 return fn(Roo.lib.Event.getEvent(e));
2035             };
2036
2037             var li = [el, eventName, fn, wrappedFn];
2038
2039             var index = listeners.length;
2040             listeners[index] = li;
2041
2042             this.doAdd(el, eventName, wrappedFn, false);
2043             return true;
2044
2045         },
2046
2047
2048         removeListener: function(el, eventName, fn) {
2049             var i, len;
2050
2051             el = Roo.getDom(el);
2052
2053             if(!fn) {
2054                 return this.purgeElement(el, false, eventName);
2055             }
2056
2057
2058             if ("unload" == eventName) {
2059
2060                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2061                     var li = unloadListeners[i];
2062                     if (li &&
2063                         li[0] == el &&
2064                         li[1] == eventName &&
2065                         li[2] == fn) {
2066                         unloadListeners.splice(i, 1);
2067                         return true;
2068                     }
2069                 }
2070
2071                 return false;
2072             }
2073
2074             var cacheItem = null;
2075
2076
2077             var index = arguments[3];
2078
2079             if ("undefined" == typeof index) {
2080                 index = this._getCacheIndex(el, eventName, fn);
2081             }
2082
2083             if (index >= 0) {
2084                 cacheItem = listeners[index];
2085             }
2086
2087             if (!el || !cacheItem) {
2088                 return false;
2089             }
2090
2091             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2092
2093             delete listeners[index][this.WFN];
2094             delete listeners[index][this.FN];
2095             listeners.splice(index, 1);
2096
2097             return true;
2098
2099         },
2100
2101
2102         getTarget: function(ev, resolveTextNode) {
2103             ev = ev.browserEvent || ev;
2104             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2105             var t = ev.target || ev.srcElement;
2106             return this.resolveTextNode(t);
2107         },
2108
2109
2110         resolveTextNode: function(node) {
2111             if (Roo.isSafari && node && 3 == node.nodeType) {
2112                 return node.parentNode;
2113             } else {
2114                 return node;
2115             }
2116         },
2117
2118
2119         getPageX: function(ev) {
2120             ev = ev.browserEvent || ev;
2121             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2122             var x = ev.pageX;
2123             if (!x && 0 !== x) {
2124                 x = ev.clientX || 0;
2125
2126                 if (Roo.isIE) {
2127                     x += this.getScroll()[1];
2128                 }
2129             }
2130
2131             return x;
2132         },
2133
2134
2135         getPageY: function(ev) {
2136             ev = ev.browserEvent || ev;
2137             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2138             var y = ev.pageY;
2139             if (!y && 0 !== y) {
2140                 y = ev.clientY || 0;
2141
2142                 if (Roo.isIE) {
2143                     y += this.getScroll()[0];
2144                 }
2145             }
2146
2147
2148             return y;
2149         },
2150
2151
2152         getXY: function(ev) {
2153             ev = ev.browserEvent || ev;
2154             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2155             return [this.getPageX(ev), this.getPageY(ev)];
2156         },
2157
2158
2159         getRelatedTarget: function(ev) {
2160             ev = ev.browserEvent || ev;
2161             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2162             var t = ev.relatedTarget;
2163             if (!t) {
2164                 if (ev.type == "mouseout") {
2165                     t = ev.toElement;
2166                 } else if (ev.type == "mouseover") {
2167                     t = ev.fromElement;
2168                 }
2169             }
2170
2171             return this.resolveTextNode(t);
2172         },
2173
2174
2175         getTime: function(ev) {
2176             ev = ev.browserEvent || ev;
2177             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2178             if (!ev.time) {
2179                 var t = new Date().getTime();
2180                 try {
2181                     ev.time = t;
2182                 } catch(ex) {
2183                     this.lastError = ex;
2184                     return t;
2185                 }
2186             }
2187
2188             return ev.time;
2189         },
2190
2191
2192         stopEvent: function(ev) {
2193             this.stopPropagation(ev);
2194             this.preventDefault(ev);
2195         },
2196
2197
2198         stopPropagation: function(ev) {
2199             ev = ev.browserEvent || ev;
2200             if (ev.stopPropagation) {
2201                 ev.stopPropagation();
2202             } else {
2203                 ev.cancelBubble = true;
2204             }
2205         },
2206
2207
2208         preventDefault: function(ev) {
2209             ev = ev.browserEvent || ev;
2210             if(ev.preventDefault) {
2211                 ev.preventDefault();
2212             } else {
2213                 ev.returnValue = false;
2214             }
2215         },
2216
2217
2218         getEvent: function(e) {
2219             var ev = e || window.event;
2220             if (!ev) {
2221                 var c = this.getEvent.caller;
2222                 while (c) {
2223                     ev = c.arguments[0];
2224                     if (ev && Event == ev.constructor) {
2225                         break;
2226                     }
2227                     c = c.caller;
2228                 }
2229             }
2230             return ev;
2231         },
2232
2233
2234         getCharCode: function(ev) {
2235             ev = ev.browserEvent || ev;
2236             return ev.charCode || ev.keyCode || 0;
2237         },
2238
2239
2240         _getCacheIndex: function(el, eventName, fn) {
2241             for (var i = 0,len = listeners.length; i < len; ++i) {
2242                 var li = listeners[i];
2243                 if (li &&
2244                     li[this.FN] == fn &&
2245                     li[this.EL] == el &&
2246                     li[this.TYPE] == eventName) {
2247                     return i;
2248                 }
2249             }
2250
2251             return -1;
2252         },
2253
2254
2255         elCache: {},
2256
2257
2258         getEl: function(id) {
2259             return document.getElementById(id);
2260         },
2261
2262
2263         clearCache: function() {
2264         },
2265
2266
2267         _load: function(e) {
2268             loadComplete = true;
2269             var EU = Roo.lib.Event;
2270
2271
2272             if (Roo.isIE) {
2273                 EU.doRemove(window, "load", EU._load);
2274             }
2275         },
2276
2277
2278         _tryPreloadAttach: function() {
2279
2280             if (this.locked) {
2281                 return false;
2282             }
2283
2284             this.locked = true;
2285
2286
2287             var tryAgain = !loadComplete;
2288             if (!tryAgain) {
2289                 tryAgain = (retryCount > 0);
2290             }
2291
2292
2293             var notAvail = [];
2294             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2295                 var item = onAvailStack[i];
2296                 if (item) {
2297                     var el = this.getEl(item.id);
2298
2299                     if (el) {
2300                         if (!item.checkReady ||
2301                             loadComplete ||
2302                             el.nextSibling ||
2303                             (document && document.body)) {
2304
2305                             var scope = el;
2306                             if (item.override) {
2307                                 if (item.override === true) {
2308                                     scope = item.obj;
2309                                 } else {
2310                                     scope = item.override;
2311                                 }
2312                             }
2313                             item.fn.call(scope, item.obj);
2314                             onAvailStack[i] = null;
2315                         }
2316                     } else {
2317                         notAvail.push(item);
2318                     }
2319                 }
2320             }
2321
2322             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323
2324             if (tryAgain) {
2325
2326                 this.startInterval();
2327             } else {
2328                 clearInterval(this._interval);
2329                 this._interval = null;
2330             }
2331
2332             this.locked = false;
2333
2334             return true;
2335
2336         },
2337
2338
2339         purgeElement: function(el, recurse, eventName) {
2340             var elListeners = this.getListeners(el, eventName);
2341             if (elListeners) {
2342                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2343                     var l = elListeners[i];
2344                     this.removeListener(el, l.type, l.fn);
2345                 }
2346             }
2347
2348             if (recurse && el && el.childNodes) {
2349                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2350                     this.purgeElement(el.childNodes[i], recurse, eventName);
2351                 }
2352             }
2353         },
2354
2355
2356         getListeners: function(el, eventName) {
2357             var results = [], searchLists;
2358             if (!eventName) {
2359                 searchLists = [listeners, unloadListeners];
2360             } else if (eventName == "unload") {
2361                 searchLists = [unloadListeners];
2362             } else {
2363                 searchLists = [listeners];
2364             }
2365
2366             for (var j = 0; j < searchLists.length; ++j) {
2367                 var searchList = searchLists[j];
2368                 if (searchList && searchList.length > 0) {
2369                     for (var i = 0,len = searchList.length; i < len; ++i) {
2370                         var l = searchList[i];
2371                         if (l && l[this.EL] === el &&
2372                             (!eventName || eventName === l[this.TYPE])) {
2373                             results.push({
2374                                 type:   l[this.TYPE],
2375                                 fn:     l[this.FN],
2376                                 obj:    l[this.OBJ],
2377                                 adjust: l[this.ADJ_SCOPE],
2378                                 index:  i
2379                             });
2380                         }
2381                     }
2382                 }
2383             }
2384
2385             return (results.length) ? results : null;
2386         },
2387
2388
2389         _unload: function(e) {
2390
2391             var EU = Roo.lib.Event, i, j, l, len, index;
2392
2393             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2394                 l = unloadListeners[i];
2395                 if (l) {
2396                     var scope = window;
2397                     if (l[EU.ADJ_SCOPE]) {
2398                         if (l[EU.ADJ_SCOPE] === true) {
2399                             scope = l[EU.OBJ];
2400                         } else {
2401                             scope = l[EU.ADJ_SCOPE];
2402                         }
2403                     }
2404                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2405                     unloadListeners[i] = null;
2406                     l = null;
2407                     scope = null;
2408                 }
2409             }
2410
2411             unloadListeners = null;
2412
2413             if (listeners && listeners.length > 0) {
2414                 j = listeners.length;
2415                 while (j) {
2416                     index = j - 1;
2417                     l = listeners[index];
2418                     if (l) {
2419                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2420                                 l[EU.FN], index);
2421                     }
2422                     j = j - 1;
2423                 }
2424                 l = null;
2425
2426                 EU.clearCache();
2427             }
2428
2429             EU.doRemove(window, "unload", EU._unload);
2430
2431         },
2432
2433
2434         getScroll: function() {
2435             var dd = document.documentElement, db = document.body;
2436             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2437                 return [dd.scrollTop, dd.scrollLeft];
2438             } else if (db) {
2439                 return [db.scrollTop, db.scrollLeft];
2440             } else {
2441                 return [0, 0];
2442             }
2443         },
2444
2445
2446         doAdd: function () {
2447             if (window.addEventListener) {
2448                 return function(el, eventName, fn, capture) {
2449                     el.addEventListener(eventName, fn, (capture));
2450                 };
2451             } else if (window.attachEvent) {
2452                 return function(el, eventName, fn, capture) {
2453                     el.attachEvent("on" + eventName, fn);
2454                 };
2455             } else {
2456                 return function() {
2457                 };
2458             }
2459         }(),
2460
2461
2462         doRemove: function() {
2463             if (window.removeEventListener) {
2464                 return function (el, eventName, fn, capture) {
2465                     el.removeEventListener(eventName, fn, (capture));
2466                 };
2467             } else if (window.detachEvent) {
2468                 return function (el, eventName, fn) {
2469                     el.detachEvent("on" + eventName, fn);
2470                 };
2471             } else {
2472                 return function() {
2473                 };
2474             }
2475         }()
2476     };
2477     
2478 }();
2479 (function() {     
2480    
2481     var E = Roo.lib.Event;
2482     E.on = E.addListener;
2483     E.un = E.removeListener;
2484
2485     if (document && document.body) {
2486         E._load();
2487     } else {
2488         E.doAdd(window, "load", E._load);
2489     }
2490     E.doAdd(window, "unload", E._unload);
2491     E._tryPreloadAttach();
2492 })();
2493
2494 /*
2495  * Portions of this file are based on pieces of Yahoo User Interface Library
2496  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2497  * YUI licensed under the BSD License:
2498  * http://developer.yahoo.net/yui/license.txt
2499  * <script type="text/javascript">
2500  *
2501  */
2502
2503 (function() {
2504     /**
2505      * @class Roo.lib.Ajax
2506      *
2507      */
2508     Roo.lib.Ajax = {
2509         /**
2510          * @static 
2511          */
2512         request : function(method, uri, cb, data, options) {
2513             if(options){
2514                 var hs = options.headers;
2515                 if(hs){
2516                     for(var h in hs){
2517                         if(hs.hasOwnProperty(h)){
2518                             this.initHeader(h, hs[h], false);
2519                         }
2520                     }
2521                 }
2522                 if(options.xmlData){
2523                     this.initHeader('Content-Type', 'text/xml', false);
2524                     method = 'POST';
2525                     data = options.xmlData;
2526                 }
2527             }
2528
2529             return this.asyncRequest(method, uri, cb, data);
2530         },
2531
2532         serializeForm : function(form) {
2533             if(typeof form == 'string') {
2534                 form = (document.getElementById(form) || document.forms[form]);
2535             }
2536
2537             var el, name, val, disabled, data = '', hasSubmit = false;
2538             for (var i = 0; i < form.elements.length; i++) {
2539                 el = form.elements[i];
2540                 disabled = form.elements[i].disabled;
2541                 name = form.elements[i].name;
2542                 val = form.elements[i].value;
2543
2544                 if (!disabled && name){
2545                     switch (el.type)
2546                             {
2547                         case 'select-one':
2548                         case 'select-multiple':
2549                             for (var j = 0; j < el.options.length; j++) {
2550                                 if (el.options[j].selected) {
2551                                     if (Roo.isIE) {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                     else {
2555                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2556                                     }
2557                                 }
2558                             }
2559                             break;
2560                         case 'radio':
2561                         case 'checkbox':
2562                             if (el.checked) {
2563                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2564                             }
2565                             break;
2566                         case 'file':
2567
2568                         case undefined:
2569
2570                         case 'reset':
2571
2572                         case 'button':
2573
2574                             break;
2575                         case 'submit':
2576                             if(hasSubmit == false) {
2577                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2578                                 hasSubmit = true;
2579                             }
2580                             break;
2581                         default:
2582                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2583                             break;
2584                     }
2585                 }
2586             }
2587             data = data.substr(0, data.length - 1);
2588             return data;
2589         },
2590
2591         headers:{},
2592
2593         hasHeaders:false,
2594
2595         useDefaultHeader:true,
2596
2597         defaultPostHeader:'application/x-www-form-urlencoded',
2598
2599         useDefaultXhrHeader:true,
2600
2601         defaultXhrHeader:'XMLHttpRequest',
2602
2603         hasDefaultHeaders:true,
2604
2605         defaultHeaders:{},
2606
2607         poll:{},
2608
2609         timeout:{},
2610
2611         pollInterval:50,
2612
2613         transactionId:0,
2614
2615         setProgId:function(id)
2616         {
2617             this.activeX.unshift(id);
2618         },
2619
2620         setDefaultPostHeader:function(b)
2621         {
2622             this.useDefaultHeader = b;
2623         },
2624
2625         setDefaultXhrHeader:function(b)
2626         {
2627             this.useDefaultXhrHeader = b;
2628         },
2629
2630         setPollingInterval:function(i)
2631         {
2632             if (typeof i == 'number' && isFinite(i)) {
2633                 this.pollInterval = i;
2634             }
2635         },
2636
2637         createXhrObject:function(transactionId)
2638         {
2639             var obj,http;
2640             try
2641             {
2642
2643                 http = new XMLHttpRequest();
2644
2645                 obj = { conn:http, tId:transactionId };
2646             }
2647             catch(e)
2648             {
2649                 for (var i = 0; i < this.activeX.length; ++i) {
2650                     try
2651                     {
2652
2653                         http = new ActiveXObject(this.activeX[i]);
2654
2655                         obj = { conn:http, tId:transactionId };
2656                         break;
2657                     }
2658                     catch(e) {
2659                     }
2660                 }
2661             }
2662             finally
2663             {
2664                 return obj;
2665             }
2666         },
2667
2668         getConnectionObject:function()
2669         {
2670             var o;
2671             var tId = this.transactionId;
2672
2673             try
2674             {
2675                 o = this.createXhrObject(tId);
2676                 if (o) {
2677                     this.transactionId++;
2678                 }
2679             }
2680             catch(e) {
2681             }
2682             finally
2683             {
2684                 return o;
2685             }
2686         },
2687
2688         asyncRequest:function(method, uri, callback, postData)
2689         {
2690             var o = this.getConnectionObject();
2691
2692             if (!o) {
2693                 return null;
2694             }
2695             else {
2696                 o.conn.open(method, uri, true);
2697
2698                 if (this.useDefaultXhrHeader) {
2699                     if (!this.defaultHeaders['X-Requested-With']) {
2700                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701                     }
2702                 }
2703
2704                 if(postData && this.useDefaultHeader){
2705                     this.initHeader('Content-Type', this.defaultPostHeader);
2706                 }
2707
2708                  if (this.hasDefaultHeaders || this.hasHeaders) {
2709                     this.setHeader(o);
2710                 }
2711
2712                 this.handleReadyState(o, callback);
2713                 o.conn.send(postData || null);
2714
2715                 return o;
2716             }
2717         },
2718
2719         handleReadyState:function(o, callback)
2720         {
2721             var oConn = this;
2722
2723             if (callback && callback.timeout) {
2724                 
2725                 this.timeout[o.tId] = window.setTimeout(function() {
2726                     oConn.abort(o, callback, true);
2727                 }, callback.timeout);
2728             }
2729
2730             this.poll[o.tId] = window.setInterval(
2731                     function() {
2732                         if (o.conn && o.conn.readyState == 4) {
2733                             window.clearInterval(oConn.poll[o.tId]);
2734                             delete oConn.poll[o.tId];
2735
2736                             if(callback && callback.timeout) {
2737                                 window.clearTimeout(oConn.timeout[o.tId]);
2738                                 delete oConn.timeout[o.tId];
2739                             }
2740
2741                             oConn.handleTransactionResponse(o, callback);
2742                         }
2743                     }
2744                     , this.pollInterval);
2745         },
2746
2747         handleTransactionResponse:function(o, callback, isAbort)
2748         {
2749
2750             if (!callback) {
2751                 this.releaseObject(o);
2752                 return;
2753             }
2754
2755             var httpStatus, responseObject;
2756
2757             try
2758             {
2759                 if (o.conn.status !== undefined && o.conn.status != 0) {
2760                     httpStatus = o.conn.status;
2761                 }
2762                 else {
2763                     httpStatus = 13030;
2764                 }
2765             }
2766             catch(e) {
2767
2768
2769                 httpStatus = 13030;
2770             }
2771
2772             if (httpStatus >= 200 && httpStatus < 300) {
2773                 responseObject = this.createResponseObject(o, callback.argument);
2774                 if (callback.success) {
2775                     if (!callback.scope) {
2776                         callback.success(responseObject);
2777                     }
2778                     else {
2779
2780
2781                         callback.success.apply(callback.scope, [responseObject]);
2782                     }
2783                 }
2784             }
2785             else {
2786                 switch (httpStatus) {
2787
2788                     case 12002:
2789                     case 12029:
2790                     case 12030:
2791                     case 12031:
2792                     case 12152:
2793                     case 13030:
2794                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2795                         if (callback.failure) {
2796                             if (!callback.scope) {
2797                                 callback.failure(responseObject);
2798                             }
2799                             else {
2800                                 callback.failure.apply(callback.scope, [responseObject]);
2801                             }
2802                         }
2803                         break;
2804                     default:
2805                         responseObject = this.createResponseObject(o, callback.argument);
2806                         if (callback.failure) {
2807                             if (!callback.scope) {
2808                                 callback.failure(responseObject);
2809                             }
2810                             else {
2811                                 callback.failure.apply(callback.scope, [responseObject]);
2812                             }
2813                         }
2814                 }
2815             }
2816
2817             this.releaseObject(o);
2818             responseObject = null;
2819         },
2820
2821         createResponseObject:function(o, callbackArg)
2822         {
2823             var obj = {};
2824             var headerObj = {};
2825
2826             try
2827             {
2828                 var headerStr = o.conn.getAllResponseHeaders();
2829                 var header = headerStr.split('\n');
2830                 for (var i = 0; i < header.length; i++) {
2831                     var delimitPos = header[i].indexOf(':');
2832                     if (delimitPos != -1) {
2833                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2834                     }
2835                 }
2836             }
2837             catch(e) {
2838             }
2839
2840             obj.tId = o.tId;
2841             obj.status = o.conn.status;
2842             obj.statusText = o.conn.statusText;
2843             obj.getResponseHeader = headerObj;
2844             obj.getAllResponseHeaders = headerStr;
2845             obj.responseText = o.conn.responseText;
2846             obj.responseXML = o.conn.responseXML;
2847
2848             if (typeof callbackArg !== undefined) {
2849                 obj.argument = callbackArg;
2850             }
2851
2852             return obj;
2853         },
2854
2855         createExceptionObject:function(tId, callbackArg, isAbort)
2856         {
2857             var COMM_CODE = 0;
2858             var COMM_ERROR = 'communication failure';
2859             var ABORT_CODE = -1;
2860             var ABORT_ERROR = 'transaction aborted';
2861
2862             var obj = {};
2863
2864             obj.tId = tId;
2865             if (isAbort) {
2866                 obj.status = ABORT_CODE;
2867                 obj.statusText = ABORT_ERROR;
2868             }
2869             else {
2870                 obj.status = COMM_CODE;
2871                 obj.statusText = COMM_ERROR;
2872             }
2873
2874             if (callbackArg) {
2875                 obj.argument = callbackArg;
2876             }
2877
2878             return obj;
2879         },
2880
2881         initHeader:function(label, value, isDefault)
2882         {
2883             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2884
2885             if (headerObj[label] === undefined) {
2886                 headerObj[label] = value;
2887             }
2888             else {
2889
2890
2891                 headerObj[label] = value + "," + headerObj[label];
2892             }
2893
2894             if (isDefault) {
2895                 this.hasDefaultHeaders = true;
2896             }
2897             else {
2898                 this.hasHeaders = true;
2899             }
2900         },
2901
2902
2903         setHeader:function(o)
2904         {
2905             if (this.hasDefaultHeaders) {
2906                 for (var prop in this.defaultHeaders) {
2907                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2908                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2909                     }
2910                 }
2911             }
2912
2913             if (this.hasHeaders) {
2914                 for (var prop in this.headers) {
2915                     if (this.headers.hasOwnProperty(prop)) {
2916                         o.conn.setRequestHeader(prop, this.headers[prop]);
2917                     }
2918                 }
2919                 this.headers = {};
2920                 this.hasHeaders = false;
2921             }
2922         },
2923
2924         resetDefaultHeaders:function() {
2925             delete this.defaultHeaders;
2926             this.defaultHeaders = {};
2927             this.hasDefaultHeaders = false;
2928         },
2929
2930         abort:function(o, callback, isTimeout)
2931         {
2932             if(this.isCallInProgress(o)) {
2933                 o.conn.abort();
2934                 window.clearInterval(this.poll[o.tId]);
2935                 delete this.poll[o.tId];
2936                 if (isTimeout) {
2937                     delete this.timeout[o.tId];
2938                 }
2939
2940                 this.handleTransactionResponse(o, callback, true);
2941
2942                 return true;
2943             }
2944             else {
2945                 return false;
2946             }
2947         },
2948
2949
2950         isCallInProgress:function(o)
2951         {
2952             if (o && o.conn) {
2953                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2954             }
2955             else {
2956
2957                 return false;
2958             }
2959         },
2960
2961
2962         releaseObject:function(o)
2963         {
2964
2965             o.conn = null;
2966
2967             o = null;
2968         },
2969
2970         activeX:[
2971         'MSXML2.XMLHTTP.3.0',
2972         'MSXML2.XMLHTTP',
2973         'Microsoft.XMLHTTP'
2974         ]
2975
2976
2977     };
2978 })();/*
2979  * Portions of this file are based on pieces of Yahoo User Interface Library
2980  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2981  * YUI licensed under the BSD License:
2982  * http://developer.yahoo.net/yui/license.txt
2983  * <script type="text/javascript">
2984  *
2985  */
2986
2987 Roo.lib.Region = function(t, r, b, l) {
2988     this.top = t;
2989     this[1] = t;
2990     this.right = r;
2991     this.bottom = b;
2992     this.left = l;
2993     this[0] = l;
2994 };
2995
2996
2997 Roo.lib.Region.prototype = {
2998     contains : function(region) {
2999         return ( region.left >= this.left &&
3000                  region.right <= this.right &&
3001                  region.top >= this.top &&
3002                  region.bottom <= this.bottom    );
3003
3004     },
3005
3006     getArea : function() {
3007         return ( (this.bottom - this.top) * (this.right - this.left) );
3008     },
3009
3010     intersect : function(region) {
3011         var t = Math.max(this.top, region.top);
3012         var r = Math.min(this.right, region.right);
3013         var b = Math.min(this.bottom, region.bottom);
3014         var l = Math.max(this.left, region.left);
3015
3016         if (b >= t && r >= l) {
3017             return new Roo.lib.Region(t, r, b, l);
3018         } else {
3019             return null;
3020         }
3021     },
3022     union : function(region) {
3023         var t = Math.min(this.top, region.top);
3024         var r = Math.max(this.right, region.right);
3025         var b = Math.max(this.bottom, region.bottom);
3026         var l = Math.min(this.left, region.left);
3027
3028         return new Roo.lib.Region(t, r, b, l);
3029     },
3030
3031     adjust : function(t, l, b, r) {
3032         this.top += t;
3033         this.left += l;
3034         this.right += r;
3035         this.bottom += b;
3036         return this;
3037     }
3038 };
3039
3040 Roo.lib.Region.getRegion = function(el) {
3041     var p = Roo.lib.Dom.getXY(el);
3042
3043     var t = p[1];
3044     var r = p[0] + el.offsetWidth;
3045     var b = p[1] + el.offsetHeight;
3046     var l = p[0];
3047
3048     return new Roo.lib.Region(t, r, b, l);
3049 };
3050 /*
3051  * Portions of this file are based on pieces of Yahoo User Interface Library
3052  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3053  * YUI licensed under the BSD License:
3054  * http://developer.yahoo.net/yui/license.txt
3055  * <script type="text/javascript">
3056  *
3057  */
3058 //@@dep Roo.lib.Region
3059
3060
3061 Roo.lib.Point = function(x, y) {
3062     if (x instanceof Array) {
3063         y = x[1];
3064         x = x[0];
3065     }
3066     this.x = this.right = this.left = this[0] = x;
3067     this.y = this.top = this.bottom = this[1] = y;
3068 };
3069
3070 Roo.lib.Point.prototype = new Roo.lib.Region();
3071 /*
3072  * Portions of this file are based on pieces of Yahoo User Interface Library
3073  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3074  * YUI licensed under the BSD License:
3075  * http://developer.yahoo.net/yui/license.txt
3076  * <script type="text/javascript">
3077  *
3078  */
3079  
3080 (function() {   
3081
3082     Roo.lib.Anim = {
3083         scroll : function(el, args, duration, easing, cb, scope) {
3084             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3085         },
3086
3087         motion : function(el, args, duration, easing, cb, scope) {
3088             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3089         },
3090
3091         color : function(el, args, duration, easing, cb, scope) {
3092             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3093         },
3094
3095         run : function(el, args, duration, easing, cb, scope, type) {
3096             type = type || Roo.lib.AnimBase;
3097             if (typeof easing == "string") {
3098                 easing = Roo.lib.Easing[easing];
3099             }
3100             var anim = new type(el, args, duration, easing);
3101             anim.animateX(function() {
3102                 Roo.callback(cb, scope);
3103             });
3104             return anim;
3105         }
3106     };
3107 })();/*
3108  * Portions of this file are based on pieces of Yahoo User Interface Library
3109  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3110  * YUI licensed under the BSD License:
3111  * http://developer.yahoo.net/yui/license.txt
3112  * <script type="text/javascript">
3113  *
3114  */
3115
3116 (function() {    
3117     var libFlyweight;
3118     
3119     function fly(el) {
3120         if (!libFlyweight) {
3121             libFlyweight = new Roo.Element.Flyweight();
3122         }
3123         libFlyweight.dom = el;
3124         return libFlyweight;
3125     }
3126
3127     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128     
3129    
3130     
3131     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3132         if (el) {
3133             this.init(el, attributes, duration, method);
3134         }
3135     };
3136
3137     Roo.lib.AnimBase.fly = fly;
3138     
3139     
3140     
3141     Roo.lib.AnimBase.prototype = {
3142
3143         toString: function() {
3144             var el = this.getEl();
3145             var id = el.id || el.tagName;
3146             return ("Anim " + id);
3147         },
3148
3149         patterns: {
3150             noNegatives:        /width|height|opacity|padding/i,
3151             offsetAttribute:  /^((width|height)|(top|left))$/,
3152             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3153             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154         },
3155
3156
3157         doMethod: function(attr, start, end) {
3158             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159         },
3160
3161
3162         setAttribute: function(attr, val, unit) {
3163             if (this.patterns.noNegatives.test(attr)) {
3164                 val = (val > 0) ? val : 0;
3165             }
3166
3167             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168         },
3169
3170
3171         getAttribute: function(attr) {
3172             var el = this.getEl();
3173             var val = fly(el).getStyle(attr);
3174
3175             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3176                 return parseFloat(val);
3177             }
3178
3179             var a = this.patterns.offsetAttribute.exec(attr) || [];
3180             var pos = !!( a[3] );
3181             var box = !!( a[2] );
3182
3183
3184             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3185                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3186             } else {
3187                 val = 0;
3188             }
3189
3190             return val;
3191         },
3192
3193
3194         getDefaultUnit: function(attr) {
3195             if (this.patterns.defaultUnit.test(attr)) {
3196                 return 'px';
3197             }
3198
3199             return '';
3200         },
3201
3202         animateX : function(callback, scope) {
3203             var f = function() {
3204                 this.onComplete.removeListener(f);
3205                 if (typeof callback == "function") {
3206                     callback.call(scope || this, this);
3207                 }
3208             };
3209             this.onComplete.addListener(f, this);
3210             this.animate();
3211         },
3212
3213
3214         setRuntimeAttribute: function(attr) {
3215             var start;
3216             var end;
3217             var attributes = this.attributes;
3218
3219             this.runtimeAttributes[attr] = {};
3220
3221             var isset = function(prop) {
3222                 return (typeof prop !== 'undefined');
3223             };
3224
3225             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226                 return false;
3227             }
3228
3229             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3230
3231
3232             if (isset(attributes[attr]['to'])) {
3233                 end = attributes[attr]['to'];
3234             } else if (isset(attributes[attr]['by'])) {
3235                 if (start.constructor == Array) {
3236                     end = [];
3237                     for (var i = 0, len = start.length; i < len; ++i) {
3238                         end[i] = start[i] + attributes[attr]['by'][i];
3239                     }
3240                 } else {
3241                     end = start + attributes[attr]['by'];
3242                 }
3243             }
3244
3245             this.runtimeAttributes[attr].start = start;
3246             this.runtimeAttributes[attr].end = end;
3247
3248
3249             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250         },
3251
3252
3253         init: function(el, attributes, duration, method) {
3254
3255             var isAnimated = false;
3256
3257
3258             var startTime = null;
3259
3260
3261             var actualFrames = 0;
3262
3263
3264             el = Roo.getDom(el);
3265
3266
3267             this.attributes = attributes || {};
3268
3269
3270             this.duration = duration || 1;
3271
3272
3273             this.method = method || Roo.lib.Easing.easeNone;
3274
3275
3276             this.useSeconds = true;
3277
3278
3279             this.currentFrame = 0;
3280
3281
3282             this.totalFrames = Roo.lib.AnimMgr.fps;
3283
3284
3285             this.getEl = function() {
3286                 return el;
3287             };
3288
3289
3290             this.isAnimated = function() {
3291                 return isAnimated;
3292             };
3293
3294
3295             this.getStartTime = function() {
3296                 return startTime;
3297             };
3298
3299             this.runtimeAttributes = {};
3300
3301
3302             this.animate = function() {
3303                 if (this.isAnimated()) {
3304                     return false;
3305                 }
3306
3307                 this.currentFrame = 0;
3308
3309                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3310
3311                 Roo.lib.AnimMgr.registerElement(this);
3312             };
3313
3314
3315             this.stop = function(finish) {
3316                 if (finish) {
3317                     this.currentFrame = this.totalFrames;
3318                     this._onTween.fire();
3319                 }
3320                 Roo.lib.AnimMgr.stop(this);
3321             };
3322
3323             var onStart = function() {
3324                 this.onStart.fire();
3325
3326                 this.runtimeAttributes = {};
3327                 for (var attr in this.attributes) {
3328                     this.setRuntimeAttribute(attr);
3329                 }
3330
3331                 isAnimated = true;
3332                 actualFrames = 0;
3333                 startTime = new Date();
3334             };
3335
3336
3337             var onTween = function() {
3338                 var data = {
3339                     duration: new Date() - this.getStartTime(),
3340                     currentFrame: this.currentFrame
3341                 };
3342
3343                 data.toString = function() {
3344                     return (
3345                             'duration: ' + data.duration +
3346                             ', currentFrame: ' + data.currentFrame
3347                             );
3348                 };
3349
3350                 this.onTween.fire(data);
3351
3352                 var runtimeAttributes = this.runtimeAttributes;
3353
3354                 for (var attr in runtimeAttributes) {
3355                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3356                 }
3357
3358                 actualFrames += 1;
3359             };
3360
3361             var onComplete = function() {
3362                 var actual_duration = (new Date() - startTime) / 1000 ;
3363
3364                 var data = {
3365                     duration: actual_duration,
3366                     frames: actualFrames,
3367                     fps: actualFrames / actual_duration
3368                 };
3369
3370                 data.toString = function() {
3371                     return (
3372                             'duration: ' + data.duration +
3373                             ', frames: ' + data.frames +
3374                             ', fps: ' + data.fps
3375                             );
3376                 };
3377
3378                 isAnimated = false;
3379                 actualFrames = 0;
3380                 this.onComplete.fire(data);
3381             };
3382
3383
3384             this._onStart = new Roo.util.Event(this);
3385             this.onStart = new Roo.util.Event(this);
3386             this.onTween = new Roo.util.Event(this);
3387             this._onTween = new Roo.util.Event(this);
3388             this.onComplete = new Roo.util.Event(this);
3389             this._onComplete = new Roo.util.Event(this);
3390             this._onStart.addListener(onStart);
3391             this._onTween.addListener(onTween);
3392             this._onComplete.addListener(onComplete);
3393         }
3394     };
3395 })();
3396 /*
3397  * Portions of this file are based on pieces of Yahoo User Interface Library
3398  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3399  * YUI licensed under the BSD License:
3400  * http://developer.yahoo.net/yui/license.txt
3401  * <script type="text/javascript">
3402  *
3403  */
3404
3405 Roo.lib.AnimMgr = new function() {
3406
3407     var thread = null;
3408
3409
3410     var queue = [];
3411
3412
3413     var tweenCount = 0;
3414
3415
3416     this.fps = 1000;
3417
3418
3419     this.delay = 1;
3420
3421
3422     this.registerElement = function(tween) {
3423         queue[queue.length] = tween;
3424         tweenCount += 1;
3425         tween._onStart.fire();
3426         this.start();
3427     };
3428
3429
3430     this.unRegister = function(tween, index) {
3431         tween._onComplete.fire();
3432         index = index || getIndex(tween);
3433         if (index != -1) {
3434             queue.splice(index, 1);
3435         }
3436
3437         tweenCount -= 1;
3438         if (tweenCount <= 0) {
3439             this.stop();
3440         }
3441     };
3442
3443
3444     this.start = function() {
3445         if (thread === null) {
3446             thread = setInterval(this.run, this.delay);
3447         }
3448     };
3449
3450
3451     this.stop = function(tween) {
3452         if (!tween) {
3453             clearInterval(thread);
3454
3455             for (var i = 0, len = queue.length; i < len; ++i) {
3456                 if (queue[0].isAnimated()) {
3457                     this.unRegister(queue[0], 0);
3458                 }
3459             }
3460
3461             queue = [];
3462             thread = null;
3463             tweenCount = 0;
3464         }
3465         else {
3466             this.unRegister(tween);
3467         }
3468     };
3469
3470
3471     this.run = function() {
3472         for (var i = 0, len = queue.length; i < len; ++i) {
3473             var tween = queue[i];
3474             if (!tween || !tween.isAnimated()) {
3475                 continue;
3476             }
3477
3478             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3479             {
3480                 tween.currentFrame += 1;
3481
3482                 if (tween.useSeconds) {
3483                     correctFrame(tween);
3484                 }
3485                 tween._onTween.fire();
3486             }
3487             else {
3488                 Roo.lib.AnimMgr.stop(tween, i);
3489             }
3490         }
3491     };
3492
3493     var getIndex = function(anim) {
3494         for (var i = 0, len = queue.length; i < len; ++i) {
3495             if (queue[i] == anim) {
3496                 return i;
3497             }
3498         }
3499         return -1;
3500     };
3501
3502
3503     var correctFrame = function(tween) {
3504         var frames = tween.totalFrames;
3505         var frame = tween.currentFrame;
3506         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3507         var elapsed = (new Date() - tween.getStartTime());
3508         var tweak = 0;
3509
3510         if (elapsed < tween.duration * 1000) {
3511             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3512         } else {
3513             tweak = frames - (frame + 1);
3514         }
3515         if (tweak > 0 && isFinite(tweak)) {
3516             if (tween.currentFrame + tweak >= frames) {
3517                 tweak = frames - (frame + 1);
3518             }
3519
3520             tween.currentFrame += tweak;
3521         }
3522     };
3523 };
3524
3525     /*
3526  * Portions of this file are based on pieces of Yahoo User Interface Library
3527  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3528  * YUI licensed under the BSD License:
3529  * http://developer.yahoo.net/yui/license.txt
3530  * <script type="text/javascript">
3531  *
3532  */
3533 Roo.lib.Bezier = new function() {
3534
3535         this.getPosition = function(points, t) {
3536             var n = points.length;
3537             var tmp = [];
3538
3539             for (var i = 0; i < n; ++i) {
3540                 tmp[i] = [points[i][0], points[i][1]];
3541             }
3542
3543             for (var j = 1; j < n; ++j) {
3544                 for (i = 0; i < n - j; ++i) {
3545                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3546                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547                 }
3548             }
3549
3550             return [ tmp[0][0], tmp[0][1] ];
3551
3552         };
3553     };/*
3554  * Portions of this file are based on pieces of Yahoo User Interface Library
3555  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3556  * YUI licensed under the BSD License:
3557  * http://developer.yahoo.net/yui/license.txt
3558  * <script type="text/javascript">
3559  *
3560  */
3561 (function() {
3562
3563     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3564         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3565     };
3566
3567     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3568
3569     var fly = Roo.lib.AnimBase.fly;
3570     var Y = Roo.lib;
3571     var superclass = Y.ColorAnim.superclass;
3572     var proto = Y.ColorAnim.prototype;
3573
3574     proto.toString = function() {
3575         var el = this.getEl();
3576         var id = el.id || el.tagName;
3577         return ("ColorAnim " + id);
3578     };
3579
3580     proto.patterns.color = /color$/i;
3581     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3582     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3583     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3584     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3585
3586
3587     proto.parseColor = function(s) {
3588         if (s.length == 3) {
3589             return s;
3590         }
3591
3592         var c = this.patterns.hex.exec(s);
3593         if (c && c.length == 4) {
3594             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3595         }
3596
3597         c = this.patterns.rgb.exec(s);
3598         if (c && c.length == 4) {
3599             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3600         }
3601
3602         c = this.patterns.hex3.exec(s);
3603         if (c && c.length == 4) {
3604             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3605         }
3606
3607         return null;
3608     };
3609     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3610     proto.getAttribute = function(attr) {
3611         var el = this.getEl();
3612         if (this.patterns.color.test(attr)) {
3613             var val = fly(el).getStyle(attr);
3614
3615             if (this.patterns.transparent.test(val)) {
3616                 var parent = el.parentNode;
3617                 val = fly(parent).getStyle(attr);
3618
3619                 while (parent && this.patterns.transparent.test(val)) {
3620                     parent = parent.parentNode;
3621                     val = fly(parent).getStyle(attr);
3622                     if (parent.tagName.toUpperCase() == 'HTML') {
3623                         val = '#fff';
3624                     }
3625                 }
3626             }
3627         } else {
3628             val = superclass.getAttribute.call(this, attr);
3629         }
3630
3631         return val;
3632     };
3633     proto.getAttribute = function(attr) {
3634         var el = this.getEl();
3635         if (this.patterns.color.test(attr)) {
3636             var val = fly(el).getStyle(attr);
3637
3638             if (this.patterns.transparent.test(val)) {
3639                 var parent = el.parentNode;
3640                 val = fly(parent).getStyle(attr);
3641
3642                 while (parent && this.patterns.transparent.test(val)) {
3643                     parent = parent.parentNode;
3644                     val = fly(parent).getStyle(attr);
3645                     if (parent.tagName.toUpperCase() == 'HTML') {
3646                         val = '#fff';
3647                     }
3648                 }
3649             }
3650         } else {
3651             val = superclass.getAttribute.call(this, attr);
3652         }
3653
3654         return val;
3655     };
3656
3657     proto.doMethod = function(attr, start, end) {
3658         var val;
3659
3660         if (this.patterns.color.test(attr)) {
3661             val = [];
3662             for (var i = 0, len = start.length; i < len; ++i) {
3663                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3664             }
3665
3666             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3667         }
3668         else {
3669             val = superclass.doMethod.call(this, attr, start, end);
3670         }
3671
3672         return val;
3673     };
3674
3675     proto.setRuntimeAttribute = function(attr) {
3676         superclass.setRuntimeAttribute.call(this, attr);
3677
3678         if (this.patterns.color.test(attr)) {
3679             var attributes = this.attributes;
3680             var start = this.parseColor(this.runtimeAttributes[attr].start);
3681             var end = this.parseColor(this.runtimeAttributes[attr].end);
3682
3683             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3684                 end = this.parseColor(attributes[attr].by);
3685
3686                 for (var i = 0, len = start.length; i < len; ++i) {
3687                     end[i] = start[i] + end[i];
3688                 }
3689             }
3690
3691             this.runtimeAttributes[attr].start = start;
3692             this.runtimeAttributes[attr].end = end;
3693         }
3694     };
3695 })();
3696
3697 /*
3698  * Portions of this file are based on pieces of Yahoo User Interface Library
3699  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3700  * YUI licensed under the BSD License:
3701  * http://developer.yahoo.net/yui/license.txt
3702  * <script type="text/javascript">
3703  *
3704  */
3705 Roo.lib.Easing = {
3706
3707
3708     easeNone: function (t, b, c, d) {
3709         return c * t / d + b;
3710     },
3711
3712
3713     easeIn: function (t, b, c, d) {
3714         return c * (t /= d) * t + b;
3715     },
3716
3717
3718     easeOut: function (t, b, c, d) {
3719         return -c * (t /= d) * (t - 2) + b;
3720     },
3721
3722
3723     easeBoth: function (t, b, c, d) {
3724         if ((t /= d / 2) < 1) {
3725             return c / 2 * t * t + b;
3726         }
3727
3728         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729     },
3730
3731
3732     easeInStrong: function (t, b, c, d) {
3733         return c * (t /= d) * t * t * t + b;
3734     },
3735
3736
3737     easeOutStrong: function (t, b, c, d) {
3738         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739     },
3740
3741
3742     easeBothStrong: function (t, b, c, d) {
3743         if ((t /= d / 2) < 1) {
3744             return c / 2 * t * t * t * t + b;
3745         }
3746
3747         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3748     },
3749
3750
3751
3752     elasticIn: function (t, b, c, d, a, p) {
3753         if (t == 0) {
3754             return b;
3755         }
3756         if ((t /= d) == 1) {
3757             return b + c;
3758         }
3759         if (!p) {
3760             p = d * .3;
3761         }
3762
3763         if (!a || a < Math.abs(c)) {
3764             a = c;
3765             var s = p / 4;
3766         }
3767         else {
3768             var s = p / (2 * Math.PI) * Math.asin(c / a);
3769         }
3770
3771         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772     },
3773
3774
3775     elasticOut: function (t, b, c, d, a, p) {
3776         if (t == 0) {
3777             return b;
3778         }
3779         if ((t /= d) == 1) {
3780             return b + c;
3781         }
3782         if (!p) {
3783             p = d * .3;
3784         }
3785
3786         if (!a || a < Math.abs(c)) {
3787             a = c;
3788             var s = p / 4;
3789         }
3790         else {
3791             var s = p / (2 * Math.PI) * Math.asin(c / a);
3792         }
3793
3794         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795     },
3796
3797
3798     elasticBoth: function (t, b, c, d, a, p) {
3799         if (t == 0) {
3800             return b;
3801         }
3802
3803         if ((t /= d / 2) == 2) {
3804             return b + c;
3805         }
3806
3807         if (!p) {
3808             p = d * (.3 * 1.5);
3809         }
3810
3811         if (!a || a < Math.abs(c)) {
3812             a = c;
3813             var s = p / 4;
3814         }
3815         else {
3816             var s = p / (2 * Math.PI) * Math.asin(c / a);
3817         }
3818
3819         if (t < 1) {
3820             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3821                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3822         }
3823         return a * Math.pow(2, -10 * (t -= 1)) *
3824                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3825     },
3826
3827
3828
3829     backIn: function (t, b, c, d, s) {
3830         if (typeof s == 'undefined') {
3831             s = 1.70158;
3832         }
3833         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834     },
3835
3836
3837     backOut: function (t, b, c, d, s) {
3838         if (typeof s == 'undefined') {
3839             s = 1.70158;
3840         }
3841         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842     },
3843
3844
3845     backBoth: function (t, b, c, d, s) {
3846         if (typeof s == 'undefined') {
3847             s = 1.70158;
3848         }
3849
3850         if ((t /= d / 2 ) < 1) {
3851             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3852         }
3853         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854     },
3855
3856
3857     bounceIn: function (t, b, c, d) {
3858         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859     },
3860
3861
3862     bounceOut: function (t, b, c, d) {
3863         if ((t /= d) < (1 / 2.75)) {
3864             return c * (7.5625 * t * t) + b;
3865         } else if (t < (2 / 2.75)) {
3866             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3867         } else if (t < (2.5 / 2.75)) {
3868             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3869         }
3870         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871     },
3872
3873
3874     bounceBoth: function (t, b, c, d) {
3875         if (t < d / 2) {
3876             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3877         }
3878         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3879     }
3880 };/*
3881  * Portions of this file are based on pieces of Yahoo User Interface Library
3882  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3883  * YUI licensed under the BSD License:
3884  * http://developer.yahoo.net/yui/license.txt
3885  * <script type="text/javascript">
3886  *
3887  */
3888     (function() {
3889         Roo.lib.Motion = function(el, attributes, duration, method) {
3890             if (el) {
3891                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892             }
3893         };
3894
3895         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896
3897
3898         var Y = Roo.lib;
3899         var superclass = Y.Motion.superclass;
3900         var proto = Y.Motion.prototype;
3901
3902         proto.toString = function() {
3903             var el = this.getEl();
3904             var id = el.id || el.tagName;
3905             return ("Motion " + id);
3906         };
3907
3908         proto.patterns.points = /^points$/i;
3909
3910         proto.setAttribute = function(attr, val, unit) {
3911             if (this.patterns.points.test(attr)) {
3912                 unit = unit || 'px';
3913                 superclass.setAttribute.call(this, 'left', val[0], unit);
3914                 superclass.setAttribute.call(this, 'top', val[1], unit);
3915             } else {
3916                 superclass.setAttribute.call(this, attr, val, unit);
3917             }
3918         };
3919
3920         proto.getAttribute = function(attr) {
3921             if (this.patterns.points.test(attr)) {
3922                 var val = [
3923                         superclass.getAttribute.call(this, 'left'),
3924                         superclass.getAttribute.call(this, 'top')
3925                         ];
3926             } else {
3927                 val = superclass.getAttribute.call(this, attr);
3928             }
3929
3930             return val;
3931         };
3932
3933         proto.doMethod = function(attr, start, end) {
3934             var val = null;
3935
3936             if (this.patterns.points.test(attr)) {
3937                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3938                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3939             } else {
3940                 val = superclass.doMethod.call(this, attr, start, end);
3941             }
3942             return val;
3943         };
3944
3945         proto.setRuntimeAttribute = function(attr) {
3946             if (this.patterns.points.test(attr)) {
3947                 var el = this.getEl();
3948                 var attributes = this.attributes;
3949                 var start;
3950                 var control = attributes['points']['control'] || [];
3951                 var end;
3952                 var i, len;
3953
3954                 if (control.length > 0 && !(control[0] instanceof Array)) {
3955                     control = [control];
3956                 } else {
3957                     var tmp = [];
3958                     for (i = 0,len = control.length; i < len; ++i) {
3959                         tmp[i] = control[i];
3960                     }
3961                     control = tmp;
3962                 }
3963
3964                 Roo.fly(el).position();
3965
3966                 if (isset(attributes['points']['from'])) {
3967                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3968                 }
3969                 else {
3970                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3971                 }
3972
3973                 start = this.getAttribute('points');
3974
3975
3976                 if (isset(attributes['points']['to'])) {
3977                     end = translateValues.call(this, attributes['points']['to'], start);
3978
3979                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3980                     for (i = 0,len = control.length; i < len; ++i) {
3981                         control[i] = translateValues.call(this, control[i], start);
3982                     }
3983
3984
3985                 } else if (isset(attributes['points']['by'])) {
3986                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3987
3988                     for (i = 0,len = control.length; i < len; ++i) {
3989                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990                     }
3991                 }
3992
3993                 this.runtimeAttributes[attr] = [start];
3994
3995                 if (control.length > 0) {
3996                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3997                 }
3998
3999                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4000             }
4001             else {
4002                 superclass.setRuntimeAttribute.call(this, attr);
4003             }
4004         };
4005
4006         var translateValues = function(val, start) {
4007             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4008             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4009
4010             return val;
4011         };
4012
4013         var isset = function(prop) {
4014             return (typeof prop !== 'undefined');
4015         };
4016     })();
4017 /*
4018  * Portions of this file are based on pieces of Yahoo User Interface Library
4019  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4020  * YUI licensed under the BSD License:
4021  * http://developer.yahoo.net/yui/license.txt
4022  * <script type="text/javascript">
4023  *
4024  */
4025     (function() {
4026         Roo.lib.Scroll = function(el, attributes, duration, method) {
4027             if (el) {
4028                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029             }
4030         };
4031
4032         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033
4034
4035         var Y = Roo.lib;
4036         var superclass = Y.Scroll.superclass;
4037         var proto = Y.Scroll.prototype;
4038
4039         proto.toString = function() {
4040             var el = this.getEl();
4041             var id = el.id || el.tagName;
4042             return ("Scroll " + id);
4043         };
4044
4045         proto.doMethod = function(attr, start, end) {
4046             var val = null;
4047
4048             if (attr == 'scroll') {
4049                 val = [
4050                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4051                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052                         ];
4053
4054             } else {
4055                 val = superclass.doMethod.call(this, attr, start, end);
4056             }
4057             return val;
4058         };
4059
4060         proto.getAttribute = function(attr) {
4061             var val = null;
4062             var el = this.getEl();
4063
4064             if (attr == 'scroll') {
4065                 val = [ el.scrollLeft, el.scrollTop ];
4066             } else {
4067                 val = superclass.getAttribute.call(this, attr);
4068             }
4069
4070             return val;
4071         };
4072
4073         proto.setAttribute = function(attr, val, unit) {
4074             var el = this.getEl();
4075
4076             if (attr == 'scroll') {
4077                 el.scrollLeft = val[0];
4078                 el.scrollTop = val[1];
4079             } else {
4080                 superclass.setAttribute.call(this, attr, val, unit);
4081             }
4082         };
4083     })();
4084 /*
4085  * Based on:
4086  * Ext JS Library 1.1.1
4087  * Copyright(c) 2006-2007, Ext JS, LLC.
4088  *
4089  * Originally Released Under LGPL - original licence link has changed is not relivant.
4090  *
4091  * Fork - LGPL
4092  * <script type="text/javascript">
4093  */
4094
4095
4096 // nasty IE9 hack - what a pile of crap that is..
4097
4098  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4099     Range.prototype.createContextualFragment = function (html) {
4100         var doc = window.document;
4101         var container = doc.createElement("div");
4102         container.innerHTML = html;
4103         var frag = doc.createDocumentFragment(), n;
4104         while ((n = container.firstChild)) {
4105             frag.appendChild(n);
4106         }
4107         return frag;
4108     };
4109 }
4110
4111 /**
4112  * @class Roo.DomHelper
4113  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4114  * 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>.
4115  * @singleton
4116  */
4117 Roo.DomHelper = function(){
4118     var tempTableEl = null;
4119     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4120     var tableRe = /^table|tbody|tr|td$/i;
4121     var xmlns = {};
4122     // build as innerHTML where available
4123     /** @ignore */
4124     var createHtml = function(o){
4125         if(typeof o == 'string'){
4126             return o;
4127         }
4128         var b = "";
4129         if(!o.tag){
4130             o.tag = "div";
4131         }
4132         b += "<" + o.tag;
4133         for(var attr in o){
4134             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4135             if(attr == "style"){
4136                 var s = o["style"];
4137                 if(typeof s == "function"){
4138                     s = s.call();
4139                 }
4140                 if(typeof s == "string"){
4141                     b += ' style="' + s + '"';
4142                 }else if(typeof s == "object"){
4143                     b += ' style="';
4144                     for(var key in s){
4145                         if(typeof s[key] != "function"){
4146                             b += key + ":" + s[key] + ";";
4147                         }
4148                     }
4149                     b += '"';
4150                 }
4151             }else{
4152                 if(attr == "cls"){
4153                     b += ' class="' + o["cls"] + '"';
4154                 }else if(attr == "htmlFor"){
4155                     b += ' for="' + o["htmlFor"] + '"';
4156                 }else{
4157                     b += " " + attr + '="' + o[attr] + '"';
4158                 }
4159             }
4160         }
4161         if(emptyTags.test(o.tag)){
4162             b += "/>";
4163         }else{
4164             b += ">";
4165             var cn = o.children || o.cn;
4166             if(cn){
4167                 //http://bugs.kde.org/show_bug.cgi?id=71506
4168                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4169                     for(var i = 0, len = cn.length; i < len; i++) {
4170                         b += createHtml(cn[i], b);
4171                     }
4172                 }else{
4173                     b += createHtml(cn, b);
4174                 }
4175             }
4176             if(o.html){
4177                 b += o.html;
4178             }
4179             b += "</" + o.tag + ">";
4180         }
4181         return b;
4182     };
4183
4184     // build as dom
4185     /** @ignore */
4186     var createDom = function(o, parentNode){
4187          
4188         // defininition craeted..
4189         var ns = false;
4190         if (o.ns && o.ns != 'html') {
4191                
4192             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4193                 xmlns[o.ns] = o.xmlns;
4194                 ns = o.xmlns;
4195             }
4196             if (typeof(xmlns[o.ns]) == 'undefined') {
4197                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4198             }
4199             ns = xmlns[o.ns];
4200         }
4201         
4202         
4203         if (typeof(o) == 'string') {
4204             return parentNode.appendChild(document.createTextNode(o));
4205         }
4206         o.tag = o.tag || div;
4207         if (o.ns && Roo.isIE) {
4208             ns = false;
4209             o.tag = o.ns + ':' + o.tag;
4210             
4211         }
4212         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4213         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4214         for(var attr in o){
4215             
4216             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4217                     attr == "style" || typeof o[attr] == "function") continue;
4218                     
4219             if(attr=="cls" && Roo.isIE){
4220                 el.className = o["cls"];
4221             }else{
4222                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4223                 else el[attr] = o[attr];
4224             }
4225         }
4226         Roo.DomHelper.applyStyles(el, o.style);
4227         var cn = o.children || o.cn;
4228         if(cn){
4229             //http://bugs.kde.org/show_bug.cgi?id=71506
4230              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4231                 for(var i = 0, len = cn.length; i < len; i++) {
4232                     createDom(cn[i], el);
4233                 }
4234             }else{
4235                 createDom(cn, el);
4236             }
4237         }
4238         if(o.html){
4239             el.innerHTML = o.html;
4240         }
4241         if(parentNode){
4242            parentNode.appendChild(el);
4243         }
4244         return el;
4245     };
4246
4247     var ieTable = function(depth, s, h, e){
4248         tempTableEl.innerHTML = [s, h, e].join('');
4249         var i = -1, el = tempTableEl;
4250         while(++i < depth){
4251             el = el.firstChild;
4252         }
4253         return el;
4254     };
4255
4256     // kill repeat to save bytes
4257     var ts = '<table>',
4258         te = '</table>',
4259         tbs = ts+'<tbody>',
4260         tbe = '</tbody>'+te,
4261         trs = tbs + '<tr>',
4262         tre = '</tr>'+tbe;
4263
4264     /**
4265      * @ignore
4266      * Nasty code for IE's broken table implementation
4267      */
4268     var insertIntoTable = function(tag, where, el, html){
4269         if(!tempTableEl){
4270             tempTableEl = document.createElement('div');
4271         }
4272         var node;
4273         var before = null;
4274         if(tag == 'td'){
4275             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4276                 return;
4277             }
4278             if(where == 'beforebegin'){
4279                 before = el;
4280                 el = el.parentNode;
4281             } else{
4282                 before = el.nextSibling;
4283                 el = el.parentNode;
4284             }
4285             node = ieTable(4, trs, html, tre);
4286         }
4287         else if(tag == 'tr'){
4288             if(where == 'beforebegin'){
4289                 before = el;
4290                 el = el.parentNode;
4291                 node = ieTable(3, tbs, html, tbe);
4292             } else if(where == 'afterend'){
4293                 before = el.nextSibling;
4294                 el = el.parentNode;
4295                 node = ieTable(3, tbs, html, tbe);
4296             } else{ // INTO a TR
4297                 if(where == 'afterbegin'){
4298                     before = el.firstChild;
4299                 }
4300                 node = ieTable(4, trs, html, tre);
4301             }
4302         } else if(tag == 'tbody'){
4303             if(where == 'beforebegin'){
4304                 before = el;
4305                 el = el.parentNode;
4306                 node = ieTable(2, ts, html, te);
4307             } else if(where == 'afterend'){
4308                 before = el.nextSibling;
4309                 el = el.parentNode;
4310                 node = ieTable(2, ts, html, te);
4311             } else{
4312                 if(where == 'afterbegin'){
4313                     before = el.firstChild;
4314                 }
4315                 node = ieTable(3, tbs, html, tbe);
4316             }
4317         } else{ // TABLE
4318             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4319                 return;
4320             }
4321             if(where == 'afterbegin'){
4322                 before = el.firstChild;
4323             }
4324             node = ieTable(2, ts, html, te);
4325         }
4326         el.insertBefore(node, before);
4327         return node;
4328     };
4329
4330     return {
4331     /** True to force the use of DOM instead of html fragments @type Boolean */
4332     useDom : false,
4333
4334     /**
4335      * Returns the markup for the passed Element(s) config
4336      * @param {Object} o The Dom object spec (and children)
4337      * @return {String}
4338      */
4339     markup : function(o){
4340         return createHtml(o);
4341     },
4342
4343     /**
4344      * Applies a style specification to an element
4345      * @param {String/HTMLElement} el The element to apply styles to
4346      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4347      * a function which returns such a specification.
4348      */
4349     applyStyles : function(el, styles){
4350         if(styles){
4351            el = Roo.fly(el);
4352            if(typeof styles == "string"){
4353                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4354                var matches;
4355                while ((matches = re.exec(styles)) != null){
4356                    el.setStyle(matches[1], matches[2]);
4357                }
4358            }else if (typeof styles == "object"){
4359                for (var style in styles){
4360                   el.setStyle(style, styles[style]);
4361                }
4362            }else if (typeof styles == "function"){
4363                 Roo.DomHelper.applyStyles(el, styles.call());
4364            }
4365         }
4366     },
4367
4368     /**
4369      * Inserts an HTML fragment into the Dom
4370      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4371      * @param {HTMLElement} el The context element
4372      * @param {String} html The HTML fragmenet
4373      * @return {HTMLElement} The new node
4374      */
4375     insertHtml : function(where, el, html){
4376         where = where.toLowerCase();
4377         if(el.insertAdjacentHTML){
4378             if(tableRe.test(el.tagName)){
4379                 var rs;
4380                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4381                     return rs;
4382                 }
4383             }
4384             switch(where){
4385                 case "beforebegin":
4386                     el.insertAdjacentHTML('BeforeBegin', html);
4387                     return el.previousSibling;
4388                 case "afterbegin":
4389                     el.insertAdjacentHTML('AfterBegin', html);
4390                     return el.firstChild;
4391                 case "beforeend":
4392                     el.insertAdjacentHTML('BeforeEnd', html);
4393                     return el.lastChild;
4394                 case "afterend":
4395                     el.insertAdjacentHTML('AfterEnd', html);
4396                     return el.nextSibling;
4397             }
4398             throw 'Illegal insertion point -> "' + where + '"';
4399         }
4400         var range = el.ownerDocument.createRange();
4401         var frag;
4402         switch(where){
4403              case "beforebegin":
4404                 range.setStartBefore(el);
4405                 frag = range.createContextualFragment(html);
4406                 el.parentNode.insertBefore(frag, el);
4407                 return el.previousSibling;
4408              case "afterbegin":
4409                 if(el.firstChild){
4410                     range.setStartBefore(el.firstChild);
4411                     frag = range.createContextualFragment(html);
4412                     el.insertBefore(frag, el.firstChild);
4413                     return el.firstChild;
4414                 }else{
4415                     el.innerHTML = html;
4416                     return el.firstChild;
4417                 }
4418             case "beforeend":
4419                 if(el.lastChild){
4420                     range.setStartAfter(el.lastChild);
4421                     frag = range.createContextualFragment(html);
4422                     el.appendChild(frag);
4423                     return el.lastChild;
4424                 }else{
4425                     el.innerHTML = html;
4426                     return el.lastChild;
4427                 }
4428             case "afterend":
4429                 range.setStartAfter(el);
4430                 frag = range.createContextualFragment(html);
4431                 el.parentNode.insertBefore(frag, el.nextSibling);
4432                 return el.nextSibling;
4433             }
4434             throw 'Illegal insertion point -> "' + where + '"';
4435     },
4436
4437     /**
4438      * Creates new Dom element(s) and inserts them before el
4439      * @param {String/HTMLElement/Element} el The context element
4440      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4441      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4442      * @return {HTMLElement/Roo.Element} The new node
4443      */
4444     insertBefore : function(el, o, returnElement){
4445         return this.doInsert(el, o, returnElement, "beforeBegin");
4446     },
4447
4448     /**
4449      * Creates new Dom element(s) and inserts them after el
4450      * @param {String/HTMLElement/Element} el The context element
4451      * @param {Object} o The Dom object spec (and children)
4452      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4453      * @return {HTMLElement/Roo.Element} The new node
4454      */
4455     insertAfter : function(el, o, returnElement){
4456         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457     },
4458
4459     /**
4460      * Creates new Dom element(s) and inserts them as the first child of el
4461      * @param {String/HTMLElement/Element} el The context element
4462      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464      * @return {HTMLElement/Roo.Element} The new node
4465      */
4466     insertFirst : function(el, o, returnElement){
4467         return this.doInsert(el, o, returnElement, "afterBegin");
4468     },
4469
4470     // private
4471     doInsert : function(el, o, returnElement, pos, sibling){
4472         el = Roo.getDom(el);
4473         var newNode;
4474         if(this.useDom || o.ns){
4475             newNode = createDom(o, null);
4476             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4477         }else{
4478             var html = createHtml(o);
4479             newNode = this.insertHtml(pos, el, html);
4480         }
4481         return returnElement ? Roo.get(newNode, true) : newNode;
4482     },
4483
4484     /**
4485      * Creates new Dom element(s) and appends them to el
4486      * @param {String/HTMLElement/Element} el The context element
4487      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4488      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4489      * @return {HTMLElement/Roo.Element} The new node
4490      */
4491     append : function(el, o, returnElement){
4492         el = Roo.getDom(el);
4493         var newNode;
4494         if(this.useDom || o.ns){
4495             newNode = createDom(o, null);
4496             el.appendChild(newNode);
4497         }else{
4498             var html = createHtml(o);
4499             newNode = this.insertHtml("beforeEnd", el, html);
4500         }
4501         return returnElement ? Roo.get(newNode, true) : newNode;
4502     },
4503
4504     /**
4505      * Creates new Dom element(s) and overwrites the contents of el with them
4506      * @param {String/HTMLElement/Element} el The context element
4507      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4508      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4509      * @return {HTMLElement/Roo.Element} The new node
4510      */
4511     overwrite : function(el, o, returnElement){
4512         el = Roo.getDom(el);
4513         if (o.ns) {
4514           
4515             while (el.childNodes.length) {
4516                 el.removeChild(el.firstChild);
4517             }
4518             createDom(o, el);
4519         } else {
4520             el.innerHTML = createHtml(o);   
4521         }
4522         
4523         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524     },
4525
4526     /**
4527      * Creates a new Roo.DomHelper.Template from the Dom object spec
4528      * @param {Object} o The Dom object spec (and children)
4529      * @return {Roo.DomHelper.Template} The new template
4530      */
4531     createTemplate : function(o){
4532         var html = createHtml(o);
4533         return new Roo.Template(html);
4534     }
4535     };
4536 }();
4537 /*
4538  * Based on:
4539  * Ext JS Library 1.1.1
4540  * Copyright(c) 2006-2007, Ext JS, LLC.
4541  *
4542  * Originally Released Under LGPL - original licence link has changed is not relivant.
4543  *
4544  * Fork - LGPL
4545  * <script type="text/javascript">
4546  */
4547  
4548 /**
4549 * @class Roo.Template
4550 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4551 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4552 * Usage:
4553 <pre><code>
4554 var t = new Roo.Template({
4555     html :  '&lt;div name="{id}"&gt;' + 
4556         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4557         '&lt;/div&gt;',
4558     myformat: function (value, allValues) {
4559         return 'XX' + value;
4560     }
4561 });
4562 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4563 </code></pre>
4564 * For more information see this blog post with examples:
4565 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4566      - Create Elements using DOM, HTML fragments and Templates</a>. 
4567 * @constructor
4568 * @param {Object} cfg - Configuration object.
4569 */
4570 Roo.Template = function(cfg){
4571     // BC!
4572     if(cfg instanceof Array){
4573         cfg = cfg.join("");
4574     }else if(arguments.length > 1){
4575         cfg = Array.prototype.join.call(arguments, "");
4576     }
4577     
4578     
4579     if (typeof(cfg) == 'object') {
4580         Roo.apply(this,cfg)
4581     } else {
4582         // bc
4583         this.html = cfg;
4584     }
4585     if (this.url) {
4586         this.load();
4587     }
4588     
4589 };
4590 Roo.Template.prototype = {
4591     
4592     /**
4593      * @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..
4594      *                    it should be fixed so that template is observable...
4595      */
4596     url : false,
4597     /**
4598      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599      */
4600     html : '',
4601     /**
4602      * Returns an HTML fragment of this template with the specified values applied.
4603      * @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'})
4604      * @return {String} The HTML fragment
4605      */
4606     applyTemplate : function(values){
4607         try {
4608            
4609             if(this.compiled){
4610                 return this.compiled(values);
4611             }
4612             var useF = this.disableFormats !== true;
4613             var fm = Roo.util.Format, tpl = this;
4614             var fn = function(m, name, format, args){
4615                 if(format && useF){
4616                     if(format.substr(0, 5) == "this."){
4617                         return tpl.call(format.substr(5), values[name], values);
4618                     }else{
4619                         if(args){
4620                             // quoted values are required for strings in compiled templates, 
4621                             // but for non compiled we need to strip them
4622                             // quoted reversed for jsmin
4623                             var re = /^\s*['"](.*)["']\s*$/;
4624                             args = args.split(',');
4625                             for(var i = 0, len = args.length; i < len; i++){
4626                                 args[i] = args[i].replace(re, "$1");
4627                             }
4628                             args = [values[name]].concat(args);
4629                         }else{
4630                             args = [values[name]];
4631                         }
4632                         return fm[format].apply(fm, args);
4633                     }
4634                 }else{
4635                     return values[name] !== undefined ? values[name] : "";
4636                 }
4637             };
4638             return this.html.replace(this.re, fn);
4639         } catch (e) {
4640             Roo.log(e);
4641             throw e;
4642         }
4643          
4644     },
4645     
4646     loading : false,
4647       
4648     load : function ()
4649     {
4650          
4651         if (this.loading) {
4652             return;
4653         }
4654         var _t = this;
4655         
4656         this.loading = true;
4657         this.compiled = false;
4658         
4659         var cx = new Roo.data.Connection();
4660         cx.request({
4661             url : this.url,
4662             method : 'GET',
4663             success : function (response) {
4664                 _t.loading = false;
4665                 _t.html = response.responseText;
4666                 _t.url = false;
4667                 _t.compile();
4668              },
4669             failure : function(response) {
4670                 Roo.log("Template failed to load from " + _t.url);
4671                 _t.loading = false;
4672             }
4673         });
4674     },
4675
4676     /**
4677      * Sets the HTML used as the template and optionally compiles it.
4678      * @param {String} html
4679      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4680      * @return {Roo.Template} this
4681      */
4682     set : function(html, compile){
4683         this.html = html;
4684         this.compiled = null;
4685         if(compile){
4686             this.compile();
4687         }
4688         return this;
4689     },
4690     
4691     /**
4692      * True to disable format functions (defaults to false)
4693      * @type Boolean
4694      */
4695     disableFormats : false,
4696     
4697     /**
4698     * The regular expression used to match template variables 
4699     * @type RegExp
4700     * @property 
4701     */
4702     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4703     
4704     /**
4705      * Compiles the template into an internal function, eliminating the RegEx overhead.
4706      * @return {Roo.Template} this
4707      */
4708     compile : function(){
4709         var fm = Roo.util.Format;
4710         var useF = this.disableFormats !== true;
4711         var sep = Roo.isGecko ? "+" : ",";
4712         var fn = function(m, name, format, args){
4713             if(format && useF){
4714                 args = args ? ',' + args : "";
4715                 if(format.substr(0, 5) != "this."){
4716                     format = "fm." + format + '(';
4717                 }else{
4718                     format = 'this.call("'+ format.substr(5) + '", ';
4719                     args = ", values";
4720                 }
4721             }else{
4722                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4723             }
4724             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4725         };
4726         var body;
4727         // branched to use + in gecko and [].join() in others
4728         if(Roo.isGecko){
4729             body = "this.compiled = function(values){ return '" +
4730                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4731                     "';};";
4732         }else{
4733             body = ["this.compiled = function(values){ return ['"];
4734             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4735             body.push("'].join('');};");
4736             body = body.join('');
4737         }
4738         /**
4739          * eval:var:values
4740          * eval:var:fm
4741          */
4742         eval(body);
4743         return this;
4744     },
4745     
4746     // private function used to call members
4747     call : function(fnName, value, allValues){
4748         return this[fnName](value, allValues);
4749     },
4750     
4751     /**
4752      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4753      * @param {String/HTMLElement/Roo.Element} el The context element
4754      * @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'})
4755      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4756      * @return {HTMLElement/Roo.Element} The new node or Element
4757      */
4758     insertFirst: function(el, values, returnElement){
4759         return this.doInsert('afterBegin', el, values, returnElement);
4760     },
4761
4762     /**
4763      * Applies the supplied values to the template and inserts the new node(s) before el.
4764      * @param {String/HTMLElement/Roo.Element} el The context element
4765      * @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'})
4766      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4767      * @return {HTMLElement/Roo.Element} The new node or Element
4768      */
4769     insertBefore: function(el, values, returnElement){
4770         return this.doInsert('beforeBegin', el, values, returnElement);
4771     },
4772
4773     /**
4774      * Applies the supplied values to the template and inserts the new node(s) after el.
4775      * @param {String/HTMLElement/Roo.Element} el The context element
4776      * @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'})
4777      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778      * @return {HTMLElement/Roo.Element} The new node or Element
4779      */
4780     insertAfter : function(el, values, returnElement){
4781         return this.doInsert('afterEnd', el, values, returnElement);
4782     },
4783     
4784     /**
4785      * Applies the supplied values to the template and appends the new node(s) to el.
4786      * @param {String/HTMLElement/Roo.Element} el The context element
4787      * @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'})
4788      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789      * @return {HTMLElement/Roo.Element} The new node or Element
4790      */
4791     append : function(el, values, returnElement){
4792         return this.doInsert('beforeEnd', el, values, returnElement);
4793     },
4794
4795     doInsert : function(where, el, values, returnEl){
4796         el = Roo.getDom(el);
4797         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4798         return returnEl ? Roo.get(newNode, true) : newNode;
4799     },
4800
4801     /**
4802      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4803      * @param {String/HTMLElement/Roo.Element} el The context element
4804      * @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'})
4805      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4806      * @return {HTMLElement/Roo.Element} The new node or Element
4807      */
4808     overwrite : function(el, values, returnElement){
4809         el = Roo.getDom(el);
4810         el.innerHTML = this.applyTemplate(values);
4811         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812     }
4813 };
4814 /**
4815  * Alias for {@link #applyTemplate}
4816  * @method
4817  */
4818 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4819
4820 // backwards compat
4821 Roo.DomHelper.Template = Roo.Template;
4822
4823 /**
4824  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4825  * @param {String/HTMLElement} el A DOM element or its id
4826  * @returns {Roo.Template} The created template
4827  * @static
4828  */
4829 Roo.Template.from = function(el){
4830     el = Roo.getDom(el);
4831     return new Roo.Template(el.value || el.innerHTML);
4832 };/*
4833  * Based on:
4834  * Ext JS Library 1.1.1
4835  * Copyright(c) 2006-2007, Ext JS, LLC.
4836  *
4837  * Originally Released Under LGPL - original licence link has changed is not relivant.
4838  *
4839  * Fork - LGPL
4840  * <script type="text/javascript">
4841  */
4842  
4843
4844 /*
4845  * This is code is also distributed under MIT license for use
4846  * with jQuery and prototype JavaScript libraries.
4847  */
4848 /**
4849  * @class Roo.DomQuery
4850 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).
4851 <p>
4852 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>
4853
4854 <p>
4855 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.
4856 </p>
4857 <h4>Element Selectors:</h4>
4858 <ul class="list">
4859     <li> <b>*</b> any element</li>
4860     <li> <b>E</b> an element with the tag E</li>
4861     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4862     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4863     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4864     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4865 </ul>
4866 <h4>Attribute Selectors:</h4>
4867 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4868 <ul class="list">
4869     <li> <b>E[foo]</b> has an attribute "foo"</li>
4870     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4871     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4872     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4873     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4874     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4875     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4876 </ul>
4877 <h4>Pseudo Classes:</h4>
4878 <ul class="list">
4879     <li> <b>E:first-child</b> E is the first child of its parent</li>
4880     <li> <b>E:last-child</b> E is the last child of its parent</li>
4881     <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>
4882     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4883     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4884     <li> <b>E:only-child</b> E is the only child of its parent</li>
4885     <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>
4886     <li> <b>E:first</b> the first E in the resultset</li>
4887     <li> <b>E:last</b> the last E in the resultset</li>
4888     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4889     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4890     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4891     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4892     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4893     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4894     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4895     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4896     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4897 </ul>
4898 <h4>CSS Value Selectors:</h4>
4899 <ul class="list">
4900     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4901     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4902     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4903     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4904     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4905     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 </ul>
4907  * @singleton
4908  */
4909 Roo.DomQuery = function(){
4910     var cache = {}, simpleCache = {}, valueCache = {};
4911     var nonSpace = /\S/;
4912     var trimRe = /^\s+|\s+$/g;
4913     var tplRe = /\{(\d+)\}/g;
4914     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4915     var tagTokenRe = /^(#)?([\w-\*]+)/;
4916     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4917
4918     function child(p, index){
4919         var i = 0;
4920         var n = p.firstChild;
4921         while(n){
4922             if(n.nodeType == 1){
4923                if(++i == index){
4924                    return n;
4925                }
4926             }
4927             n = n.nextSibling;
4928         }
4929         return null;
4930     };
4931
4932     function next(n){
4933         while((n = n.nextSibling) && n.nodeType != 1);
4934         return n;
4935     };
4936
4937     function prev(n){
4938         while((n = n.previousSibling) && n.nodeType != 1);
4939         return n;
4940     };
4941
4942     function children(d){
4943         var n = d.firstChild, ni = -1;
4944             while(n){
4945                 var nx = n.nextSibling;
4946                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4947                     d.removeChild(n);
4948                 }else{
4949                     n.nodeIndex = ++ni;
4950                 }
4951                 n = nx;
4952             }
4953             return this;
4954         };
4955
4956     function byClassName(c, a, v){
4957         if(!v){
4958             return c;
4959         }
4960         var r = [], ri = -1, cn;
4961         for(var i = 0, ci; ci = c[i]; i++){
4962             if((' '+ci.className+' ').indexOf(v) != -1){
4963                 r[++ri] = ci;
4964             }
4965         }
4966         return r;
4967     };
4968
4969     function attrValue(n, attr){
4970         if(!n.tagName && typeof n.length != "undefined"){
4971             n = n[0];
4972         }
4973         if(!n){
4974             return null;
4975         }
4976         if(attr == "for"){
4977             return n.htmlFor;
4978         }
4979         if(attr == "class" || attr == "className"){
4980             return n.className;
4981         }
4982         return n.getAttribute(attr) || n[attr];
4983
4984     };
4985
4986     function getNodes(ns, mode, tagName){
4987         var result = [], ri = -1, cs;
4988         if(!ns){
4989             return result;
4990         }
4991         tagName = tagName || "*";
4992         if(typeof ns.getElementsByTagName != "undefined"){
4993             ns = [ns];
4994         }
4995         if(!mode){
4996             for(var i = 0, ni; ni = ns[i]; i++){
4997                 cs = ni.getElementsByTagName(tagName);
4998                 for(var j = 0, ci; ci = cs[j]; j++){
4999                     result[++ri] = ci;
5000                 }
5001             }
5002         }else if(mode == "/" || mode == ">"){
5003             var utag = tagName.toUpperCase();
5004             for(var i = 0, ni, cn; ni = ns[i]; i++){
5005                 cn = ni.children || ni.childNodes;
5006                 for(var j = 0, cj; cj = cn[j]; j++){
5007                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5008                         result[++ri] = cj;
5009                     }
5010                 }
5011             }
5012         }else if(mode == "+"){
5013             var utag = tagName.toUpperCase();
5014             for(var i = 0, n; n = ns[i]; i++){
5015                 while((n = n.nextSibling) && n.nodeType != 1);
5016                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017                     result[++ri] = n;
5018                 }
5019             }
5020         }else if(mode == "~"){
5021             for(var i = 0, n; n = ns[i]; i++){
5022                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5023                 if(n){
5024                     result[++ri] = n;
5025                 }
5026             }
5027         }
5028         return result;
5029     };
5030
5031     function concat(a, b){
5032         if(b.slice){
5033             return a.concat(b);
5034         }
5035         for(var i = 0, l = b.length; i < l; i++){
5036             a[a.length] = b[i];
5037         }
5038         return a;
5039     }
5040
5041     function byTag(cs, tagName){
5042         if(cs.tagName || cs == document){
5043             cs = [cs];
5044         }
5045         if(!tagName){
5046             return cs;
5047         }
5048         var r = [], ri = -1;
5049         tagName = tagName.toLowerCase();
5050         for(var i = 0, ci; ci = cs[i]; i++){
5051             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5052                 r[++ri] = ci;
5053             }
5054         }
5055         return r;
5056     };
5057
5058     function byId(cs, attr, id){
5059         if(cs.tagName || cs == document){
5060             cs = [cs];
5061         }
5062         if(!id){
5063             return cs;
5064         }
5065         var r = [], ri = -1;
5066         for(var i = 0,ci; ci = cs[i]; i++){
5067             if(ci && ci.id == id){
5068                 r[++ri] = ci;
5069                 return r;
5070             }
5071         }
5072         return r;
5073     };
5074
5075     function byAttribute(cs, attr, value, op, custom){
5076         var r = [], ri = -1, st = custom=="{";
5077         var f = Roo.DomQuery.operators[op];
5078         for(var i = 0, ci; ci = cs[i]; i++){
5079             var a;
5080             if(st){
5081                 a = Roo.DomQuery.getStyle(ci, attr);
5082             }
5083             else if(attr == "class" || attr == "className"){
5084                 a = ci.className;
5085             }else if(attr == "for"){
5086                 a = ci.htmlFor;
5087             }else if(attr == "href"){
5088                 a = ci.getAttribute("href", 2);
5089             }else{
5090                 a = ci.getAttribute(attr);
5091             }
5092             if((f && f(a, value)) || (!f && a)){
5093                 r[++ri] = ci;
5094             }
5095         }
5096         return r;
5097     };
5098
5099     function byPseudo(cs, name, value){
5100         return Roo.DomQuery.pseudos[name](cs, value);
5101     };
5102
5103     // This is for IE MSXML which does not support expandos.
5104     // IE runs the same speed using setAttribute, however FF slows way down
5105     // and Safari completely fails so they need to continue to use expandos.
5106     var isIE = window.ActiveXObject ? true : false;
5107
5108     // this eval is stop the compressor from
5109     // renaming the variable to something shorter
5110     
5111     /** eval:var:batch */
5112     var batch = 30803; 
5113
5114     var key = 30803;
5115
5116     function nodupIEXml(cs){
5117         var d = ++key;
5118         cs[0].setAttribute("_nodup", d);
5119         var r = [cs[0]];
5120         for(var i = 1, len = cs.length; i < len; i++){
5121             var c = cs[i];
5122             if(!c.getAttribute("_nodup") != d){
5123                 c.setAttribute("_nodup", d);
5124                 r[r.length] = c;
5125             }
5126         }
5127         for(var i = 0, len = cs.length; i < len; i++){
5128             cs[i].removeAttribute("_nodup");
5129         }
5130         return r;
5131     }
5132
5133     function nodup(cs){
5134         if(!cs){
5135             return [];
5136         }
5137         var len = cs.length, c, i, r = cs, cj, ri = -1;
5138         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5139             return cs;
5140         }
5141         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5142             return nodupIEXml(cs);
5143         }
5144         var d = ++key;
5145         cs[0]._nodup = d;
5146         for(i = 1; c = cs[i]; i++){
5147             if(c._nodup != d){
5148                 c._nodup = d;
5149             }else{
5150                 r = [];
5151                 for(var j = 0; j < i; j++){
5152                     r[++ri] = cs[j];
5153                 }
5154                 for(j = i+1; cj = cs[j]; j++){
5155                     if(cj._nodup != d){
5156                         cj._nodup = d;
5157                         r[++ri] = cj;
5158                     }
5159                 }
5160                 return r;
5161             }
5162         }
5163         return r;
5164     }
5165
5166     function quickDiffIEXml(c1, c2){
5167         var d = ++key;
5168         for(var i = 0, len = c1.length; i < len; i++){
5169             c1[i].setAttribute("_qdiff", d);
5170         }
5171         var r = [];
5172         for(var i = 0, len = c2.length; i < len; i++){
5173             if(c2[i].getAttribute("_qdiff") != d){
5174                 r[r.length] = c2[i];
5175             }
5176         }
5177         for(var i = 0, len = c1.length; i < len; i++){
5178            c1[i].removeAttribute("_qdiff");
5179         }
5180         return r;
5181     }
5182
5183     function quickDiff(c1, c2){
5184         var len1 = c1.length;
5185         if(!len1){
5186             return c2;
5187         }
5188         if(isIE && c1[0].selectSingleNode){
5189             return quickDiffIEXml(c1, c2);
5190         }
5191         var d = ++key;
5192         for(var i = 0; i < len1; i++){
5193             c1[i]._qdiff = d;
5194         }
5195         var r = [];
5196         for(var i = 0, len = c2.length; i < len; i++){
5197             if(c2[i]._qdiff != d){
5198                 r[r.length] = c2[i];
5199             }
5200         }
5201         return r;
5202     }
5203
5204     function quickId(ns, mode, root, id){
5205         if(ns == root){
5206            var d = root.ownerDocument || root;
5207            return d.getElementById(id);
5208         }
5209         ns = getNodes(ns, mode, "*");
5210         return byId(ns, null, id);
5211     }
5212
5213     return {
5214         getStyle : function(el, name){
5215             return Roo.fly(el).getStyle(name);
5216         },
5217         /**
5218          * Compiles a selector/xpath query into a reusable function. The returned function
5219          * takes one parameter "root" (optional), which is the context node from where the query should start.
5220          * @param {String} selector The selector/xpath query
5221          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5222          * @return {Function}
5223          */
5224         compile : function(path, type){
5225             type = type || "select";
5226             
5227             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5228             var q = path, mode, lq;
5229             var tk = Roo.DomQuery.matchers;
5230             var tklen = tk.length;
5231             var mm;
5232
5233             // accept leading mode switch
5234             var lmode = q.match(modeRe);
5235             if(lmode && lmode[1]){
5236                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5237                 q = q.replace(lmode[1], "");
5238             }
5239             // strip leading slashes
5240             while(path.substr(0, 1)=="/"){
5241                 path = path.substr(1);
5242             }
5243
5244             while(q && lq != q){
5245                 lq = q;
5246                 var tm = q.match(tagTokenRe);
5247                 if(type == "select"){
5248                     if(tm){
5249                         if(tm[1] == "#"){
5250                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5251                         }else{
5252                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5253                         }
5254                         q = q.replace(tm[0], "");
5255                     }else if(q.substr(0, 1) != '@'){
5256                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5257                     }
5258                 }else{
5259                     if(tm){
5260                         if(tm[1] == "#"){
5261                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5262                         }else{
5263                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5264                         }
5265                         q = q.replace(tm[0], "");
5266                     }
5267                 }
5268                 while(!(mm = q.match(modeRe))){
5269                     var matched = false;
5270                     for(var j = 0; j < tklen; j++){
5271                         var t = tk[j];
5272                         var m = q.match(t.re);
5273                         if(m){
5274                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5275                                                     return m[i];
5276                                                 });
5277                             q = q.replace(m[0], "");
5278                             matched = true;
5279                             break;
5280                         }
5281                     }
5282                     // prevent infinite loop on bad selector
5283                     if(!matched){
5284                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5285                     }
5286                 }
5287                 if(mm[1]){
5288                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5289                     q = q.replace(mm[1], "");
5290                 }
5291             }
5292             fn[fn.length] = "return nodup(n);\n}";
5293             
5294              /** 
5295               * list of variables that need from compression as they are used by eval.
5296              *  eval:var:batch 
5297              *  eval:var:nodup
5298              *  eval:var:byTag
5299              *  eval:var:ById
5300              *  eval:var:getNodes
5301              *  eval:var:quickId
5302              *  eval:var:mode
5303              *  eval:var:root
5304              *  eval:var:n
5305              *  eval:var:byClassName
5306              *  eval:var:byPseudo
5307              *  eval:var:byAttribute
5308              *  eval:var:attrValue
5309              * 
5310              **/ 
5311             eval(fn.join(""));
5312             return f;
5313         },
5314
5315         /**
5316          * Selects a group of elements.
5317          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5318          * @param {Node} root (optional) The start of the query (defaults to document).
5319          * @return {Array}
5320          */
5321         select : function(path, root, type){
5322             if(!root || root == document){
5323                 root = document;
5324             }
5325             if(typeof root == "string"){
5326                 root = document.getElementById(root);
5327             }
5328             var paths = path.split(",");
5329             var results = [];
5330             for(var i = 0, len = paths.length; i < len; i++){
5331                 var p = paths[i].replace(trimRe, "");
5332                 if(!cache[p]){
5333                     cache[p] = Roo.DomQuery.compile(p);
5334                     if(!cache[p]){
5335                         throw p + " is not a valid selector";
5336                     }
5337                 }
5338                 var result = cache[p](root);
5339                 if(result && result != document){
5340                     results = results.concat(result);
5341                 }
5342             }
5343             if(paths.length > 1){
5344                 return nodup(results);
5345             }
5346             return results;
5347         },
5348
5349         /**
5350          * Selects a single element.
5351          * @param {String} selector The selector/xpath query
5352          * @param {Node} root (optional) The start of the query (defaults to document).
5353          * @return {Element}
5354          */
5355         selectNode : function(path, root){
5356             return Roo.DomQuery.select(path, root)[0];
5357         },
5358
5359         /**
5360          * Selects the value of a node, optionally replacing null with the defaultValue.
5361          * @param {String} selector The selector/xpath query
5362          * @param {Node} root (optional) The start of the query (defaults to document).
5363          * @param {String} defaultValue
5364          */
5365         selectValue : function(path, root, defaultValue){
5366             path = path.replace(trimRe, "");
5367             if(!valueCache[path]){
5368                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5369             }
5370             var n = valueCache[path](root);
5371             n = n[0] ? n[0] : n;
5372             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5373             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374         },
5375
5376         /**
5377          * Selects the value of a node, parsing integers and floats.
5378          * @param {String} selector The selector/xpath query
5379          * @param {Node} root (optional) The start of the query (defaults to document).
5380          * @param {Number} defaultValue
5381          * @return {Number}
5382          */
5383         selectNumber : function(path, root, defaultValue){
5384             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5385             return parseFloat(v);
5386         },
5387
5388         /**
5389          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5390          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5391          * @param {String} selector The simple selector to test
5392          * @return {Boolean}
5393          */
5394         is : function(el, ss){
5395             if(typeof el == "string"){
5396                 el = document.getElementById(el);
5397             }
5398             var isArray = (el instanceof Array);
5399             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5400             return isArray ? (result.length == el.length) : (result.length > 0);
5401         },
5402
5403         /**
5404          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5405          * @param {Array} el An array of elements to filter
5406          * @param {String} selector The simple selector to test
5407          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5408          * the selector instead of the ones that match
5409          * @return {Array}
5410          */
5411         filter : function(els, ss, nonMatches){
5412             ss = ss.replace(trimRe, "");
5413             if(!simpleCache[ss]){
5414                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5415             }
5416             var result = simpleCache[ss](els);
5417             return nonMatches ? quickDiff(result, els) : result;
5418         },
5419
5420         /**
5421          * Collection of matching regular expressions and code snippets.
5422          */
5423         matchers : [{
5424                 re: /^\.([\w-]+)/,
5425                 select: 'n = byClassName(n, null, " {1} ");'
5426             }, {
5427                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5428                 select: 'n = byPseudo(n, "{1}", "{2}");'
5429             },{
5430                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5431                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5432             }, {
5433                 re: /^#([\w-]+)/,
5434                 select: 'n = byId(n, null, "{1}");'
5435             },{
5436                 re: /^@([\w-]+)/,
5437                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5438             }
5439         ],
5440
5441         /**
5442          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5443          * 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;.
5444          */
5445         operators : {
5446             "=" : function(a, v){
5447                 return a == v;
5448             },
5449             "!=" : function(a, v){
5450                 return a != v;
5451             },
5452             "^=" : function(a, v){
5453                 return a && a.substr(0, v.length) == v;
5454             },
5455             "$=" : function(a, v){
5456                 return a && a.substr(a.length-v.length) == v;
5457             },
5458             "*=" : function(a, v){
5459                 return a && a.indexOf(v) !== -1;
5460             },
5461             "%=" : function(a, v){
5462                 return (a % v) == 0;
5463             },
5464             "|=" : function(a, v){
5465                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5466             },
5467             "~=" : function(a, v){
5468                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5469             }
5470         },
5471
5472         /**
5473          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5474          * and the argument (if any) supplied in the selector.
5475          */
5476         pseudos : {
5477             "first-child" : function(c){
5478                 var r = [], ri = -1, n;
5479                 for(var i = 0, ci; ci = n = c[i]; i++){
5480                     while((n = n.previousSibling) && n.nodeType != 1);
5481                     if(!n){
5482                         r[++ri] = ci;
5483                     }
5484                 }
5485                 return r;
5486             },
5487
5488             "last-child" : function(c){
5489                 var r = [], ri = -1, n;
5490                 for(var i = 0, ci; ci = n = c[i]; i++){
5491                     while((n = n.nextSibling) && n.nodeType != 1);
5492                     if(!n){
5493                         r[++ri] = ci;
5494                     }
5495                 }
5496                 return r;
5497             },
5498
5499             "nth-child" : function(c, a) {
5500                 var r = [], ri = -1;
5501                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5502                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5503                 for(var i = 0, n; n = c[i]; i++){
5504                     var pn = n.parentNode;
5505                     if (batch != pn._batch) {
5506                         var j = 0;
5507                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5508                             if(cn.nodeType == 1){
5509                                cn.nodeIndex = ++j;
5510                             }
5511                         }
5512                         pn._batch = batch;
5513                     }
5514                     if (f == 1) {
5515                         if (l == 0 || n.nodeIndex == l){
5516                             r[++ri] = n;
5517                         }
5518                     } else if ((n.nodeIndex + l) % f == 0){
5519                         r[++ri] = n;
5520                     }
5521                 }
5522
5523                 return r;
5524             },
5525
5526             "only-child" : function(c){
5527                 var r = [], ri = -1;;
5528                 for(var i = 0, ci; ci = c[i]; i++){
5529                     if(!prev(ci) && !next(ci)){
5530                         r[++ri] = ci;
5531                     }
5532                 }
5533                 return r;
5534             },
5535
5536             "empty" : function(c){
5537                 var r = [], ri = -1;
5538                 for(var i = 0, ci; ci = c[i]; i++){
5539                     var cns = ci.childNodes, j = 0, cn, empty = true;
5540                     while(cn = cns[j]){
5541                         ++j;
5542                         if(cn.nodeType == 1 || cn.nodeType == 3){
5543                             empty = false;
5544                             break;
5545                         }
5546                     }
5547                     if(empty){
5548                         r[++ri] = ci;
5549                     }
5550                 }
5551                 return r;
5552             },
5553
5554             "contains" : function(c, v){
5555                 var r = [], ri = -1;
5556                 for(var i = 0, ci; ci = c[i]; i++){
5557                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5558                         r[++ri] = ci;
5559                     }
5560                 }
5561                 return r;
5562             },
5563
5564             "nodeValue" : function(c, v){
5565                 var r = [], ri = -1;
5566                 for(var i = 0, ci; ci = c[i]; i++){
5567                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5568                         r[++ri] = ci;
5569                     }
5570                 }
5571                 return r;
5572             },
5573
5574             "checked" : function(c){
5575                 var r = [], ri = -1;
5576                 for(var i = 0, ci; ci = c[i]; i++){
5577                     if(ci.checked == true){
5578                         r[++ri] = ci;
5579                     }
5580                 }
5581                 return r;
5582             },
5583
5584             "not" : function(c, ss){
5585                 return Roo.DomQuery.filter(c, ss, true);
5586             },
5587
5588             "odd" : function(c){
5589                 return this["nth-child"](c, "odd");
5590             },
5591
5592             "even" : function(c){
5593                 return this["nth-child"](c, "even");
5594             },
5595
5596             "nth" : function(c, a){
5597                 return c[a-1] || [];
5598             },
5599
5600             "first" : function(c){
5601                 return c[0] || [];
5602             },
5603
5604             "last" : function(c){
5605                 return c[c.length-1] || [];
5606             },
5607
5608             "has" : function(c, ss){
5609                 var s = Roo.DomQuery.select;
5610                 var r = [], ri = -1;
5611                 for(var i = 0, ci; ci = c[i]; i++){
5612                     if(s(ss, ci).length > 0){
5613                         r[++ri] = ci;
5614                     }
5615                 }
5616                 return r;
5617             },
5618
5619             "next" : function(c, ss){
5620                 var is = Roo.DomQuery.is;
5621                 var r = [], ri = -1;
5622                 for(var i = 0, ci; ci = c[i]; i++){
5623                     var n = next(ci);
5624                     if(n && is(n, ss)){
5625                         r[++ri] = ci;
5626                     }
5627                 }
5628                 return r;
5629             },
5630
5631             "prev" : function(c, ss){
5632                 var is = Roo.DomQuery.is;
5633                 var r = [], ri = -1;
5634                 for(var i = 0, ci; ci = c[i]; i++){
5635                     var n = prev(ci);
5636                     if(n && is(n, ss)){
5637                         r[++ri] = ci;
5638                     }
5639                 }
5640                 return r;
5641             }
5642         }
5643     };
5644 }();
5645
5646 /**
5647  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5648  * @param {String} path The selector/xpath query
5649  * @param {Node} root (optional) The start of the query (defaults to document).
5650  * @return {Array}
5651  * @member Roo
5652  * @method query
5653  */
5654 Roo.query = Roo.DomQuery.select;
5655 /*
5656  * Based on:
5657  * Ext JS Library 1.1.1
5658  * Copyright(c) 2006-2007, Ext JS, LLC.
5659  *
5660  * Originally Released Under LGPL - original licence link has changed is not relivant.
5661  *
5662  * Fork - LGPL
5663  * <script type="text/javascript">
5664  */
5665
5666 /**
5667  * @class Roo.util.Observable
5668  * Base class that provides a common interface for publishing events. Subclasses are expected to
5669  * to have a property "events" with all the events defined.<br>
5670  * For example:
5671  * <pre><code>
5672  Employee = function(name){
5673     this.name = name;
5674     this.addEvents({
5675         "fired" : true,
5676         "quit" : true
5677     });
5678  }
5679  Roo.extend(Employee, Roo.util.Observable);
5680 </code></pre>
5681  * @param {Object} config properties to use (incuding events / listeners)
5682  */
5683
5684 Roo.util.Observable = function(cfg){
5685     
5686     cfg = cfg|| {};
5687     this.addEvents(cfg.events || {});
5688     if (cfg.events) {
5689         delete cfg.events; // make sure
5690     }
5691      
5692     Roo.apply(this, cfg);
5693     
5694     if(this.listeners){
5695         this.on(this.listeners);
5696         delete this.listeners;
5697     }
5698 };
5699 Roo.util.Observable.prototype = {
5700     /** 
5701  * @cfg {Object} listeners  list of events and functions to call for this object, 
5702  * For example :
5703  * <pre><code>
5704     listeners :  { 
5705        'click' : function(e) {
5706            ..... 
5707         } ,
5708         .... 
5709     } 
5710   </code></pre>
5711  */
5712     
5713     
5714     /**
5715      * Fires the specified event with the passed parameters (minus the event name).
5716      * @param {String} eventName
5717      * @param {Object...} args Variable number of parameters are passed to handlers
5718      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5719      */
5720     fireEvent : function(){
5721         var ce = this.events[arguments[0].toLowerCase()];
5722         if(typeof ce == "object"){
5723             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5724         }else{
5725             return true;
5726         }
5727     },
5728
5729     // private
5730     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5731
5732     /**
5733      * Appends an event handler to this component
5734      * @param {String}   eventName The type of event to listen for
5735      * @param {Function} handler The method the event invokes
5736      * @param {Object}   scope (optional) The scope in which to execute the handler
5737      * function. The handler function's "this" context.
5738      * @param {Object}   options (optional) An object containing handler configuration
5739      * properties. This may contain any of the following properties:<ul>
5740      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5741      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5742      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5743      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5744      * by the specified number of milliseconds. If the event fires again within that time, the original
5745      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5746      * </ul><br>
5747      * <p>
5748      * <b>Combining Options</b><br>
5749      * Using the options argument, it is possible to combine different types of listeners:<br>
5750      * <br>
5751      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5752                 <pre><code>
5753                 el.on('click', this.onClick, this, {
5754                         single: true,
5755                 delay: 100,
5756                 forumId: 4
5757                 });
5758                 </code></pre>
5759      * <p>
5760      * <b>Attaching multiple handlers in 1 call</b><br>
5761      * The method also allows for a single argument to be passed which is a config object containing properties
5762      * which specify multiple handlers.
5763      * <pre><code>
5764                 el.on({
5765                         'click': {
5766                         fn: this.onClick,
5767                         scope: this,
5768                         delay: 100
5769                 }, 
5770                 'mouseover': {
5771                         fn: this.onMouseOver,
5772                         scope: this
5773                 },
5774                 'mouseout': {
5775                         fn: this.onMouseOut,
5776                         scope: this
5777                 }
5778                 });
5779                 </code></pre>
5780      * <p>
5781      * Or a shorthand syntax which passes the same scope object to all handlers:
5782         <pre><code>
5783                 el.on({
5784                         'click': this.onClick,
5785                 'mouseover': this.onMouseOver,
5786                 'mouseout': this.onMouseOut,
5787                 scope: this
5788                 });
5789                 </code></pre>
5790      */
5791     addListener : function(eventName, fn, scope, o){
5792         if(typeof eventName == "object"){
5793             o = eventName;
5794             for(var e in o){
5795                 if(this.filterOptRe.test(e)){
5796                     continue;
5797                 }
5798                 if(typeof o[e] == "function"){
5799                     // shared options
5800                     this.addListener(e, o[e], o.scope,  o);
5801                 }else{
5802                     // individual options
5803                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5804                 }
5805             }
5806             return;
5807         }
5808         o = (!o || typeof o == "boolean") ? {} : o;
5809         eventName = eventName.toLowerCase();
5810         var ce = this.events[eventName] || true;
5811         if(typeof ce == "boolean"){
5812             ce = new Roo.util.Event(this, eventName);
5813             this.events[eventName] = ce;
5814         }
5815         ce.addListener(fn, scope, o);
5816     },
5817
5818     /**
5819      * Removes a listener
5820      * @param {String}   eventName     The type of event to listen for
5821      * @param {Function} handler        The handler to remove
5822      * @param {Object}   scope  (optional) The scope (this object) for the handler
5823      */
5824     removeListener : function(eventName, fn, scope){
5825         var ce = this.events[eventName.toLowerCase()];
5826         if(typeof ce == "object"){
5827             ce.removeListener(fn, scope);
5828         }
5829     },
5830
5831     /**
5832      * Removes all listeners for this object
5833      */
5834     purgeListeners : function(){
5835         for(var evt in this.events){
5836             if(typeof this.events[evt] == "object"){
5837                  this.events[evt].clearListeners();
5838             }
5839         }
5840     },
5841
5842     relayEvents : function(o, events){
5843         var createHandler = function(ename){
5844             return function(){
5845                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5846             };
5847         };
5848         for(var i = 0, len = events.length; i < len; i++){
5849             var ename = events[i];
5850             if(!this.events[ename]){ this.events[ename] = true; };
5851             o.on(ename, createHandler(ename), this);
5852         }
5853     },
5854
5855     /**
5856      * Used to define events on this Observable
5857      * @param {Object} object The object with the events defined
5858      */
5859     addEvents : function(o){
5860         if(!this.events){
5861             this.events = {};
5862         }
5863         Roo.applyIf(this.events, o);
5864     },
5865
5866     /**
5867      * Checks to see if this object has any listeners for a specified event
5868      * @param {String} eventName The name of the event to check for
5869      * @return {Boolean} True if the event is being listened for, else false
5870      */
5871     hasListener : function(eventName){
5872         var e = this.events[eventName];
5873         return typeof e == "object" && e.listeners.length > 0;
5874     }
5875 };
5876 /**
5877  * Appends an event handler to this element (shorthand for addListener)
5878  * @param {String}   eventName     The type of event to listen for
5879  * @param {Function} handler        The method the event invokes
5880  * @param {Object}   scope (optional) The scope in which to execute the handler
5881  * function. The handler function's "this" context.
5882  * @param {Object}   options  (optional)
5883  * @method
5884  */
5885 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5886 /**
5887  * Removes a listener (shorthand for removeListener)
5888  * @param {String}   eventName     The type of event to listen for
5889  * @param {Function} handler        The handler to remove
5890  * @param {Object}   scope  (optional) The scope (this object) for the handler
5891  * @method
5892  */
5893 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5894
5895 /**
5896  * Starts capture on the specified Observable. All events will be passed
5897  * to the supplied function with the event name + standard signature of the event
5898  * <b>before</b> the event is fired. If the supplied function returns false,
5899  * the event will not fire.
5900  * @param {Observable} o The Observable to capture
5901  * @param {Function} fn The function to call
5902  * @param {Object} scope (optional) The scope (this object) for the fn
5903  * @static
5904  */
5905 Roo.util.Observable.capture = function(o, fn, scope){
5906     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 };
5908
5909 /**
5910  * Removes <b>all</b> added captures from the Observable.
5911  * @param {Observable} o The Observable to release
5912  * @static
5913  */
5914 Roo.util.Observable.releaseCapture = function(o){
5915     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5916 };
5917
5918 (function(){
5919
5920     var createBuffered = function(h, o, scope){
5921         var task = new Roo.util.DelayedTask();
5922         return function(){
5923             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924         };
5925     };
5926
5927     var createSingle = function(h, e, fn, scope){
5928         return function(){
5929             e.removeListener(fn, scope);
5930             return h.apply(scope, arguments);
5931         };
5932     };
5933
5934     var createDelayed = function(h, o, scope){
5935         return function(){
5936             var args = Array.prototype.slice.call(arguments, 0);
5937             setTimeout(function(){
5938                 h.apply(scope, args);
5939             }, o.delay || 10);
5940         };
5941     };
5942
5943     Roo.util.Event = function(obj, name){
5944         this.name = name;
5945         this.obj = obj;
5946         this.listeners = [];
5947     };
5948
5949     Roo.util.Event.prototype = {
5950         addListener : function(fn, scope, options){
5951             var o = options || {};
5952             scope = scope || this.obj;
5953             if(!this.isListening(fn, scope)){
5954                 var l = {fn: fn, scope: scope, options: o};
5955                 var h = fn;
5956                 if(o.delay){
5957                     h = createDelayed(h, o, scope);
5958                 }
5959                 if(o.single){
5960                     h = createSingle(h, this, fn, scope);
5961                 }
5962                 if(o.buffer){
5963                     h = createBuffered(h, o, scope);
5964                 }
5965                 l.fireFn = h;
5966                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5967                     this.listeners.push(l);
5968                 }else{
5969                     this.listeners = this.listeners.slice(0);
5970                     this.listeners.push(l);
5971                 }
5972             }
5973         },
5974
5975         findListener : function(fn, scope){
5976             scope = scope || this.obj;
5977             var ls = this.listeners;
5978             for(var i = 0, len = ls.length; i < len; i++){
5979                 var l = ls[i];
5980                 if(l.fn == fn && l.scope == scope){
5981                     return i;
5982                 }
5983             }
5984             return -1;
5985         },
5986
5987         isListening : function(fn, scope){
5988             return this.findListener(fn, scope) != -1;
5989         },
5990
5991         removeListener : function(fn, scope){
5992             var index;
5993             if((index = this.findListener(fn, scope)) != -1){
5994                 if(!this.firing){
5995                     this.listeners.splice(index, 1);
5996                 }else{
5997                     this.listeners = this.listeners.slice(0);
5998                     this.listeners.splice(index, 1);
5999                 }
6000                 return true;
6001             }
6002             return false;
6003         },
6004
6005         clearListeners : function(){
6006             this.listeners = [];
6007         },
6008
6009         fire : function(){
6010             var ls = this.listeners, scope, len = ls.length;
6011             if(len > 0){
6012                 this.firing = true;
6013                 var args = Array.prototype.slice.call(arguments, 0);
6014                 for(var i = 0; i < len; i++){
6015                     var l = ls[i];
6016                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6017                         this.firing = false;
6018                         return false;
6019                     }
6020                 }
6021                 this.firing = false;
6022             }
6023             return true;
6024         }
6025     };
6026 })();/*
6027  * Based on:
6028  * Ext JS Library 1.1.1
6029  * Copyright(c) 2006-2007, Ext JS, LLC.
6030  *
6031  * Originally Released Under LGPL - original licence link has changed is not relivant.
6032  *
6033  * Fork - LGPL
6034  * <script type="text/javascript">
6035  */
6036
6037 /**
6038  * @class Roo.EventManager
6039  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6040  * several useful events directly.
6041  * See {@link Roo.EventObject} for more details on normalized event objects.
6042  * @singleton
6043  */
6044 Roo.EventManager = function(){
6045     var docReadyEvent, docReadyProcId, docReadyState = false;
6046     var resizeEvent, resizeTask, textEvent, textSize;
6047     var E = Roo.lib.Event;
6048     var D = Roo.lib.Dom;
6049
6050
6051     var fireDocReady = function(){
6052         if(!docReadyState){
6053             docReadyState = true;
6054             Roo.isReady = true;
6055             if(docReadyProcId){
6056                 clearInterval(docReadyProcId);
6057             }
6058             if(Roo.isGecko || Roo.isOpera) {
6059                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6060             }
6061             if(Roo.isIE){
6062                 var defer = document.getElementById("ie-deferred-loader");
6063                 if(defer){
6064                     defer.onreadystatechange = null;
6065                     defer.parentNode.removeChild(defer);
6066                 }
6067             }
6068             if(docReadyEvent){
6069                 docReadyEvent.fire();
6070                 docReadyEvent.clearListeners();
6071             }
6072         }
6073     };
6074     
6075     var initDocReady = function(){
6076         docReadyEvent = new Roo.util.Event();
6077         if(Roo.isGecko || Roo.isOpera) {
6078             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6079         }else if(Roo.isIE){
6080             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6081             var defer = document.getElementById("ie-deferred-loader");
6082             defer.onreadystatechange = function(){
6083                 if(this.readyState == "complete"){
6084                     fireDocReady();
6085                 }
6086             };
6087         }else if(Roo.isSafari){ 
6088             docReadyProcId = setInterval(function(){
6089                 var rs = document.readyState;
6090                 if(rs == "complete") {
6091                     fireDocReady();     
6092                  }
6093             }, 10);
6094         }
6095         // no matter what, make sure it fires on load
6096         E.on(window, "load", fireDocReady);
6097     };
6098
6099     var createBuffered = function(h, o){
6100         var task = new Roo.util.DelayedTask(h);
6101         return function(e){
6102             // create new event object impl so new events don't wipe out properties
6103             e = new Roo.EventObjectImpl(e);
6104             task.delay(o.buffer, h, null, [e]);
6105         };
6106     };
6107
6108     var createSingle = function(h, el, ename, fn){
6109         return function(e){
6110             Roo.EventManager.removeListener(el, ename, fn);
6111             h(e);
6112         };
6113     };
6114
6115     var createDelayed = function(h, o){
6116         return function(e){
6117             // create new event object impl so new events don't wipe out properties
6118             e = new Roo.EventObjectImpl(e);
6119             setTimeout(function(){
6120                 h(e);
6121             }, o.delay || 10);
6122         };
6123     };
6124
6125     var listen = function(element, ename, opt, fn, scope){
6126         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6127         fn = fn || o.fn; scope = scope || o.scope;
6128         var el = Roo.getDom(element);
6129         if(!el){
6130             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6131         }
6132         var h = function(e){
6133             e = Roo.EventObject.setEvent(e);
6134             var t;
6135             if(o.delegate){
6136                 t = e.getTarget(o.delegate, el);
6137                 if(!t){
6138                     return;
6139                 }
6140             }else{
6141                 t = e.target;
6142             }
6143             if(o.stopEvent === true){
6144                 e.stopEvent();
6145             }
6146             if(o.preventDefault === true){
6147                e.preventDefault();
6148             }
6149             if(o.stopPropagation === true){
6150                 e.stopPropagation();
6151             }
6152
6153             if(o.normalized === false){
6154                 e = e.browserEvent;
6155             }
6156
6157             fn.call(scope || el, e, t, o);
6158         };
6159         if(o.delay){
6160             h = createDelayed(h, o);
6161         }
6162         if(o.single){
6163             h = createSingle(h, el, ename, fn);
6164         }
6165         if(o.buffer){
6166             h = createBuffered(h, o);
6167         }
6168         fn._handlers = fn._handlers || [];
6169         fn._handlers.push([Roo.id(el), ename, h]);
6170
6171         E.on(el, ename, h);
6172         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6173             el.addEventListener("DOMMouseScroll", h, false);
6174             E.on(window, 'unload', function(){
6175                 el.removeEventListener("DOMMouseScroll", h, false);
6176             });
6177         }
6178         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6179             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6180         }
6181         return h;
6182     };
6183
6184     var stopListening = function(el, ename, fn){
6185         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6186         if(hds){
6187             for(var i = 0, len = hds.length; i < len; i++){
6188                 var h = hds[i];
6189                 if(h[0] == id && h[1] == ename){
6190                     hd = h[2];
6191                     hds.splice(i, 1);
6192                     break;
6193                 }
6194             }
6195         }
6196         E.un(el, ename, hd);
6197         el = Roo.getDom(el);
6198         if(ename == "mousewheel" && el.addEventListener){
6199             el.removeEventListener("DOMMouseScroll", hd, false);
6200         }
6201         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6202             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203         }
6204     };
6205
6206     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6207     
6208     var pub = {
6209         
6210         
6211         /** 
6212          * Fix for doc tools
6213          * @scope Roo.EventManager
6214          */
6215         
6216         
6217         /** 
6218          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6219          * object with a Roo.EventObject
6220          * @param {Function} fn        The method the event invokes
6221          * @param {Object}   scope    An object that becomes the scope of the handler
6222          * @param {boolean}  override If true, the obj passed in becomes
6223          *                             the execution scope of the listener
6224          * @return {Function} The wrapped function
6225          * @deprecated
6226          */
6227         wrap : function(fn, scope, override){
6228             return function(e){
6229                 Roo.EventObject.setEvent(e);
6230                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6231             };
6232         },
6233         
6234         /**
6235      * Appends an event handler to an element (shorthand for addListener)
6236      * @param {String/HTMLElement}   element        The html element or id to assign the
6237      * @param {String}   eventName The type of event to listen for
6238      * @param {Function} handler The method the event invokes
6239      * @param {Object}   scope (optional) The scope in which to execute the handler
6240      * function. The handler function's "this" context.
6241      * @param {Object}   options (optional) An object containing handler configuration
6242      * properties. This may contain any of the following properties:<ul>
6243      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6244      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6245      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6246      * <li>preventDefault {Boolean} True to prevent the default action</li>
6247      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6248      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6249      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6250      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6251      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6252      * by the specified number of milliseconds. If the event fires again within that time, the original
6253      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6254      * </ul><br>
6255      * <p>
6256      * <b>Combining Options</b><br>
6257      * Using the options argument, it is possible to combine different types of listeners:<br>
6258      * <br>
6259      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6260      * Code:<pre><code>
6261 el.on('click', this.onClick, this, {
6262     single: true,
6263     delay: 100,
6264     stopEvent : true,
6265     forumId: 4
6266 });</code></pre>
6267      * <p>
6268      * <b>Attaching multiple handlers in 1 call</b><br>
6269       * The method also allows for a single argument to be passed which is a config object containing properties
6270      * which specify multiple handlers.
6271      * <p>
6272      * Code:<pre><code>
6273 el.on({
6274     'click' : {
6275         fn: this.onClick
6276         scope: this,
6277         delay: 100
6278     },
6279     'mouseover' : {
6280         fn: this.onMouseOver
6281         scope: this
6282     },
6283     'mouseout' : {
6284         fn: this.onMouseOut
6285         scope: this
6286     }
6287 });</code></pre>
6288      * <p>
6289      * Or a shorthand syntax:<br>
6290      * Code:<pre><code>
6291 el.on({
6292     'click' : this.onClick,
6293     'mouseover' : this.onMouseOver,
6294     'mouseout' : this.onMouseOut
6295     scope: this
6296 });</code></pre>
6297      */
6298         addListener : function(element, eventName, fn, scope, options){
6299             if(typeof eventName == "object"){
6300                 var o = eventName;
6301                 for(var e in o){
6302                     if(propRe.test(e)){
6303                         continue;
6304                     }
6305                     if(typeof o[e] == "function"){
6306                         // shared options
6307                         listen(element, e, o, o[e], o.scope);
6308                     }else{
6309                         // individual options
6310                         listen(element, e, o[e]);
6311                     }
6312                 }
6313                 return;
6314             }
6315             return listen(element, eventName, options, fn, scope);
6316         },
6317         
6318         /**
6319          * Removes an event handler
6320          *
6321          * @param {String/HTMLElement}   element        The id or html element to remove the 
6322          *                             event from
6323          * @param {String}   eventName     The type of event
6324          * @param {Function} fn
6325          * @return {Boolean} True if a listener was actually removed
6326          */
6327         removeListener : function(element, eventName, fn){
6328             return stopListening(element, eventName, fn);
6329         },
6330         
6331         /**
6332          * Fires when the document is ready (before onload and before images are loaded). Can be 
6333          * accessed shorthanded Roo.onReady().
6334          * @param {Function} fn        The method the event invokes
6335          * @param {Object}   scope    An  object that becomes the scope of the handler
6336          * @param {boolean}  options
6337          */
6338         onDocumentReady : function(fn, scope, options){
6339             if(docReadyState){ // if it already fired
6340                 docReadyEvent.addListener(fn, scope, options);
6341                 docReadyEvent.fire();
6342                 docReadyEvent.clearListeners();
6343                 return;
6344             }
6345             if(!docReadyEvent){
6346                 initDocReady();
6347             }
6348             docReadyEvent.addListener(fn, scope, options);
6349         },
6350         
6351         /**
6352          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6353          * @param {Function} fn        The method the event invokes
6354          * @param {Object}   scope    An object that becomes the scope of the handler
6355          * @param {boolean}  options
6356          */
6357         onWindowResize : function(fn, scope, options){
6358             if(!resizeEvent){
6359                 resizeEvent = new Roo.util.Event();
6360                 resizeTask = new Roo.util.DelayedTask(function(){
6361                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6362                 });
6363                 E.on(window, "resize", function(){
6364                     if(Roo.isIE){
6365                         resizeTask.delay(50);
6366                     }else{
6367                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368                     }
6369                 });
6370             }
6371             resizeEvent.addListener(fn, scope, options);
6372         },
6373
6374         /**
6375          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6376          * @param {Function} fn        The method the event invokes
6377          * @param {Object}   scope    An object that becomes the scope of the handler
6378          * @param {boolean}  options
6379          */
6380         onTextResize : function(fn, scope, options){
6381             if(!textEvent){
6382                 textEvent = new Roo.util.Event();
6383                 var textEl = new Roo.Element(document.createElement('div'));
6384                 textEl.dom.className = 'x-text-resize';
6385                 textEl.dom.innerHTML = 'X';
6386                 textEl.appendTo(document.body);
6387                 textSize = textEl.dom.offsetHeight;
6388                 setInterval(function(){
6389                     if(textEl.dom.offsetHeight != textSize){
6390                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6391                     }
6392                 }, this.textResizeInterval);
6393             }
6394             textEvent.addListener(fn, scope, options);
6395         },
6396
6397         /**
6398          * Removes the passed window resize listener.
6399          * @param {Function} fn        The method the event invokes
6400          * @param {Object}   scope    The scope of handler
6401          */
6402         removeResizeListener : function(fn, scope){
6403             if(resizeEvent){
6404                 resizeEvent.removeListener(fn, scope);
6405             }
6406         },
6407
6408         // private
6409         fireResize : function(){
6410             if(resizeEvent){
6411                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412             }   
6413         },
6414         /**
6415          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416          */
6417         ieDeferSrc : false,
6418         /**
6419          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6420          */
6421         textResizeInterval : 50
6422     };
6423     
6424     /**
6425      * Fix for doc tools
6426      * @scopeAlias pub=Roo.EventManager
6427      */
6428     
6429      /**
6430      * Appends an event handler to an element (shorthand for addListener)
6431      * @param {String/HTMLElement}   element        The html element or id to assign the
6432      * @param {String}   eventName The type of event to listen for
6433      * @param {Function} handler The method the event invokes
6434      * @param {Object}   scope (optional) The scope in which to execute the handler
6435      * function. The handler function's "this" context.
6436      * @param {Object}   options (optional) An object containing handler configuration
6437      * properties. This may contain any of the following properties:<ul>
6438      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6439      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6440      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6441      * <li>preventDefault {Boolean} True to prevent the default action</li>
6442      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6443      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6444      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6445      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6446      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6447      * by the specified number of milliseconds. If the event fires again within that time, the original
6448      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6449      * </ul><br>
6450      * <p>
6451      * <b>Combining Options</b><br>
6452      * Using the options argument, it is possible to combine different types of listeners:<br>
6453      * <br>
6454      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6455      * Code:<pre><code>
6456 el.on('click', this.onClick, this, {
6457     single: true,
6458     delay: 100,
6459     stopEvent : true,
6460     forumId: 4
6461 });</code></pre>
6462      * <p>
6463      * <b>Attaching multiple handlers in 1 call</b><br>
6464       * The method also allows for a single argument to be passed which is a config object containing properties
6465      * which specify multiple handlers.
6466      * <p>
6467      * Code:<pre><code>
6468 el.on({
6469     'click' : {
6470         fn: this.onClick
6471         scope: this,
6472         delay: 100
6473     },
6474     'mouseover' : {
6475         fn: this.onMouseOver
6476         scope: this
6477     },
6478     'mouseout' : {
6479         fn: this.onMouseOut
6480         scope: this
6481     }
6482 });</code></pre>
6483      * <p>
6484      * Or a shorthand syntax:<br>
6485      * Code:<pre><code>
6486 el.on({
6487     'click' : this.onClick,
6488     'mouseover' : this.onMouseOver,
6489     'mouseout' : this.onMouseOut
6490     scope: this
6491 });</code></pre>
6492      */
6493     pub.on = pub.addListener;
6494     pub.un = pub.removeListener;
6495
6496     pub.stoppedMouseDownEvent = new Roo.util.Event();
6497     return pub;
6498 }();
6499 /**
6500   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6501   * @param {Function} fn        The method the event invokes
6502   * @param {Object}   scope    An  object that becomes the scope of the handler
6503   * @param {boolean}  override If true, the obj passed in becomes
6504   *                             the execution scope of the listener
6505   * @member Roo
6506   * @method onReady
6507  */
6508 Roo.onReady = Roo.EventManager.onDocumentReady;
6509
6510 Roo.onReady(function(){
6511     var bd = Roo.get(document.body);
6512     if(!bd){ return; }
6513
6514     var cls = [
6515             Roo.isIE ? "roo-ie"
6516             : Roo.isGecko ? "roo-gecko"
6517             : Roo.isOpera ? "roo-opera"
6518             : Roo.isSafari ? "roo-safari" : ""];
6519
6520     if(Roo.isMac){
6521         cls.push("roo-mac");
6522     }
6523     if(Roo.isLinux){
6524         cls.push("roo-linux");
6525     }
6526     if(Roo.isBorderBox){
6527         cls.push('roo-border-box');
6528     }
6529     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6530         var p = bd.dom.parentNode;
6531         if(p){
6532             p.className += ' roo-strict';
6533         }
6534     }
6535     bd.addClass(cls.join(' '));
6536 });
6537
6538 /**
6539  * @class Roo.EventObject
6540  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6541  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6542  * Example:
6543  * <pre><code>
6544  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6545     e.preventDefault();
6546     var target = e.getTarget();
6547     ...
6548  }
6549  var myDiv = Roo.get("myDiv");
6550  myDiv.on("click", handleClick);
6551  //or
6552  Roo.EventManager.on("myDiv", 'click', handleClick);
6553  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554  </code></pre>
6555  * @singleton
6556  */
6557 Roo.EventObject = function(){
6558     
6559     var E = Roo.lib.Event;
6560     
6561     // safari keypress events for special keys return bad keycodes
6562     var safariKeys = {
6563         63234 : 37, // left
6564         63235 : 39, // right
6565         63232 : 38, // up
6566         63233 : 40, // down
6567         63276 : 33, // page up
6568         63277 : 34, // page down
6569         63272 : 46, // delete
6570         63273 : 36, // home
6571         63275 : 35  // end
6572     };
6573
6574     // normalize button clicks
6575     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6576                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6577
6578     Roo.EventObjectImpl = function(e){
6579         if(e){
6580             this.setEvent(e.browserEvent || e);
6581         }
6582     };
6583     Roo.EventObjectImpl.prototype = {
6584         /**
6585          * Used to fix doc tools.
6586          * @scope Roo.EventObject.prototype
6587          */
6588             
6589
6590         
6591         
6592         /** The normal browser event */
6593         browserEvent : null,
6594         /** The button pressed in a mouse event */
6595         button : -1,
6596         /** True if the shift key was down during the event */
6597         shiftKey : false,
6598         /** True if the control key was down during the event */
6599         ctrlKey : false,
6600         /** True if the alt key was down during the event */
6601         altKey : false,
6602
6603         /** Key constant 
6604         * @type Number */
6605         BACKSPACE : 8,
6606         /** Key constant 
6607         * @type Number */
6608         TAB : 9,
6609         /** Key constant 
6610         * @type Number */
6611         RETURN : 13,
6612         /** Key constant 
6613         * @type Number */
6614         ENTER : 13,
6615         /** Key constant 
6616         * @type Number */
6617         SHIFT : 16,
6618         /** Key constant 
6619         * @type Number */
6620         CONTROL : 17,
6621         /** Key constant 
6622         * @type Number */
6623         ESC : 27,
6624         /** Key constant 
6625         * @type Number */
6626         SPACE : 32,
6627         /** Key constant 
6628         * @type Number */
6629         PAGEUP : 33,
6630         /** Key constant 
6631         * @type Number */
6632         PAGEDOWN : 34,
6633         /** Key constant 
6634         * @type Number */
6635         END : 35,
6636         /** Key constant 
6637         * @type Number */
6638         HOME : 36,
6639         /** Key constant 
6640         * @type Number */
6641         LEFT : 37,
6642         /** Key constant 
6643         * @type Number */
6644         UP : 38,
6645         /** Key constant 
6646         * @type Number */
6647         RIGHT : 39,
6648         /** Key constant 
6649         * @type Number */
6650         DOWN : 40,
6651         /** Key constant 
6652         * @type Number */
6653         DELETE : 46,
6654         /** Key constant 
6655         * @type Number */
6656         F5 : 116,
6657
6658            /** @private */
6659         setEvent : function(e){
6660             if(e == this || (e && e.browserEvent)){ // already wrapped
6661                 return e;
6662             }
6663             this.browserEvent = e;
6664             if(e){
6665                 // normalize buttons
6666                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6667                 if(e.type == 'click' && this.button == -1){
6668                     this.button = 0;
6669                 }
6670                 this.type = e.type;
6671                 this.shiftKey = e.shiftKey;
6672                 // mac metaKey behaves like ctrlKey
6673                 this.ctrlKey = e.ctrlKey || e.metaKey;
6674                 this.altKey = e.altKey;
6675                 // in getKey these will be normalized for the mac
6676                 this.keyCode = e.keyCode;
6677                 // keyup warnings on firefox.
6678                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6679                 // cache the target for the delayed and or buffered events
6680                 this.target = E.getTarget(e);
6681                 // same for XY
6682                 this.xy = E.getXY(e);
6683             }else{
6684                 this.button = -1;
6685                 this.shiftKey = false;
6686                 this.ctrlKey = false;
6687                 this.altKey = false;
6688                 this.keyCode = 0;
6689                 this.charCode =0;
6690                 this.target = null;
6691                 this.xy = [0, 0];
6692             }
6693             return this;
6694         },
6695
6696         /**
6697          * Stop the event (preventDefault and stopPropagation)
6698          */
6699         stopEvent : function(){
6700             if(this.browserEvent){
6701                 if(this.browserEvent.type == 'mousedown'){
6702                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6703                 }
6704                 E.stopEvent(this.browserEvent);
6705             }
6706         },
6707
6708         /**
6709          * Prevents the browsers default handling of the event.
6710          */
6711         preventDefault : function(){
6712             if(this.browserEvent){
6713                 E.preventDefault(this.browserEvent);
6714             }
6715         },
6716
6717         /** @private */
6718         isNavKeyPress : function(){
6719             var k = this.keyCode;
6720             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6721             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6722         },
6723
6724         isSpecialKey : function(){
6725             var k = this.keyCode;
6726             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6727             (k == 16) || (k == 17) ||
6728             (k >= 18 && k <= 20) ||
6729             (k >= 33 && k <= 35) ||
6730             (k >= 36 && k <= 39) ||
6731             (k >= 44 && k <= 45);
6732         },
6733         /**
6734          * Cancels bubbling of the event.
6735          */
6736         stopPropagation : function(){
6737             if(this.browserEvent){
6738                 if(this.type == 'mousedown'){
6739                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6740                 }
6741                 E.stopPropagation(this.browserEvent);
6742             }
6743         },
6744
6745         /**
6746          * Gets the key code for the event.
6747          * @return {Number}
6748          */
6749         getCharCode : function(){
6750             return this.charCode || this.keyCode;
6751         },
6752
6753         /**
6754          * Returns a normalized keyCode for the event.
6755          * @return {Number} The key code
6756          */
6757         getKey : function(){
6758             var k = this.keyCode || this.charCode;
6759             return Roo.isSafari ? (safariKeys[k] || k) : k;
6760         },
6761
6762         /**
6763          * Gets the x coordinate of the event.
6764          * @return {Number}
6765          */
6766         getPageX : function(){
6767             return this.xy[0];
6768         },
6769
6770         /**
6771          * Gets the y coordinate of the event.
6772          * @return {Number}
6773          */
6774         getPageY : function(){
6775             return this.xy[1];
6776         },
6777
6778         /**
6779          * Gets the time of the event.
6780          * @return {Number}
6781          */
6782         getTime : function(){
6783             if(this.browserEvent){
6784                 return E.getTime(this.browserEvent);
6785             }
6786             return null;
6787         },
6788
6789         /**
6790          * Gets the page coordinates of the event.
6791          * @return {Array} The xy values like [x, y]
6792          */
6793         getXY : function(){
6794             return this.xy;
6795         },
6796
6797         /**
6798          * Gets the target for the event.
6799          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6800          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6801                 search as a number or element (defaults to 10 || document.body)
6802          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6803          * @return {HTMLelement}
6804          */
6805         getTarget : function(selector, maxDepth, returnEl){
6806             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6807         },
6808         /**
6809          * Gets the related target.
6810          * @return {HTMLElement}
6811          */
6812         getRelatedTarget : function(){
6813             if(this.browserEvent){
6814                 return E.getRelatedTarget(this.browserEvent);
6815             }
6816             return null;
6817         },
6818
6819         /**
6820          * Normalizes mouse wheel delta across browsers
6821          * @return {Number} The delta
6822          */
6823         getWheelDelta : function(){
6824             var e = this.browserEvent;
6825             var delta = 0;
6826             if(e.wheelDelta){ /* IE/Opera. */
6827                 delta = e.wheelDelta/120;
6828             }else if(e.detail){ /* Mozilla case. */
6829                 delta = -e.detail/3;
6830             }
6831             return delta;
6832         },
6833
6834         /**
6835          * Returns true if the control, meta, shift or alt key was pressed during this event.
6836          * @return {Boolean}
6837          */
6838         hasModifier : function(){
6839             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840         },
6841
6842         /**
6843          * Returns true if the target of this event equals el or is a child of el
6844          * @param {String/HTMLElement/Element} el
6845          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6846          * @return {Boolean}
6847          */
6848         within : function(el, related){
6849             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6850             return t && Roo.fly(el).contains(t);
6851         },
6852
6853         getPoint : function(){
6854             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855         }
6856     };
6857
6858     return new Roo.EventObjectImpl();
6859 }();
6860             
6861     /*
6862  * Based on:
6863  * Ext JS Library 1.1.1
6864  * Copyright(c) 2006-2007, Ext JS, LLC.
6865  *
6866  * Originally Released Under LGPL - original licence link has changed is not relivant.
6867  *
6868  * Fork - LGPL
6869  * <script type="text/javascript">
6870  */
6871
6872  
6873 // was in Composite Element!??!?!
6874  
6875 (function(){
6876     var D = Roo.lib.Dom;
6877     var E = Roo.lib.Event;
6878     var A = Roo.lib.Anim;
6879
6880     // local style camelizing for speed
6881     var propCache = {};
6882     var camelRe = /(-[a-z])/gi;
6883     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6884     var view = document.defaultView;
6885
6886 /**
6887  * @class Roo.Element
6888  * Represents an Element in the DOM.<br><br>
6889  * Usage:<br>
6890 <pre><code>
6891 var el = Roo.get("my-div");
6892
6893 // or with getEl
6894 var el = getEl("my-div");
6895
6896 // or with a DOM element
6897 var el = Roo.get(myDivElement);
6898 </code></pre>
6899  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6900  * each call instead of constructing a new one.<br><br>
6901  * <b>Animations</b><br />
6902  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6903  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6904 <pre>
6905 Option    Default   Description
6906 --------- --------  ---------------------------------------------
6907 duration  .35       The duration of the animation in seconds
6908 easing    easeOut   The YUI easing method
6909 callback  none      A function to execute when the anim completes
6910 scope     this      The scope (this) of the callback function
6911 </pre>
6912 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6913 * manipulate the animation. Here's an example:
6914 <pre><code>
6915 var el = Roo.get("my-div");
6916
6917 // no animation
6918 el.setWidth(100);
6919
6920 // default animation
6921 el.setWidth(100, true);
6922
6923 // animation with some options set
6924 el.setWidth(100, {
6925     duration: 1,
6926     callback: this.foo,
6927     scope: this
6928 });
6929
6930 // using the "anim" property to get the Anim object
6931 var opt = {
6932     duration: 1,
6933     callback: this.foo,
6934     scope: this
6935 };
6936 el.setWidth(100, opt);
6937 ...
6938 if(opt.anim.isAnimated()){
6939     opt.anim.stop();
6940 }
6941 </code></pre>
6942 * <b> Composite (Collections of) Elements</b><br />
6943  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6944  * @constructor Create a new Element directly.
6945  * @param {String/HTMLElement} element
6946  * @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).
6947  */
6948     Roo.Element = function(element, forceNew){
6949         var dom = typeof element == "string" ?
6950                 document.getElementById(element) : element;
6951         if(!dom){ // invalid id/element
6952             return null;
6953         }
6954         var id = dom.id;
6955         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6956             return Roo.Element.cache[id];
6957         }
6958
6959         /**
6960          * The DOM element
6961          * @type HTMLElement
6962          */
6963         this.dom = dom;
6964
6965         /**
6966          * The DOM element ID
6967          * @type String
6968          */
6969         this.id = id || Roo.id(dom);
6970     };
6971
6972     var El = Roo.Element;
6973
6974     El.prototype = {
6975         /**
6976          * The element's default display mode  (defaults to "")
6977          * @type String
6978          */
6979         originalDisplay : "",
6980
6981         visibilityMode : 1,
6982         /**
6983          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6984          * @type String
6985          */
6986         defaultUnit : "px",
6987         /**
6988          * Sets the element's visibility mode. When setVisible() is called it
6989          * will use this to determine whether to set the visibility or the display property.
6990          * @param visMode Element.VISIBILITY or Element.DISPLAY
6991          * @return {Roo.Element} this
6992          */
6993         setVisibilityMode : function(visMode){
6994             this.visibilityMode = visMode;
6995             return this;
6996         },
6997         /**
6998          * Convenience method for setVisibilityMode(Element.DISPLAY)
6999          * @param {String} display (optional) What to set display to when visible
7000          * @return {Roo.Element} this
7001          */
7002         enableDisplayMode : function(display){
7003             this.setVisibilityMode(El.DISPLAY);
7004             if(typeof display != "undefined") this.originalDisplay = display;
7005             return this;
7006         },
7007
7008         /**
7009          * 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)
7010          * @param {String} selector The simple selector to test
7011          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7012                 search as a number or element (defaults to 10 || document.body)
7013          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7014          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7015          */
7016         findParent : function(simpleSelector, maxDepth, returnEl){
7017             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7018             maxDepth = maxDepth || 50;
7019             if(typeof maxDepth != "number"){
7020                 stopEl = Roo.getDom(maxDepth);
7021                 maxDepth = 10;
7022             }
7023             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7024                 if(dq.is(p, simpleSelector)){
7025                     return returnEl ? Roo.get(p) : p;
7026                 }
7027                 depth++;
7028                 p = p.parentNode;
7029             }
7030             return null;
7031         },
7032
7033
7034         /**
7035          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7036          * @param {String} selector The simple selector to test
7037          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7038                 search as a number or element (defaults to 10 || document.body)
7039          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7040          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7041          */
7042         findParentNode : function(simpleSelector, maxDepth, returnEl){
7043             var p = Roo.fly(this.dom.parentNode, '_internal');
7044             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045         },
7046
7047         /**
7048          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7049          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7050          * @param {String} selector The simple selector to test
7051          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7052                 search as a number or element (defaults to 10 || document.body)
7053          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7054          */
7055         up : function(simpleSelector, maxDepth){
7056             return this.findParentNode(simpleSelector, maxDepth, true);
7057         },
7058
7059
7060
7061         /**
7062          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7063          * @param {String} selector The simple selector to test
7064          * @return {Boolean} True if this element matches the selector, else false
7065          */
7066         is : function(simpleSelector){
7067             return Roo.DomQuery.is(this.dom, simpleSelector);
7068         },
7069
7070         /**
7071          * Perform animation on this element.
7072          * @param {Object} args The YUI animation control args
7073          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7074          * @param {Function} onComplete (optional) Function to call when animation completes
7075          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7076          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7077          * @return {Roo.Element} this
7078          */
7079         animate : function(args, duration, onComplete, easing, animType){
7080             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7081             return this;
7082         },
7083
7084         /*
7085          * @private Internal animation call
7086          */
7087         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7088             animType = animType || 'run';
7089             opt = opt || {};
7090             var anim = Roo.lib.Anim[animType](
7091                 this.dom, args,
7092                 (opt.duration || defaultDur) || .35,
7093                 (opt.easing || defaultEase) || 'easeOut',
7094                 function(){
7095                     Roo.callback(cb, this);
7096                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7097                 },
7098                 this
7099             );
7100             opt.anim = anim;
7101             return anim;
7102         },
7103
7104         // private legacy anim prep
7105         preanim : function(a, i){
7106             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107         },
7108
7109         /**
7110          * Removes worthless text nodes
7111          * @param {Boolean} forceReclean (optional) By default the element
7112          * keeps track if it has been cleaned already so
7113          * you can call this over and over. However, if you update the element and
7114          * need to force a reclean, you can pass true.
7115          */
7116         clean : function(forceReclean){
7117             if(this.isCleaned && forceReclean !== true){
7118                 return this;
7119             }
7120             var ns = /\S/;
7121             var d = this.dom, n = d.firstChild, ni = -1;
7122             while(n){
7123                 var nx = n.nextSibling;
7124                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7125                     d.removeChild(n);
7126                 }else{
7127                     n.nodeIndex = ++ni;
7128                 }
7129                 n = nx;
7130             }
7131             this.isCleaned = true;
7132             return this;
7133         },
7134
7135         // private
7136         calcOffsetsTo : function(el){
7137             el = Roo.get(el);
7138             var d = el.dom;
7139             var restorePos = false;
7140             if(el.getStyle('position') == 'static'){
7141                 el.position('relative');
7142                 restorePos = true;
7143             }
7144             var x = 0, y =0;
7145             var op = this.dom;
7146             while(op && op != d && op.tagName != 'HTML'){
7147                 x+= op.offsetLeft;
7148                 y+= op.offsetTop;
7149                 op = op.offsetParent;
7150             }
7151             if(restorePos){
7152                 el.position('static');
7153             }
7154             return [x, y];
7155         },
7156
7157         /**
7158          * Scrolls this element into view within the passed container.
7159          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7160          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7161          * @return {Roo.Element} this
7162          */
7163         scrollIntoView : function(container, hscroll){
7164             var c = Roo.getDom(container) || document.body;
7165             var el = this.dom;
7166
7167             var o = this.calcOffsetsTo(c),
7168                 l = o[0],
7169                 t = o[1],
7170                 b = t+el.offsetHeight,
7171                 r = l+el.offsetWidth;
7172
7173             var ch = c.clientHeight;
7174             var ct = parseInt(c.scrollTop, 10);
7175             var cl = parseInt(c.scrollLeft, 10);
7176             var cb = ct + ch;
7177             var cr = cl + c.clientWidth;
7178
7179             if(t < ct){
7180                 c.scrollTop = t;
7181             }else if(b > cb){
7182                 c.scrollTop = b-ch;
7183             }
7184
7185             if(hscroll !== false){
7186                 if(l < cl){
7187                     c.scrollLeft = l;
7188                 }else if(r > cr){
7189                     c.scrollLeft = r-c.clientWidth;
7190                 }
7191             }
7192             return this;
7193         },
7194
7195         // private
7196         scrollChildIntoView : function(child, hscroll){
7197             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198         },
7199
7200         /**
7201          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7202          * the new height may not be available immediately.
7203          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7204          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7205          * @param {Function} onComplete (optional) Function to call when animation completes
7206          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7207          * @return {Roo.Element} this
7208          */
7209         autoHeight : function(animate, duration, onComplete, easing){
7210             var oldHeight = this.getHeight();
7211             this.clip();
7212             this.setHeight(1); // force clipping
7213             setTimeout(function(){
7214                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7215                 if(!animate){
7216                     this.setHeight(height);
7217                     this.unclip();
7218                     if(typeof onComplete == "function"){
7219                         onComplete();
7220                     }
7221                 }else{
7222                     this.setHeight(oldHeight); // restore original height
7223                     this.setHeight(height, animate, duration, function(){
7224                         this.unclip();
7225                         if(typeof onComplete == "function") onComplete();
7226                     }.createDelegate(this), easing);
7227                 }
7228             }.createDelegate(this), 0);
7229             return this;
7230         },
7231
7232         /**
7233          * Returns true if this element is an ancestor of the passed element
7234          * @param {HTMLElement/String} el The element to check
7235          * @return {Boolean} True if this element is an ancestor of el, else false
7236          */
7237         contains : function(el){
7238             if(!el){return false;}
7239             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240         },
7241
7242         /**
7243          * Checks whether the element is currently visible using both visibility and display properties.
7244          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7245          * @return {Boolean} True if the element is currently visible, else false
7246          */
7247         isVisible : function(deep) {
7248             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7249             if(deep !== true || !vis){
7250                 return vis;
7251             }
7252             var p = this.dom.parentNode;
7253             while(p && p.tagName.toLowerCase() != "body"){
7254                 if(!Roo.fly(p, '_isVisible').isVisible()){
7255                     return false;
7256                 }
7257                 p = p.parentNode;
7258             }
7259             return true;
7260         },
7261
7262         /**
7263          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7264          * @param {String} selector The CSS selector
7265          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7266          * @return {CompositeElement/CompositeElementLite} The composite element
7267          */
7268         select : function(selector, unique){
7269             return El.select(selector, unique, this.dom);
7270         },
7271
7272         /**
7273          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7274          * @param {String} selector The CSS selector
7275          * @return {Array} An array of the matched nodes
7276          */
7277         query : function(selector, unique){
7278             return Roo.DomQuery.select(selector, this.dom);
7279         },
7280
7281         /**
7282          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7283          * @param {String} selector The CSS selector
7284          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7285          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7286          */
7287         child : function(selector, returnDom){
7288             var n = Roo.DomQuery.selectNode(selector, this.dom);
7289             return returnDom ? n : Roo.get(n);
7290         },
7291
7292         /**
7293          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7294          * @param {String} selector The CSS selector
7295          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7296          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7297          */
7298         down : function(selector, returnDom){
7299             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7300             return returnDom ? n : Roo.get(n);
7301         },
7302
7303         /**
7304          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7305          * @param {String} group The group the DD object is member of
7306          * @param {Object} config The DD config object
7307          * @param {Object} overrides An object containing methods to override/implement on the DD object
7308          * @return {Roo.dd.DD} The DD object
7309          */
7310         initDD : function(group, config, overrides){
7311             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7312             return Roo.apply(dd, overrides);
7313         },
7314
7315         /**
7316          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7317          * @param {String} group The group the DDProxy object is member of
7318          * @param {Object} config The DDProxy config object
7319          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7320          * @return {Roo.dd.DDProxy} The DDProxy object
7321          */
7322         initDDProxy : function(group, config, overrides){
7323             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7324             return Roo.apply(dd, overrides);
7325         },
7326
7327         /**
7328          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7329          * @param {String} group The group the DDTarget object is member of
7330          * @param {Object} config The DDTarget config object
7331          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7332          * @return {Roo.dd.DDTarget} The DDTarget object
7333          */
7334         initDDTarget : function(group, config, overrides){
7335             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7336             return Roo.apply(dd, overrides);
7337         },
7338
7339         /**
7340          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7341          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7342          * @param {Boolean} visible Whether the element is visible
7343          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7344          * @return {Roo.Element} this
7345          */
7346          setVisible : function(visible, animate){
7347             if(!animate || !A){
7348                 if(this.visibilityMode == El.DISPLAY){
7349                     this.setDisplayed(visible);
7350                 }else{
7351                     this.fixDisplay();
7352                     this.dom.style.visibility = visible ? "visible" : "hidden";
7353                 }
7354             }else{
7355                 // closure for composites
7356                 var dom = this.dom;
7357                 var visMode = this.visibilityMode;
7358                 if(visible){
7359                     this.setOpacity(.01);
7360                     this.setVisible(true);
7361                 }
7362                 this.anim({opacity: { to: (visible?1:0) }},
7363                       this.preanim(arguments, 1),
7364                       null, .35, 'easeIn', function(){
7365                          if(!visible){
7366                              if(visMode == El.DISPLAY){
7367                                  dom.style.display = "none";
7368                              }else{
7369                                  dom.style.visibility = "hidden";
7370                              }
7371                              Roo.get(dom).setOpacity(1);
7372                          }
7373                      });
7374             }
7375             return this;
7376         },
7377
7378         /**
7379          * Returns true if display is not "none"
7380          * @return {Boolean}
7381          */
7382         isDisplayed : function() {
7383             return this.getStyle("display") != "none";
7384         },
7385
7386         /**
7387          * Toggles the element's visibility or display, depending on visibility mode.
7388          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7389          * @return {Roo.Element} this
7390          */
7391         toggle : function(animate){
7392             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7393             return this;
7394         },
7395
7396         /**
7397          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7398          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7399          * @return {Roo.Element} this
7400          */
7401         setDisplayed : function(value) {
7402             if(typeof value == "boolean"){
7403                value = value ? this.originalDisplay : "none";
7404             }
7405             this.setStyle("display", value);
7406             return this;
7407         },
7408
7409         /**
7410          * Tries to focus the element. Any exceptions are caught and ignored.
7411          * @return {Roo.Element} this
7412          */
7413         focus : function() {
7414             try{
7415                 this.dom.focus();
7416             }catch(e){}
7417             return this;
7418         },
7419
7420         /**
7421          * Tries to blur the element. Any exceptions are caught and ignored.
7422          * @return {Roo.Element} this
7423          */
7424         blur : function() {
7425             try{
7426                 this.dom.blur();
7427             }catch(e){}
7428             return this;
7429         },
7430
7431         /**
7432          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7433          * @param {String/Array} className The CSS class to add, or an array of classes
7434          * @return {Roo.Element} this
7435          */
7436         addClass : function(className){
7437             if(className instanceof Array){
7438                 for(var i = 0, len = className.length; i < len; i++) {
7439                     this.addClass(className[i]);
7440                 }
7441             }else{
7442                 if(className && !this.hasClass(className)){
7443                     this.dom.className = this.dom.className + " " + className;
7444                 }
7445             }
7446             return this;
7447         },
7448
7449         /**
7450          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7451          * @param {String/Array} className The CSS class to add, or an array of classes
7452          * @return {Roo.Element} this
7453          */
7454         radioClass : function(className){
7455             var siblings = this.dom.parentNode.childNodes;
7456             for(var i = 0; i < siblings.length; i++) {
7457                 var s = siblings[i];
7458                 if(s.nodeType == 1){
7459                     Roo.get(s).removeClass(className);
7460                 }
7461             }
7462             this.addClass(className);
7463             return this;
7464         },
7465
7466         /**
7467          * Removes one or more CSS classes from the element.
7468          * @param {String/Array} className The CSS class to remove, or an array of classes
7469          * @return {Roo.Element} this
7470          */
7471         removeClass : function(className){
7472             if(!className || !this.dom.className){
7473                 return this;
7474             }
7475             if(className instanceof Array){
7476                 for(var i = 0, len = className.length; i < len; i++) {
7477                     this.removeClass(className[i]);
7478                 }
7479             }else{
7480                 if(this.hasClass(className)){
7481                     var re = this.classReCache[className];
7482                     if (!re) {
7483                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7484                        this.classReCache[className] = re;
7485                     }
7486                     this.dom.className =
7487                         this.dom.className.replace(re, " ");
7488                 }
7489             }
7490             return this;
7491         },
7492
7493         // private
7494         classReCache: {},
7495
7496         /**
7497          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7498          * @param {String} className The CSS class to toggle
7499          * @return {Roo.Element} this
7500          */
7501         toggleClass : function(className){
7502             if(this.hasClass(className)){
7503                 this.removeClass(className);
7504             }else{
7505                 this.addClass(className);
7506             }
7507             return this;
7508         },
7509
7510         /**
7511          * Checks if the specified CSS class exists on this element's DOM node.
7512          * @param {String} className The CSS class to check for
7513          * @return {Boolean} True if the class exists, else false
7514          */
7515         hasClass : function(className){
7516             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517         },
7518
7519         /**
7520          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7521          * @param {String} oldClassName The CSS class to replace
7522          * @param {String} newClassName The replacement CSS class
7523          * @return {Roo.Element} this
7524          */
7525         replaceClass : function(oldClassName, newClassName){
7526             this.removeClass(oldClassName);
7527             this.addClass(newClassName);
7528             return this;
7529         },
7530
7531         /**
7532          * Returns an object with properties matching the styles requested.
7533          * For example, el.getStyles('color', 'font-size', 'width') might return
7534          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7535          * @param {String} style1 A style name
7536          * @param {String} style2 A style name
7537          * @param {String} etc.
7538          * @return {Object} The style object
7539          */
7540         getStyles : function(){
7541             var a = arguments, len = a.length, r = {};
7542             for(var i = 0; i < len; i++){
7543                 r[a[i]] = this.getStyle(a[i]);
7544             }
7545             return r;
7546         },
7547
7548         /**
7549          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7550          * @param {String} property The style property whose value is returned.
7551          * @return {String} The current value of the style property for this element.
7552          */
7553         getStyle : function(){
7554             return view && view.getComputedStyle ?
7555                 function(prop){
7556                     var el = this.dom, v, cs, camel;
7557                     if(prop == 'float'){
7558                         prop = "cssFloat";
7559                     }
7560                     if(el.style && (v = el.style[prop])){
7561                         return v;
7562                     }
7563                     if(cs = view.getComputedStyle(el, "")){
7564                         if(!(camel = propCache[prop])){
7565                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7566                         }
7567                         return cs[camel];
7568                     }
7569                     return null;
7570                 } :
7571                 function(prop){
7572                     var el = this.dom, v, cs, camel;
7573                     if(prop == 'opacity'){
7574                         if(typeof el.style.filter == 'string'){
7575                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7576                             if(m){
7577                                 var fv = parseFloat(m[1]);
7578                                 if(!isNaN(fv)){
7579                                     return fv ? fv / 100 : 0;
7580                                 }
7581                             }
7582                         }
7583                         return 1;
7584                     }else if(prop == 'float'){
7585                         prop = "styleFloat";
7586                     }
7587                     if(!(camel = propCache[prop])){
7588                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7589                     }
7590                     if(v = el.style[camel]){
7591                         return v;
7592                     }
7593                     if(cs = el.currentStyle){
7594                         return cs[camel];
7595                     }
7596                     return null;
7597                 };
7598         }(),
7599
7600         /**
7601          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7602          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7603          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7604          * @return {Roo.Element} this
7605          */
7606         setStyle : function(prop, value){
7607             if(typeof prop == "string"){
7608                 
7609                 if (prop == 'float') {
7610                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7611                     return this;
7612                 }
7613                 
7614                 var camel;
7615                 if(!(camel = propCache[prop])){
7616                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7617                 }
7618                 
7619                 if(camel == 'opacity') {
7620                     this.setOpacity(value);
7621                 }else{
7622                     this.dom.style[camel] = value;
7623                 }
7624             }else{
7625                 for(var style in prop){
7626                     if(typeof prop[style] != "function"){
7627                        this.setStyle(style, prop[style]);
7628                     }
7629                 }
7630             }
7631             return this;
7632         },
7633
7634         /**
7635          * More flexible version of {@link #setStyle} for setting style properties.
7636          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7637          * a function which returns such a specification.
7638          * @return {Roo.Element} this
7639          */
7640         applyStyles : function(style){
7641             Roo.DomHelper.applyStyles(this.dom, style);
7642             return this;
7643         },
7644
7645         /**
7646           * 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).
7647           * @return {Number} The X position of the element
7648           */
7649         getX : function(){
7650             return D.getX(this.dom);
7651         },
7652
7653         /**
7654           * 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).
7655           * @return {Number} The Y position of the element
7656           */
7657         getY : function(){
7658             return D.getY(this.dom);
7659         },
7660
7661         /**
7662           * 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).
7663           * @return {Array} The XY position of the element
7664           */
7665         getXY : function(){
7666             return D.getXY(this.dom);
7667         },
7668
7669         /**
7670          * 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).
7671          * @param {Number} The X position of the element
7672          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7673          * @return {Roo.Element} this
7674          */
7675         setX : function(x, animate){
7676             if(!animate || !A){
7677                 D.setX(this.dom, x);
7678             }else{
7679                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7680             }
7681             return this;
7682         },
7683
7684         /**
7685          * 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).
7686          * @param {Number} The Y position of the element
7687          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7688          * @return {Roo.Element} this
7689          */
7690         setY : function(y, animate){
7691             if(!animate || !A){
7692                 D.setY(this.dom, y);
7693             }else{
7694                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7695             }
7696             return this;
7697         },
7698
7699         /**
7700          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7701          * @param {String} left The left CSS property value
7702          * @return {Roo.Element} this
7703          */
7704         setLeft : function(left){
7705             this.setStyle("left", this.addUnits(left));
7706             return this;
7707         },
7708
7709         /**
7710          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7711          * @param {String} top The top CSS property value
7712          * @return {Roo.Element} this
7713          */
7714         setTop : function(top){
7715             this.setStyle("top", this.addUnits(top));
7716             return this;
7717         },
7718
7719         /**
7720          * Sets the element's CSS right style.
7721          * @param {String} right The right CSS property value
7722          * @return {Roo.Element} this
7723          */
7724         setRight : function(right){
7725             this.setStyle("right", this.addUnits(right));
7726             return this;
7727         },
7728
7729         /**
7730          * Sets the element's CSS bottom style.
7731          * @param {String} bottom The bottom CSS property value
7732          * @return {Roo.Element} this
7733          */
7734         setBottom : function(bottom){
7735             this.setStyle("bottom", this.addUnits(bottom));
7736             return this;
7737         },
7738
7739         /**
7740          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7741          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7742          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7743          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7744          * @return {Roo.Element} this
7745          */
7746         setXY : function(pos, animate){
7747             if(!animate || !A){
7748                 D.setXY(this.dom, pos);
7749             }else{
7750                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7751             }
7752             return this;
7753         },
7754
7755         /**
7756          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7757          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7758          * @param {Number} x X value for new position (coordinates are page-based)
7759          * @param {Number} y Y value for new position (coordinates are page-based)
7760          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7761          * @return {Roo.Element} this
7762          */
7763         setLocation : function(x, y, animate){
7764             this.setXY([x, y], this.preanim(arguments, 2));
7765             return this;
7766         },
7767
7768         /**
7769          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7770          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7771          * @param {Number} x X value for new position (coordinates are page-based)
7772          * @param {Number} y Y value for new position (coordinates are page-based)
7773          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7774          * @return {Roo.Element} this
7775          */
7776         moveTo : function(x, y, animate){
7777             this.setXY([x, y], this.preanim(arguments, 2));
7778             return this;
7779         },
7780
7781         /**
7782          * Returns the region of the given element.
7783          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7784          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7785          */
7786         getRegion : function(){
7787             return D.getRegion(this.dom);
7788         },
7789
7790         /**
7791          * Returns the offset height of the element
7792          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7793          * @return {Number} The element's height
7794          */
7795         getHeight : function(contentHeight){
7796             var h = this.dom.offsetHeight || 0;
7797             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798         },
7799
7800         /**
7801          * Returns the offset width of the element
7802          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7803          * @return {Number} The element's width
7804          */
7805         getWidth : function(contentWidth){
7806             var w = this.dom.offsetWidth || 0;
7807             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808         },
7809
7810         /**
7811          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7812          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7813          * if a height has not been set using CSS.
7814          * @return {Number}
7815          */
7816         getComputedHeight : function(){
7817             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7818             if(!h){
7819                 h = parseInt(this.getStyle('height'), 10) || 0;
7820                 if(!this.isBorderBox()){
7821                     h += this.getFrameWidth('tb');
7822                 }
7823             }
7824             return h;
7825         },
7826
7827         /**
7828          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7829          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7830          * if a width has not been set using CSS.
7831          * @return {Number}
7832          */
7833         getComputedWidth : function(){
7834             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7835             if(!w){
7836                 w = parseInt(this.getStyle('width'), 10) || 0;
7837                 if(!this.isBorderBox()){
7838                     w += this.getFrameWidth('lr');
7839                 }
7840             }
7841             return w;
7842         },
7843
7844         /**
7845          * Returns the size of the element.
7846          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7847          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7848          */
7849         getSize : function(contentSize){
7850             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851         },
7852
7853         /**
7854          * Returns the width and height of the viewport.
7855          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7856          */
7857         getViewSize : function(){
7858             var d = this.dom, doc = document, aw = 0, ah = 0;
7859             if(d == doc || d == doc.body){
7860                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7861             }else{
7862                 return {
7863                     width : d.clientWidth,
7864                     height: d.clientHeight
7865                 };
7866             }
7867         },
7868
7869         /**
7870          * Returns the value of the "value" attribute
7871          * @param {Boolean} asNumber true to parse the value as a number
7872          * @return {String/Number}
7873          */
7874         getValue : function(asNumber){
7875             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876         },
7877
7878         // private
7879         adjustWidth : function(width){
7880             if(typeof width == "number"){
7881                 if(this.autoBoxAdjust && !this.isBorderBox()){
7882                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7883                 }
7884                 if(width < 0){
7885                     width = 0;
7886                 }
7887             }
7888             return width;
7889         },
7890
7891         // private
7892         adjustHeight : function(height){
7893             if(typeof height == "number"){
7894                if(this.autoBoxAdjust && !this.isBorderBox()){
7895                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7896                }
7897                if(height < 0){
7898                    height = 0;
7899                }
7900             }
7901             return height;
7902         },
7903
7904         /**
7905          * Set the width of the element
7906          * @param {Number} width The new width
7907          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7908          * @return {Roo.Element} this
7909          */
7910         setWidth : function(width, animate){
7911             width = this.adjustWidth(width);
7912             if(!animate || !A){
7913                 this.dom.style.width = this.addUnits(width);
7914             }else{
7915                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7916             }
7917             return this;
7918         },
7919
7920         /**
7921          * Set the height of the element
7922          * @param {Number} height The new height
7923          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7924          * @return {Roo.Element} this
7925          */
7926          setHeight : function(height, animate){
7927             height = this.adjustHeight(height);
7928             if(!animate || !A){
7929                 this.dom.style.height = this.addUnits(height);
7930             }else{
7931                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7932             }
7933             return this;
7934         },
7935
7936         /**
7937          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7938          * @param {Number} width The new width
7939          * @param {Number} height The new height
7940          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7941          * @return {Roo.Element} this
7942          */
7943          setSize : function(width, height, animate){
7944             if(typeof width == "object"){ // in case of object from getSize()
7945                 height = width.height; width = width.width;
7946             }
7947             width = this.adjustWidth(width); height = this.adjustHeight(height);
7948             if(!animate || !A){
7949                 this.dom.style.width = this.addUnits(width);
7950                 this.dom.style.height = this.addUnits(height);
7951             }else{
7952                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7953             }
7954             return this;
7955         },
7956
7957         /**
7958          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7959          * @param {Number} x X value for new position (coordinates are page-based)
7960          * @param {Number} y Y value for new position (coordinates are page-based)
7961          * @param {Number} width The new width
7962          * @param {Number} height The new height
7963          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7964          * @return {Roo.Element} this
7965          */
7966         setBounds : function(x, y, width, height, animate){
7967             if(!animate || !A){
7968                 this.setSize(width, height);
7969                 this.setLocation(x, y);
7970             }else{
7971                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7972                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7973                               this.preanim(arguments, 4), 'motion');
7974             }
7975             return this;
7976         },
7977
7978         /**
7979          * 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.
7980          * @param {Roo.lib.Region} region The region to fill
7981          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7982          * @return {Roo.Element} this
7983          */
7984         setRegion : function(region, animate){
7985             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7986             return this;
7987         },
7988
7989         /**
7990          * Appends an event handler
7991          *
7992          * @param {String}   eventName     The type of event to append
7993          * @param {Function} fn        The method the event invokes
7994          * @param {Object} scope       (optional) The scope (this object) of the fn
7995          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7996          */
7997         addListener : function(eventName, fn, scope, options){
7998             if (this.dom) {
7999                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8000             }
8001         },
8002
8003         /**
8004          * Removes an event handler from this element
8005          * @param {String} eventName the type of event to remove
8006          * @param {Function} fn the method the event invokes
8007          * @return {Roo.Element} this
8008          */
8009         removeListener : function(eventName, fn){
8010             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8011             return this;
8012         },
8013
8014         /**
8015          * Removes all previous added listeners from this element
8016          * @return {Roo.Element} this
8017          */
8018         removeAllListeners : function(){
8019             E.purgeElement(this.dom);
8020             return this;
8021         },
8022
8023         relayEvent : function(eventName, observable){
8024             this.on(eventName, function(e){
8025                 observable.fireEvent(eventName, e);
8026             });
8027         },
8028
8029         /**
8030          * Set the opacity of the element
8031          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8032          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8033          * @return {Roo.Element} this
8034          */
8035          setOpacity : function(opacity, animate){
8036             if(!animate || !A){
8037                 var s = this.dom.style;
8038                 if(Roo.isIE){
8039                     s.zoom = 1;
8040                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8041                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8042                 }else{
8043                     s.opacity = opacity;
8044                 }
8045             }else{
8046                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8047             }
8048             return this;
8049         },
8050
8051         /**
8052          * Gets the left X coordinate
8053          * @param {Boolean} local True to get the local css position instead of page coordinate
8054          * @return {Number}
8055          */
8056         getLeft : function(local){
8057             if(!local){
8058                 return this.getX();
8059             }else{
8060                 return parseInt(this.getStyle("left"), 10) || 0;
8061             }
8062         },
8063
8064         /**
8065          * Gets the right X coordinate of the element (element X position + element width)
8066          * @param {Boolean} local True to get the local css position instead of page coordinate
8067          * @return {Number}
8068          */
8069         getRight : function(local){
8070             if(!local){
8071                 return this.getX() + this.getWidth();
8072             }else{
8073                 return (this.getLeft(true) + this.getWidth()) || 0;
8074             }
8075         },
8076
8077         /**
8078          * Gets the top Y coordinate
8079          * @param {Boolean} local True to get the local css position instead of page coordinate
8080          * @return {Number}
8081          */
8082         getTop : function(local) {
8083             if(!local){
8084                 return this.getY();
8085             }else{
8086                 return parseInt(this.getStyle("top"), 10) || 0;
8087             }
8088         },
8089
8090         /**
8091          * Gets the bottom Y coordinate of the element (element Y position + element height)
8092          * @param {Boolean} local True to get the local css position instead of page coordinate
8093          * @return {Number}
8094          */
8095         getBottom : function(local){
8096             if(!local){
8097                 return this.getY() + this.getHeight();
8098             }else{
8099                 return (this.getTop(true) + this.getHeight()) || 0;
8100             }
8101         },
8102
8103         /**
8104         * Initializes positioning on this element. If a desired position is not passed, it will make the
8105         * the element positioned relative IF it is not already positioned.
8106         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8107         * @param {Number} zIndex (optional) The zIndex to apply
8108         * @param {Number} x (optional) Set the page X position
8109         * @param {Number} y (optional) Set the page Y position
8110         */
8111         position : function(pos, zIndex, x, y){
8112             if(!pos){
8113                if(this.getStyle('position') == 'static'){
8114                    this.setStyle('position', 'relative');
8115                }
8116             }else{
8117                 this.setStyle("position", pos);
8118             }
8119             if(zIndex){
8120                 this.setStyle("z-index", zIndex);
8121             }
8122             if(x !== undefined && y !== undefined){
8123                 this.setXY([x, y]);
8124             }else if(x !== undefined){
8125                 this.setX(x);
8126             }else if(y !== undefined){
8127                 this.setY(y);
8128             }
8129         },
8130
8131         /**
8132         * Clear positioning back to the default when the document was loaded
8133         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8134         * @return {Roo.Element} this
8135          */
8136         clearPositioning : function(value){
8137             value = value ||'';
8138             this.setStyle({
8139                 "left": value,
8140                 "right": value,
8141                 "top": value,
8142                 "bottom": value,
8143                 "z-index": "",
8144                 "position" : "static"
8145             });
8146             return this;
8147         },
8148
8149         /**
8150         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8151         * snapshot before performing an update and then restoring the element.
8152         * @return {Object}
8153         */
8154         getPositioning : function(){
8155             var l = this.getStyle("left");
8156             var t = this.getStyle("top");
8157             return {
8158                 "position" : this.getStyle("position"),
8159                 "left" : l,
8160                 "right" : l ? "" : this.getStyle("right"),
8161                 "top" : t,
8162                 "bottom" : t ? "" : this.getStyle("bottom"),
8163                 "z-index" : this.getStyle("z-index")
8164             };
8165         },
8166
8167         /**
8168          * Gets the width of the border(s) for the specified side(s)
8169          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8170          * passing lr would get the border (l)eft width + the border (r)ight width.
8171          * @return {Number} The width of the sides passed added together
8172          */
8173         getBorderWidth : function(side){
8174             return this.addStyles(side, El.borders);
8175         },
8176
8177         /**
8178          * Gets the width of the padding(s) for the specified side(s)
8179          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8180          * passing lr would get the padding (l)eft + the padding (r)ight.
8181          * @return {Number} The padding of the sides passed added together
8182          */
8183         getPadding : function(side){
8184             return this.addStyles(side, El.paddings);
8185         },
8186
8187         /**
8188         * Set positioning with an object returned by getPositioning().
8189         * @param {Object} posCfg
8190         * @return {Roo.Element} this
8191          */
8192         setPositioning : function(pc){
8193             this.applyStyles(pc);
8194             if(pc.right == "auto"){
8195                 this.dom.style.right = "";
8196             }
8197             if(pc.bottom == "auto"){
8198                 this.dom.style.bottom = "";
8199             }
8200             return this;
8201         },
8202
8203         // private
8204         fixDisplay : function(){
8205             if(this.getStyle("display") == "none"){
8206                 this.setStyle("visibility", "hidden");
8207                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8208                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8209                     this.setStyle("display", "block");
8210                 }
8211             }
8212         },
8213
8214         /**
8215          * Quick set left and top adding default units
8216          * @param {String} left The left CSS property value
8217          * @param {String} top The top CSS property value
8218          * @return {Roo.Element} this
8219          */
8220          setLeftTop : function(left, top){
8221             this.dom.style.left = this.addUnits(left);
8222             this.dom.style.top = this.addUnits(top);
8223             return this;
8224         },
8225
8226         /**
8227          * Move this element relative to its current position.
8228          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8229          * @param {Number} distance How far to move the element in pixels
8230          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8231          * @return {Roo.Element} this
8232          */
8233          move : function(direction, distance, animate){
8234             var xy = this.getXY();
8235             direction = direction.toLowerCase();
8236             switch(direction){
8237                 case "l":
8238                 case "left":
8239                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240                     break;
8241                case "r":
8242                case "right":
8243                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8244                     break;
8245                case "t":
8246                case "top":
8247                case "up":
8248                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8249                     break;
8250                case "b":
8251                case "bottom":
8252                case "down":
8253                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8254                     break;
8255             }
8256             return this;
8257         },
8258
8259         /**
8260          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8261          * @return {Roo.Element} this
8262          */
8263         clip : function(){
8264             if(!this.isClipped){
8265                this.isClipped = true;
8266                this.originalClip = {
8267                    "o": this.getStyle("overflow"),
8268                    "x": this.getStyle("overflow-x"),
8269                    "y": this.getStyle("overflow-y")
8270                };
8271                this.setStyle("overflow", "hidden");
8272                this.setStyle("overflow-x", "hidden");
8273                this.setStyle("overflow-y", "hidden");
8274             }
8275             return this;
8276         },
8277
8278         /**
8279          *  Return clipping (overflow) to original clipping before clip() was called
8280          * @return {Roo.Element} this
8281          */
8282         unclip : function(){
8283             if(this.isClipped){
8284                 this.isClipped = false;
8285                 var o = this.originalClip;
8286                 if(o.o){this.setStyle("overflow", o.o);}
8287                 if(o.x){this.setStyle("overflow-x", o.x);}
8288                 if(o.y){this.setStyle("overflow-y", o.y);}
8289             }
8290             return this;
8291         },
8292
8293
8294         /**
8295          * Gets the x,y coordinates specified by the anchor position on the element.
8296          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8297          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8298          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8299          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8300          * @return {Array} [x, y] An array containing the element's x and y coordinates
8301          */
8302         getAnchorXY : function(anchor, local, s){
8303             //Passing a different size is useful for pre-calculating anchors,
8304             //especially for anchored animations that change the el size.
8305
8306             var w, h, vp = false;
8307             if(!s){
8308                 var d = this.dom;
8309                 if(d == document.body || d == document){
8310                     vp = true;
8311                     w = D.getViewWidth(); h = D.getViewHeight();
8312                 }else{
8313                     w = this.getWidth(); h = this.getHeight();
8314                 }
8315             }else{
8316                 w = s.width;  h = s.height;
8317             }
8318             var x = 0, y = 0, r = Math.round;
8319             switch((anchor || "tl").toLowerCase()){
8320                 case "c":
8321                     x = r(w*.5);
8322                     y = r(h*.5);
8323                 break;
8324                 case "t":
8325                     x = r(w*.5);
8326                     y = 0;
8327                 break;
8328                 case "l":
8329                     x = 0;
8330                     y = r(h*.5);
8331                 break;
8332                 case "r":
8333                     x = w;
8334                     y = r(h*.5);
8335                 break;
8336                 case "b":
8337                     x = r(w*.5);
8338                     y = h;
8339                 break;
8340                 case "tl":
8341                     x = 0;
8342                     y = 0;
8343                 break;
8344                 case "bl":
8345                     x = 0;
8346                     y = h;
8347                 break;
8348                 case "br":
8349                     x = w;
8350                     y = h;
8351                 break;
8352                 case "tr":
8353                     x = w;
8354                     y = 0;
8355                 break;
8356             }
8357             if(local === true){
8358                 return [x, y];
8359             }
8360             if(vp){
8361                 var sc = this.getScroll();
8362                 return [x + sc.left, y + sc.top];
8363             }
8364             //Add the element's offset xy
8365             var o = this.getXY();
8366             return [x+o[0], y+o[1]];
8367         },
8368
8369         /**
8370          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8371          * supported position values.
8372          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8373          * @param {String} position The position to align to.
8374          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8375          * @return {Array} [x, y]
8376          */
8377         getAlignToXY : function(el, p, o){
8378             el = Roo.get(el);
8379             var d = this.dom;
8380             if(!el.dom){
8381                 throw "Element.alignTo with an element that doesn't exist";
8382             }
8383             var c = false; //constrain to viewport
8384             var p1 = "", p2 = "";
8385             o = o || [0,0];
8386
8387             if(!p){
8388                 p = "tl-bl";
8389             }else if(p == "?"){
8390                 p = "tl-bl?";
8391             }else if(p.indexOf("-") == -1){
8392                 p = "tl-" + p;
8393             }
8394             p = p.toLowerCase();
8395             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8396             if(!m){
8397                throw "Element.alignTo with an invalid alignment " + p;
8398             }
8399             p1 = m[1]; p2 = m[2]; c = !!m[3];
8400
8401             //Subtract the aligned el's internal xy from the target's offset xy
8402             //plus custom offset to get the aligned el's new offset xy
8403             var a1 = this.getAnchorXY(p1, true);
8404             var a2 = el.getAnchorXY(p2, false);
8405             var x = a2[0] - a1[0] + o[0];
8406             var y = a2[1] - a1[1] + o[1];
8407             if(c){
8408                 //constrain the aligned el to viewport if necessary
8409                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8410                 // 5px of margin for ie
8411                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8412
8413                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8414                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8415                 //otherwise swap the aligned el to the opposite border of the target.
8416                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8417                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8418                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8419                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8420
8421                var doc = document;
8422                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8423                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8424
8425                if((x+w) > dw + scrollX){
8426                     x = swapX ? r.left-w : dw+scrollX-w;
8427                 }
8428                if(x < scrollX){
8429                    x = swapX ? r.right : scrollX;
8430                }
8431                if((y+h) > dh + scrollY){
8432                     y = swapY ? r.top-h : dh+scrollY-h;
8433                 }
8434                if (y < scrollY){
8435                    y = swapY ? r.bottom : scrollY;
8436                }
8437             }
8438             return [x,y];
8439         },
8440
8441         // private
8442         getConstrainToXY : function(){
8443             var os = {top:0, left:0, bottom:0, right: 0};
8444
8445             return function(el, local, offsets, proposedXY){
8446                 el = Roo.get(el);
8447                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8448
8449                 var vw, vh, vx = 0, vy = 0;
8450                 if(el.dom == document.body || el.dom == document){
8451                     vw = Roo.lib.Dom.getViewWidth();
8452                     vh = Roo.lib.Dom.getViewHeight();
8453                 }else{
8454                     vw = el.dom.clientWidth;
8455                     vh = el.dom.clientHeight;
8456                     if(!local){
8457                         var vxy = el.getXY();
8458                         vx = vxy[0];
8459                         vy = vxy[1];
8460                     }
8461                 }
8462
8463                 var s = el.getScroll();
8464
8465                 vx += offsets.left + s.left;
8466                 vy += offsets.top + s.top;
8467
8468                 vw -= offsets.right;
8469                 vh -= offsets.bottom;
8470
8471                 var vr = vx+vw;
8472                 var vb = vy+vh;
8473
8474                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8475                 var x = xy[0], y = xy[1];
8476                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8477
8478                 // only move it if it needs it
8479                 var moved = false;
8480
8481                 // first validate right/bottom
8482                 if((x + w) > vr){
8483                     x = vr - w;
8484                     moved = true;
8485                 }
8486                 if((y + h) > vb){
8487                     y = vb - h;
8488                     moved = true;
8489                 }
8490                 // then make sure top/left isn't negative
8491                 if(x < vx){
8492                     x = vx;
8493                     moved = true;
8494                 }
8495                 if(y < vy){
8496                     y = vy;
8497                     moved = true;
8498                 }
8499                 return moved ? [x, y] : false;
8500             };
8501         }(),
8502
8503         // private
8504         adjustForConstraints : function(xy, parent, offsets){
8505             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8506         },
8507
8508         /**
8509          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8510          * document it aligns it to the viewport.
8511          * The position parameter is optional, and can be specified in any one of the following formats:
8512          * <ul>
8513          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8514          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8515          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8516          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8517          *   <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
8518          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8519          * </ul>
8520          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8521          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8522          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8523          * that specified in order to enforce the viewport constraints.
8524          * Following are all of the supported anchor positions:
8525     <pre>
8526     Value  Description
8527     -----  -----------------------------
8528     tl     The top left corner (default)
8529     t      The center of the top edge
8530     tr     The top right corner
8531     l      The center of the left edge
8532     c      In the center of the element
8533     r      The center of the right edge
8534     bl     The bottom left corner
8535     b      The center of the bottom edge
8536     br     The bottom right corner
8537     </pre>
8538     Example Usage:
8539     <pre><code>
8540     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8541     el.alignTo("other-el");
8542
8543     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8544     el.alignTo("other-el", "tr?");
8545
8546     // align the bottom right corner of el with the center left edge of other-el
8547     el.alignTo("other-el", "br-l?");
8548
8549     // align the center of el with the bottom left corner of other-el and
8550     // adjust the x position by -6 pixels (and the y position by 0)
8551     el.alignTo("other-el", "c-bl", [-6, 0]);
8552     </code></pre>
8553          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8554          * @param {String} position The position to align to.
8555          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8556          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8557          * @return {Roo.Element} this
8558          */
8559         alignTo : function(element, position, offsets, animate){
8560             var xy = this.getAlignToXY(element, position, offsets);
8561             this.setXY(xy, this.preanim(arguments, 3));
8562             return this;
8563         },
8564
8565         /**
8566          * Anchors an element to another element and realigns it when the window is resized.
8567          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8568          * @param {String} position The position to align to.
8569          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8570          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8571          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8572          * is a number, it is used as the buffer delay (defaults to 50ms).
8573          * @param {Function} callback The function to call after the animation finishes
8574          * @return {Roo.Element} this
8575          */
8576         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8577             var action = function(){
8578                 this.alignTo(el, alignment, offsets, animate);
8579                 Roo.callback(callback, this);
8580             };
8581             Roo.EventManager.onWindowResize(action, this);
8582             var tm = typeof monitorScroll;
8583             if(tm != 'undefined'){
8584                 Roo.EventManager.on(window, 'scroll', action, this,
8585                     {buffer: tm == 'number' ? monitorScroll : 50});
8586             }
8587             action.call(this); // align immediately
8588             return this;
8589         },
8590         /**
8591          * Clears any opacity settings from this element. Required in some cases for IE.
8592          * @return {Roo.Element} this
8593          */
8594         clearOpacity : function(){
8595             if (window.ActiveXObject) {
8596                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8597                     this.dom.style.filter = "";
8598                 }
8599             } else {
8600                 this.dom.style.opacity = "";
8601                 this.dom.style["-moz-opacity"] = "";
8602                 this.dom.style["-khtml-opacity"] = "";
8603             }
8604             return this;
8605         },
8606
8607         /**
8608          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8609          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8610          * @return {Roo.Element} this
8611          */
8612         hide : function(animate){
8613             this.setVisible(false, this.preanim(arguments, 0));
8614             return this;
8615         },
8616
8617         /**
8618         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8619         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8620          * @return {Roo.Element} this
8621          */
8622         show : function(animate){
8623             this.setVisible(true, this.preanim(arguments, 0));
8624             return this;
8625         },
8626
8627         /**
8628          * @private Test if size has a unit, otherwise appends the default
8629          */
8630         addUnits : function(size){
8631             return Roo.Element.addUnits(size, this.defaultUnit);
8632         },
8633
8634         /**
8635          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8636          * @return {Roo.Element} this
8637          */
8638         beginMeasure : function(){
8639             var el = this.dom;
8640             if(el.offsetWidth || el.offsetHeight){
8641                 return this; // offsets work already
8642             }
8643             var changed = [];
8644             var p = this.dom, b = document.body; // start with this element
8645             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8646                 var pe = Roo.get(p);
8647                 if(pe.getStyle('display') == 'none'){
8648                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8649                     p.style.visibility = "hidden";
8650                     p.style.display = "block";
8651                 }
8652                 p = p.parentNode;
8653             }
8654             this._measureChanged = changed;
8655             return this;
8656
8657         },
8658
8659         /**
8660          * Restores displays to before beginMeasure was called
8661          * @return {Roo.Element} this
8662          */
8663         endMeasure : function(){
8664             var changed = this._measureChanged;
8665             if(changed){
8666                 for(var i = 0, len = changed.length; i < len; i++) {
8667                     var r = changed[i];
8668                     r.el.style.visibility = r.visibility;
8669                     r.el.style.display = "none";
8670                 }
8671                 this._measureChanged = null;
8672             }
8673             return this;
8674         },
8675
8676         /**
8677         * Update the innerHTML of this element, optionally searching for and processing scripts
8678         * @param {String} html The new HTML
8679         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8680         * @param {Function} callback For async script loading you can be noticed when the update completes
8681         * @return {Roo.Element} this
8682          */
8683         update : function(html, loadScripts, callback){
8684             if(typeof html == "undefined"){
8685                 html = "";
8686             }
8687             if(loadScripts !== true){
8688                 this.dom.innerHTML = html;
8689                 if(typeof callback == "function"){
8690                     callback();
8691                 }
8692                 return this;
8693             }
8694             var id = Roo.id();
8695             var dom = this.dom;
8696
8697             html += '<span id="' + id + '"></span>';
8698
8699             E.onAvailable(id, function(){
8700                 var hd = document.getElementsByTagName("head")[0];
8701                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8702                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8703                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8704
8705                 var match;
8706                 while(match = re.exec(html)){
8707                     var attrs = match[1];
8708                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8709                     if(srcMatch && srcMatch[2]){
8710                        var s = document.createElement("script");
8711                        s.src = srcMatch[2];
8712                        var typeMatch = attrs.match(typeRe);
8713                        if(typeMatch && typeMatch[2]){
8714                            s.type = typeMatch[2];
8715                        }
8716                        hd.appendChild(s);
8717                     }else if(match[2] && match[2].length > 0){
8718                         if(window.execScript) {
8719                            window.execScript(match[2]);
8720                         } else {
8721                             /**
8722                              * eval:var:id
8723                              * eval:var:dom
8724                              * eval:var:html
8725                              * 
8726                              */
8727                            window.eval(match[2]);
8728                         }
8729                     }
8730                 }
8731                 var el = document.getElementById(id);
8732                 if(el){el.parentNode.removeChild(el);}
8733                 if(typeof callback == "function"){
8734                     callback();
8735                 }
8736             });
8737             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8738             return this;
8739         },
8740
8741         /**
8742          * Direct access to the UpdateManager update() method (takes the same parameters).
8743          * @param {String/Function} url The url for this request or a function to call to get the url
8744          * @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}
8745          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8746          * @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.
8747          * @return {Roo.Element} this
8748          */
8749         load : function(){
8750             var um = this.getUpdateManager();
8751             um.update.apply(um, arguments);
8752             return this;
8753         },
8754
8755         /**
8756         * Gets this element's UpdateManager
8757         * @return {Roo.UpdateManager} The UpdateManager
8758         */
8759         getUpdateManager : function(){
8760             if(!this.updateManager){
8761                 this.updateManager = new Roo.UpdateManager(this);
8762             }
8763             return this.updateManager;
8764         },
8765
8766         /**
8767          * Disables text selection for this element (normalized across browsers)
8768          * @return {Roo.Element} this
8769          */
8770         unselectable : function(){
8771             this.dom.unselectable = "on";
8772             this.swallowEvent("selectstart", true);
8773             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8774             this.addClass("x-unselectable");
8775             return this;
8776         },
8777
8778         /**
8779         * Calculates the x, y to center this element on the screen
8780         * @return {Array} The x, y values [x, y]
8781         */
8782         getCenterXY : function(){
8783             return this.getAlignToXY(document, 'c-c');
8784         },
8785
8786         /**
8787         * Centers the Element in either the viewport, or another Element.
8788         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8789         */
8790         center : function(centerIn){
8791             this.alignTo(centerIn || document, 'c-c');
8792             return this;
8793         },
8794
8795         /**
8796          * Tests various css rules/browsers to determine if this element uses a border box
8797          * @return {Boolean}
8798          */
8799         isBorderBox : function(){
8800             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801         },
8802
8803         /**
8804          * Return a box {x, y, width, height} that can be used to set another elements
8805          * size/location to match this element.
8806          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8807          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8808          * @return {Object} box An object in the format {x, y, width, height}
8809          */
8810         getBox : function(contentBox, local){
8811             var xy;
8812             if(!local){
8813                 xy = this.getXY();
8814             }else{
8815                 var left = parseInt(this.getStyle("left"), 10) || 0;
8816                 var top = parseInt(this.getStyle("top"), 10) || 0;
8817                 xy = [left, top];
8818             }
8819             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8820             if(!contentBox){
8821                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8822             }else{
8823                 var l = this.getBorderWidth("l")+this.getPadding("l");
8824                 var r = this.getBorderWidth("r")+this.getPadding("r");
8825                 var t = this.getBorderWidth("t")+this.getPadding("t");
8826                 var b = this.getBorderWidth("b")+this.getPadding("b");
8827                 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)};
8828             }
8829             bx.right = bx.x + bx.width;
8830             bx.bottom = bx.y + bx.height;
8831             return bx;
8832         },
8833
8834         /**
8835          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8836          for more information about the sides.
8837          * @param {String} sides
8838          * @return {Number}
8839          */
8840         getFrameWidth : function(sides, onlyContentBox){
8841             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842         },
8843
8844         /**
8845          * 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.
8846          * @param {Object} box The box to fill {x, y, width, height}
8847          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8848          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8849          * @return {Roo.Element} this
8850          */
8851         setBox : function(box, adjust, animate){
8852             var w = box.width, h = box.height;
8853             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8854                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8855                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8856             }
8857             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8858             return this;
8859         },
8860
8861         /**
8862          * Forces the browser to repaint this element
8863          * @return {Roo.Element} this
8864          */
8865          repaint : function(){
8866             var dom = this.dom;
8867             this.addClass("x-repaint");
8868             setTimeout(function(){
8869                 Roo.get(dom).removeClass("x-repaint");
8870             }, 1);
8871             return this;
8872         },
8873
8874         /**
8875          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8876          * then it returns the calculated width of the sides (see getPadding)
8877          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8878          * @return {Object/Number}
8879          */
8880         getMargins : function(side){
8881             if(!side){
8882                 return {
8883                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8884                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8885                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8886                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8887                 };
8888             }else{
8889                 return this.addStyles(side, El.margins);
8890              }
8891         },
8892
8893         // private
8894         addStyles : function(sides, styles){
8895             var val = 0, v, w;
8896             for(var i = 0, len = sides.length; i < len; i++){
8897                 v = this.getStyle(styles[sides.charAt(i)]);
8898                 if(v){
8899                      w = parseInt(v, 10);
8900                      if(w){ val += w; }
8901                 }
8902             }
8903             return val;
8904         },
8905
8906         /**
8907          * Creates a proxy element of this element
8908          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8909          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8910          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8911          * @return {Roo.Element} The new proxy element
8912          */
8913         createProxy : function(config, renderTo, matchBox){
8914             if(renderTo){
8915                 renderTo = Roo.getDom(renderTo);
8916             }else{
8917                 renderTo = document.body;
8918             }
8919             config = typeof config == "object" ?
8920                 config : {tag : "div", cls: config};
8921             var proxy = Roo.DomHelper.append(renderTo, config, true);
8922             if(matchBox){
8923                proxy.setBox(this.getBox());
8924             }
8925             return proxy;
8926         },
8927
8928         /**
8929          * Puts a mask over this element to disable user interaction. Requires core.css.
8930          * This method can only be applied to elements which accept child nodes.
8931          * @param {String} msg (optional) A message to display in the mask
8932          * @param {String} msgCls (optional) A css class to apply to the msg element
8933          * @return {Element} The mask  element
8934          */
8935         mask : function(msg, msgCls)
8936         {
8937             if(this.getStyle("position") == "static"){
8938                 this.setStyle("position", "relative");
8939             }
8940             if(!this._mask){
8941                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8942             }
8943             this.addClass("x-masked");
8944             this._mask.setDisplayed(true);
8945             
8946             // we wander
8947             var z = 0;
8948             var dom = this.dom
8949             while (dom && dom.style) {
8950                 if (!isNaN(parseInt(dom.style.zIndex))) {
8951                     z = Math.max(z, parseInt(dom.style.zIndex));
8952                 }
8953                 dom = dom.parentNode;
8954             }
8955             // if we are masking the body - then it hides everything..
8956             if (this.dom == document.body) {
8957                 z = 1000000;
8958                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8959                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8960             }
8961            
8962             if(typeof msg == 'string'){
8963                 if(!this._maskMsg){
8964                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8965                 }
8966                 var mm = this._maskMsg;
8967                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8968                 mm.dom.firstChild.innerHTML = msg;
8969                 mm.setDisplayed(true);
8970                 mm.center(this);
8971                 mm.setStyle('z-index', z + 102);
8972             }
8973             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8974                 this._mask.setHeight(this.getHeight());
8975             }
8976             this._mask.setStyle('z-index', z + 100);
8977             
8978             return this._mask;
8979         },
8980
8981         /**
8982          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8983          * it is cached for reuse.
8984          */
8985         unmask : function(removeEl){
8986             if(this._mask){
8987                 if(removeEl === true){
8988                     this._mask.remove();
8989                     delete this._mask;
8990                     if(this._maskMsg){
8991                         this._maskMsg.remove();
8992                         delete this._maskMsg;
8993                     }
8994                 }else{
8995                     this._mask.setDisplayed(false);
8996                     if(this._maskMsg){
8997                         this._maskMsg.setDisplayed(false);
8998                     }
8999                 }
9000             }
9001             this.removeClass("x-masked");
9002         },
9003
9004         /**
9005          * Returns true if this element is masked
9006          * @return {Boolean}
9007          */
9008         isMasked : function(){
9009             return this._mask && this._mask.isVisible();
9010         },
9011
9012         /**
9013          * Creates an iframe shim for this element to keep selects and other windowed objects from
9014          * showing through.
9015          * @return {Roo.Element} The new shim element
9016          */
9017         createShim : function(){
9018             var el = document.createElement('iframe');
9019             el.frameBorder = 'no';
9020             el.className = 'roo-shim';
9021             if(Roo.isIE && Roo.isSecure){
9022                 el.src = Roo.SSL_SECURE_URL;
9023             }
9024             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9025             shim.autoBoxAdjust = false;
9026             return shim;
9027         },
9028
9029         /**
9030          * Removes this element from the DOM and deletes it from the cache
9031          */
9032         remove : function(){
9033             if(this.dom.parentNode){
9034                 this.dom.parentNode.removeChild(this.dom);
9035             }
9036             delete El.cache[this.dom.id];
9037         },
9038
9039         /**
9040          * Sets up event handlers to add and remove a css class when the mouse is over this element
9041          * @param {String} className
9042          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9043          * mouseout events for children elements
9044          * @return {Roo.Element} this
9045          */
9046         addClassOnOver : function(className, preventFlicker){
9047             this.on("mouseover", function(){
9048                 Roo.fly(this, '_internal').addClass(className);
9049             }, this.dom);
9050             var removeFn = function(e){
9051                 if(preventFlicker !== true || !e.within(this, true)){
9052                     Roo.fly(this, '_internal').removeClass(className);
9053                 }
9054             };
9055             this.on("mouseout", removeFn, this.dom);
9056             return this;
9057         },
9058
9059         /**
9060          * Sets up event handlers to add and remove a css class when this element has the focus
9061          * @param {String} className
9062          * @return {Roo.Element} this
9063          */
9064         addClassOnFocus : function(className){
9065             this.on("focus", function(){
9066                 Roo.fly(this, '_internal').addClass(className);
9067             }, this.dom);
9068             this.on("blur", function(){
9069                 Roo.fly(this, '_internal').removeClass(className);
9070             }, this.dom);
9071             return this;
9072         },
9073         /**
9074          * 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)
9075          * @param {String} className
9076          * @return {Roo.Element} this
9077          */
9078         addClassOnClick : function(className){
9079             var dom = this.dom;
9080             this.on("mousedown", function(){
9081                 Roo.fly(dom, '_internal').addClass(className);
9082                 var d = Roo.get(document);
9083                 var fn = function(){
9084                     Roo.fly(dom, '_internal').removeClass(className);
9085                     d.removeListener("mouseup", fn);
9086                 };
9087                 d.on("mouseup", fn);
9088             });
9089             return this;
9090         },
9091
9092         /**
9093          * Stops the specified event from bubbling and optionally prevents the default action
9094          * @param {String} eventName
9095          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9096          * @return {Roo.Element} this
9097          */
9098         swallowEvent : function(eventName, preventDefault){
9099             var fn = function(e){
9100                 e.stopPropagation();
9101                 if(preventDefault){
9102                     e.preventDefault();
9103                 }
9104             };
9105             if(eventName instanceof Array){
9106                 for(var i = 0, len = eventName.length; i < len; i++){
9107                      this.on(eventName[i], fn);
9108                 }
9109                 return this;
9110             }
9111             this.on(eventName, fn);
9112             return this;
9113         },
9114
9115         /**
9116          * @private
9117          */
9118       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9119
9120         /**
9121          * Sizes this element to its parent element's dimensions performing
9122          * neccessary box adjustments.
9123          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9124          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9125          * @return {Roo.Element} this
9126          */
9127         fitToParent : function(monitorResize, targetParent) {
9128           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9129           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9130           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9131             return;
9132           }
9133           var p = Roo.get(targetParent || this.dom.parentNode);
9134           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9135           if (monitorResize === true) {
9136             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9137             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9138           }
9139           return this;
9140         },
9141
9142         /**
9143          * Gets the next sibling, skipping text nodes
9144          * @return {HTMLElement} The next sibling or null
9145          */
9146         getNextSibling : function(){
9147             var n = this.dom.nextSibling;
9148             while(n && n.nodeType != 1){
9149                 n = n.nextSibling;
9150             }
9151             return n;
9152         },
9153
9154         /**
9155          * Gets the previous sibling, skipping text nodes
9156          * @return {HTMLElement} The previous sibling or null
9157          */
9158         getPrevSibling : function(){
9159             var n = this.dom.previousSibling;
9160             while(n && n.nodeType != 1){
9161                 n = n.previousSibling;
9162             }
9163             return n;
9164         },
9165
9166
9167         /**
9168          * Appends the passed element(s) to this element
9169          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9170          * @return {Roo.Element} this
9171          */
9172         appendChild: function(el){
9173             el = Roo.get(el);
9174             el.appendTo(this);
9175             return this;
9176         },
9177
9178         /**
9179          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9180          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9181          * automatically generated with the specified attributes.
9182          * @param {HTMLElement} insertBefore (optional) a child element of this element
9183          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9184          * @return {Roo.Element} The new child element
9185          */
9186         createChild: function(config, insertBefore, returnDom){
9187             config = config || {tag:'div'};
9188             if(insertBefore){
9189                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9190             }
9191             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9192         },
9193
9194         /**
9195          * Appends this element to the passed element
9196          * @param {String/HTMLElement/Element} el The new parent element
9197          * @return {Roo.Element} this
9198          */
9199         appendTo: function(el){
9200             el = Roo.getDom(el);
9201             el.appendChild(this.dom);
9202             return this;
9203         },
9204
9205         /**
9206          * Inserts this element before the passed element in the DOM
9207          * @param {String/HTMLElement/Element} el The element to insert before
9208          * @return {Roo.Element} this
9209          */
9210         insertBefore: function(el){
9211             el = Roo.getDom(el);
9212             el.parentNode.insertBefore(this.dom, el);
9213             return this;
9214         },
9215
9216         /**
9217          * Inserts this element after the passed element in the DOM
9218          * @param {String/HTMLElement/Element} el The element to insert after
9219          * @return {Roo.Element} this
9220          */
9221         insertAfter: function(el){
9222             el = Roo.getDom(el);
9223             el.parentNode.insertBefore(this.dom, el.nextSibling);
9224             return this;
9225         },
9226
9227         /**
9228          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9229          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9230          * @return {Roo.Element} The new child
9231          */
9232         insertFirst: function(el, returnDom){
9233             el = el || {};
9234             if(typeof el == 'object' && !el.nodeType){ // dh config
9235                 return this.createChild(el, this.dom.firstChild, returnDom);
9236             }else{
9237                 el = Roo.getDom(el);
9238                 this.dom.insertBefore(el, this.dom.firstChild);
9239                 return !returnDom ? Roo.get(el) : el;
9240             }
9241         },
9242
9243         /**
9244          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9245          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9246          * @param {String} where (optional) 'before' or 'after' defaults to before
9247          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9248          * @return {Roo.Element} the inserted Element
9249          */
9250         insertSibling: function(el, where, returnDom){
9251             where = where ? where.toLowerCase() : 'before';
9252             el = el || {};
9253             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9254
9255             if(typeof el == 'object' && !el.nodeType){ // dh config
9256                 if(where == 'after' && !this.dom.nextSibling){
9257                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9258                 }else{
9259                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260                 }
9261
9262             }else{
9263                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9264                             where == 'before' ? this.dom : this.dom.nextSibling);
9265                 if(!returnDom){
9266                     rt = Roo.get(rt);
9267                 }
9268             }
9269             return rt;
9270         },
9271
9272         /**
9273          * Creates and wraps this element with another element
9274          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9275          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9276          * @return {HTMLElement/Element} The newly created wrapper element
9277          */
9278         wrap: function(config, returnDom){
9279             if(!config){
9280                 config = {tag: "div"};
9281             }
9282             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9283             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9284             return newEl;
9285         },
9286
9287         /**
9288          * Replaces the passed element with this element
9289          * @param {String/HTMLElement/Element} el The element to replace
9290          * @return {Roo.Element} this
9291          */
9292         replace: function(el){
9293             el = Roo.get(el);
9294             this.insertBefore(el);
9295             el.remove();
9296             return this;
9297         },
9298
9299         /**
9300          * Inserts an html fragment into this element
9301          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9302          * @param {String} html The HTML fragment
9303          * @param {Boolean} returnEl True to return an Roo.Element
9304          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9305          */
9306         insertHtml : function(where, html, returnEl){
9307             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9308             return returnEl ? Roo.get(el) : el;
9309         },
9310
9311         /**
9312          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9313          * @param {Object} o The object with the attributes
9314          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9315          * @return {Roo.Element} this
9316          */
9317         set : function(o, useSet){
9318             var el = this.dom;
9319             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9320             for(var attr in o){
9321                 if(attr == "style" || typeof o[attr] == "function") continue;
9322                 if(attr=="cls"){
9323                     el.className = o["cls"];
9324                 }else{
9325                     if(useSet) el.setAttribute(attr, o[attr]);
9326                     else el[attr] = o[attr];
9327                 }
9328             }
9329             if(o.style){
9330                 Roo.DomHelper.applyStyles(el, o.style);
9331             }
9332             return this;
9333         },
9334
9335         /**
9336          * Convenience method for constructing a KeyMap
9337          * @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:
9338          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9339          * @param {Function} fn The function to call
9340          * @param {Object} scope (optional) The scope of the function
9341          * @return {Roo.KeyMap} The KeyMap created
9342          */
9343         addKeyListener : function(key, fn, scope){
9344             var config;
9345             if(typeof key != "object" || key instanceof Array){
9346                 config = {
9347                     key: key,
9348                     fn: fn,
9349                     scope: scope
9350                 };
9351             }else{
9352                 config = {
9353                     key : key.key,
9354                     shift : key.shift,
9355                     ctrl : key.ctrl,
9356                     alt : key.alt,
9357                     fn: fn,
9358                     scope: scope
9359                 };
9360             }
9361             return new Roo.KeyMap(this, config);
9362         },
9363
9364         /**
9365          * Creates a KeyMap for this element
9366          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9367          * @return {Roo.KeyMap} The KeyMap created
9368          */
9369         addKeyMap : function(config){
9370             return new Roo.KeyMap(this, config);
9371         },
9372
9373         /**
9374          * Returns true if this element is scrollable.
9375          * @return {Boolean}
9376          */
9377          isScrollable : function(){
9378             var dom = this.dom;
9379             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380         },
9381
9382         /**
9383          * 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().
9384          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9385          * @param {Number} value The new scroll value
9386          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9387          * @return {Element} this
9388          */
9389
9390         scrollTo : function(side, value, animate){
9391             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9392             if(!animate || !A){
9393                 this.dom[prop] = value;
9394             }else{
9395                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9396                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9397             }
9398             return this;
9399         },
9400
9401         /**
9402          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9403          * within this element's scrollable range.
9404          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9405          * @param {Number} distance How far to scroll the element in pixels
9406          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9407          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9408          * was scrolled as far as it could go.
9409          */
9410          scroll : function(direction, distance, animate){
9411              if(!this.isScrollable()){
9412                  return;
9413              }
9414              var el = this.dom;
9415              var l = el.scrollLeft, t = el.scrollTop;
9416              var w = el.scrollWidth, h = el.scrollHeight;
9417              var cw = el.clientWidth, ch = el.clientHeight;
9418              direction = direction.toLowerCase();
9419              var scrolled = false;
9420              var a = this.preanim(arguments, 2);
9421              switch(direction){
9422                  case "l":
9423                  case "left":
9424                      if(w - l > cw){
9425                          var v = Math.min(l + distance, w-cw);
9426                          this.scrollTo("left", v, a);
9427                          scrolled = true;
9428                      }
9429                      break;
9430                 case "r":
9431                 case "right":
9432                      if(l > 0){
9433                          var v = Math.max(l - distance, 0);
9434                          this.scrollTo("left", v, a);
9435                          scrolled = true;
9436                      }
9437                      break;
9438                 case "t":
9439                 case "top":
9440                 case "up":
9441                      if(t > 0){
9442                          var v = Math.max(t - distance, 0);
9443                          this.scrollTo("top", v, a);
9444                          scrolled = true;
9445                      }
9446                      break;
9447                 case "b":
9448                 case "bottom":
9449                 case "down":
9450                      if(h - t > ch){
9451                          var v = Math.min(t + distance, h-ch);
9452                          this.scrollTo("top", v, a);
9453                          scrolled = true;
9454                      }
9455                      break;
9456              }
9457              return scrolled;
9458         },
9459
9460         /**
9461          * Translates the passed page coordinates into left/top css values for this element
9462          * @param {Number/Array} x The page x or an array containing [x, y]
9463          * @param {Number} y The page y
9464          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9465          */
9466         translatePoints : function(x, y){
9467             if(typeof x == 'object' || x instanceof Array){
9468                 y = x[1]; x = x[0];
9469             }
9470             var p = this.getStyle('position');
9471             var o = this.getXY();
9472
9473             var l = parseInt(this.getStyle('left'), 10);
9474             var t = parseInt(this.getStyle('top'), 10);
9475
9476             if(isNaN(l)){
9477                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9478             }
9479             if(isNaN(t)){
9480                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9481             }
9482
9483             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484         },
9485
9486         /**
9487          * Returns the current scroll position of the element.
9488          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9489          */
9490         getScroll : function(){
9491             var d = this.dom, doc = document;
9492             if(d == doc || d == doc.body){
9493                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9494                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9495                 return {left: l, top: t};
9496             }else{
9497                 return {left: d.scrollLeft, top: d.scrollTop};
9498             }
9499         },
9500
9501         /**
9502          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9503          * are convert to standard 6 digit hex color.
9504          * @param {String} attr The css attribute
9505          * @param {String} defaultValue The default value to use when a valid color isn't found
9506          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9507          * YUI color anims.
9508          */
9509         getColor : function(attr, defaultValue, prefix){
9510             var v = this.getStyle(attr);
9511             if(!v || v == "transparent" || v == "inherit") {
9512                 return defaultValue;
9513             }
9514             var color = typeof prefix == "undefined" ? "#" : prefix;
9515             if(v.substr(0, 4) == "rgb("){
9516                 var rvs = v.slice(4, v.length -1).split(",");
9517                 for(var i = 0; i < 3; i++){
9518                     var h = parseInt(rvs[i]).toString(16);
9519                     if(h < 16){
9520                         h = "0" + h;
9521                     }
9522                     color += h;
9523                 }
9524             } else {
9525                 if(v.substr(0, 1) == "#"){
9526                     if(v.length == 4) {
9527                         for(var i = 1; i < 4; i++){
9528                             var c = v.charAt(i);
9529                             color +=  c + c;
9530                         }
9531                     }else if(v.length == 7){
9532                         color += v.substr(1);
9533                     }
9534                 }
9535             }
9536             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537         },
9538
9539         /**
9540          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9541          * gradient background, rounded corners and a 4-way shadow.
9542          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9543          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9544          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9545          * @return {Roo.Element} this
9546          */
9547         boxWrap : function(cls){
9548             cls = cls || 'x-box';
9549             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9550             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9551             return el;
9552         },
9553
9554         /**
9555          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9556          * @param {String} namespace The namespace in which to look for the attribute
9557          * @param {String} name The attribute name
9558          * @return {String} The attribute value
9559          */
9560         getAttributeNS : Roo.isIE ? function(ns, name){
9561             var d = this.dom;
9562             var type = typeof d[ns+":"+name];
9563             if(type != 'undefined' && type != 'unknown'){
9564                 return d[ns+":"+name];
9565             }
9566             return d[name];
9567         } : function(ns, name){
9568             var d = this.dom;
9569             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9570         },
9571         
9572         
9573         /**
9574          * Sets or Returns the value the dom attribute value
9575          * @param {String} name The attribute name
9576          * @param {String} value (optional) The value to set the attribute to
9577          * @return {String} The attribute value
9578          */
9579         attr : function(name){
9580             if (arguments.length > 1) {
9581                 this.dom.setAttribute(name, arguments[1]);
9582                 return arguments[1];
9583             }
9584             if (!this.dom.hasAttribute(name)) {
9585                 return undefined;
9586             }
9587             return this.dom.getAttribute(name);
9588         }
9589         
9590         
9591         
9592     };
9593
9594     var ep = El.prototype;
9595
9596     /**
9597      * Appends an event handler (Shorthand for addListener)
9598      * @param {String}   eventName     The type of event to append
9599      * @param {Function} fn        The method the event invokes
9600      * @param {Object} scope       (optional) The scope (this object) of the fn
9601      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9602      * @method
9603      */
9604     ep.on = ep.addListener;
9605         // backwards compat
9606     ep.mon = ep.addListener;
9607
9608     /**
9609      * Removes an event handler from this element (shorthand for removeListener)
9610      * @param {String} eventName the type of event to remove
9611      * @param {Function} fn the method the event invokes
9612      * @return {Roo.Element} this
9613      * @method
9614      */
9615     ep.un = ep.removeListener;
9616
9617     /**
9618      * true to automatically adjust width and height settings for box-model issues (default to true)
9619      */
9620     ep.autoBoxAdjust = true;
9621
9622     // private
9623     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9624
9625     // private
9626     El.addUnits = function(v, defaultUnit){
9627         if(v === "" || v == "auto"){
9628             return v;
9629         }
9630         if(v === undefined){
9631             return '';
9632         }
9633         if(typeof v == "number" || !El.unitPattern.test(v)){
9634             return v + (defaultUnit || 'px');
9635         }
9636         return v;
9637     };
9638
9639     // special markup used throughout Roo when box wrapping elements
9640     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>';
9641     /**
9642      * Visibility mode constant - Use visibility to hide element
9643      * @static
9644      * @type Number
9645      */
9646     El.VISIBILITY = 1;
9647     /**
9648      * Visibility mode constant - Use display to hide element
9649      * @static
9650      * @type Number
9651      */
9652     El.DISPLAY = 2;
9653
9654     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9655     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9656     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9657
9658
9659
9660     /**
9661      * @private
9662      */
9663     El.cache = {};
9664
9665     var docEl;
9666
9667     /**
9668      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9669      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9670      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9671      * @return {Element} The Element object
9672      * @static
9673      */
9674     El.get = function(el){
9675         var ex, elm, id;
9676         if(!el){ return null; }
9677         if(typeof el == "string"){ // element id
9678             if(!(elm = document.getElementById(el))){
9679                 return null;
9680             }
9681             if(ex = El.cache[el]){
9682                 ex.dom = elm;
9683             }else{
9684                 ex = El.cache[el] = new El(elm);
9685             }
9686             return ex;
9687         }else if(el.tagName){ // dom element
9688             if(!(id = el.id)){
9689                 id = Roo.id(el);
9690             }
9691             if(ex = El.cache[id]){
9692                 ex.dom = el;
9693             }else{
9694                 ex = El.cache[id] = new El(el);
9695             }
9696             return ex;
9697         }else if(el instanceof El){
9698             if(el != docEl){
9699                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9700                                                               // catch case where it hasn't been appended
9701                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9702             }
9703             return el;
9704         }else if(el.isComposite){
9705             return el;
9706         }else if(el instanceof Array){
9707             return El.select(el);
9708         }else if(el == document){
9709             // create a bogus element object representing the document object
9710             if(!docEl){
9711                 var f = function(){};
9712                 f.prototype = El.prototype;
9713                 docEl = new f();
9714                 docEl.dom = document;
9715             }
9716             return docEl;
9717         }
9718         return null;
9719     };
9720
9721     // private
9722     El.uncache = function(el){
9723         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9724             if(a[i]){
9725                 delete El.cache[a[i].id || a[i]];
9726             }
9727         }
9728     };
9729
9730     // private
9731     // Garbage collection - uncache elements/purge listeners on orphaned elements
9732     // so we don't hold a reference and cause the browser to retain them
9733     El.garbageCollect = function(){
9734         if(!Roo.enableGarbageCollector){
9735             clearInterval(El.collectorThread);
9736             return;
9737         }
9738         for(var eid in El.cache){
9739             var el = El.cache[eid], d = el.dom;
9740             // -------------------------------------------------------
9741             // Determining what is garbage:
9742             // -------------------------------------------------------
9743             // !d
9744             // dom node is null, definitely garbage
9745             // -------------------------------------------------------
9746             // !d.parentNode
9747             // no parentNode == direct orphan, definitely garbage
9748             // -------------------------------------------------------
9749             // !d.offsetParent && !document.getElementById(eid)
9750             // display none elements have no offsetParent so we will
9751             // also try to look it up by it's id. However, check
9752             // offsetParent first so we don't do unneeded lookups.
9753             // This enables collection of elements that are not orphans
9754             // directly, but somewhere up the line they have an orphan
9755             // parent.
9756             // -------------------------------------------------------
9757             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9758                 delete El.cache[eid];
9759                 if(d && Roo.enableListenerCollection){
9760                     E.purgeElement(d);
9761                 }
9762             }
9763         }
9764     }
9765     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9766
9767
9768     // dom is optional
9769     El.Flyweight = function(dom){
9770         this.dom = dom;
9771     };
9772     El.Flyweight.prototype = El.prototype;
9773
9774     El._flyweights = {};
9775     /**
9776      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9777      * the dom node can be overwritten by other code.
9778      * @param {String/HTMLElement} el The dom node or id
9779      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9780      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9781      * @static
9782      * @return {Element} The shared Element object
9783      */
9784     El.fly = function(el, named){
9785         named = named || '_global';
9786         el = Roo.getDom(el);
9787         if(!el){
9788             return null;
9789         }
9790         if(!El._flyweights[named]){
9791             El._flyweights[named] = new El.Flyweight();
9792         }
9793         El._flyweights[named].dom = el;
9794         return El._flyweights[named];
9795     };
9796
9797     /**
9798      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9799      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9800      * Shorthand of {@link Roo.Element#get}
9801      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9802      * @return {Element} The Element object
9803      * @member Roo
9804      * @method get
9805      */
9806     Roo.get = El.get;
9807     /**
9808      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9809      * the dom node can be overwritten by other code.
9810      * Shorthand of {@link Roo.Element#fly}
9811      * @param {String/HTMLElement} el The dom node or id
9812      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9813      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9814      * @static
9815      * @return {Element} The shared Element object
9816      * @member Roo
9817      * @method fly
9818      */
9819     Roo.fly = El.fly;
9820
9821     // speedy lookup for elements never to box adjust
9822     var noBoxAdjust = Roo.isStrict ? {
9823         select:1
9824     } : {
9825         input:1, select:1, textarea:1
9826     };
9827     if(Roo.isIE || Roo.isGecko){
9828         noBoxAdjust['button'] = 1;
9829     }
9830
9831
9832     Roo.EventManager.on(window, 'unload', function(){
9833         delete El.cache;
9834         delete El._flyweights;
9835     });
9836 })();
9837
9838
9839
9840
9841 if(Roo.DomQuery){
9842     Roo.Element.selectorFunction = Roo.DomQuery.select;
9843 }
9844
9845 Roo.Element.select = function(selector, unique, root){
9846     var els;
9847     if(typeof selector == "string"){
9848         els = Roo.Element.selectorFunction(selector, root);
9849     }else if(selector.length !== undefined){
9850         els = selector;
9851     }else{
9852         throw "Invalid selector";
9853     }
9854     if(unique === true){
9855         return new Roo.CompositeElement(els);
9856     }else{
9857         return new Roo.CompositeElementLite(els);
9858     }
9859 };
9860 /**
9861  * Selects elements based on the passed CSS selector to enable working on them as 1.
9862  * @param {String/Array} selector The CSS selector or an array of elements
9863  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9864  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9865  * @return {CompositeElementLite/CompositeElement}
9866  * @member Roo
9867  * @method select
9868  */
9869 Roo.select = Roo.Element.select;
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883
9884 /*
9885  * Based on:
9886  * Ext JS Library 1.1.1
9887  * Copyright(c) 2006-2007, Ext JS, LLC.
9888  *
9889  * Originally Released Under LGPL - original licence link has changed is not relivant.
9890  *
9891  * Fork - LGPL
9892  * <script type="text/javascript">
9893  */
9894
9895
9896
9897 //Notifies Element that fx methods are available
9898 Roo.enableFx = true;
9899
9900 /**
9901  * @class Roo.Fx
9902  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9903  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9904  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9905  * Element effects to work.</p><br/>
9906  *
9907  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9908  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9909  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9910  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9911  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9912  * expected results and should be done with care.</p><br/>
9913  *
9914  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9915  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9916 <pre>
9917 Value  Description
9918 -----  -----------------------------
9919 tl     The top left corner
9920 t      The center of the top edge
9921 tr     The top right corner
9922 l      The center of the left edge
9923 r      The center of the right edge
9924 bl     The bottom left corner
9925 b      The center of the bottom edge
9926 br     The bottom right corner
9927 </pre>
9928  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9929  * below are common options that can be passed to any Fx method.</b>
9930  * @cfg {Function} callback A function called when the effect is finished
9931  * @cfg {Object} scope The scope of the effect function
9932  * @cfg {String} easing A valid Easing value for the effect
9933  * @cfg {String} afterCls A css class to apply after the effect
9934  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9935  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9936  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9937  * effects that end with the element being visually hidden, ignored otherwise)
9938  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9939  * a function which returns such a specification that will be applied to the Element after the effect finishes
9940  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9941  * @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
9942  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9943  */
9944 Roo.Fx = {
9945         /**
9946          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9947          * origin for the slide effect.  This function automatically handles wrapping the element with
9948          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9949          * Usage:
9950          *<pre><code>
9951 // default: slide the element in from the top
9952 el.slideIn();
9953
9954 // custom: slide the element in from the right with a 2-second duration
9955 el.slideIn('r', { duration: 2 });
9956
9957 // common config options shown with default values
9958 el.slideIn('t', {
9959     easing: 'easeOut',
9960     duration: .5
9961 });
9962 </code></pre>
9963          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9964          * @param {Object} options (optional) Object literal with any of the Fx config options
9965          * @return {Roo.Element} The Element
9966          */
9967     slideIn : function(anchor, o){
9968         var el = this.getFxEl();
9969         o = o || {};
9970
9971         el.queueFx(o, function(){
9972
9973             anchor = anchor || "t";
9974
9975             // fix display to visibility
9976             this.fixDisplay();
9977
9978             // restore values after effect
9979             var r = this.getFxRestore();
9980             var b = this.getBox();
9981             // fixed size for slide
9982             this.setSize(b);
9983
9984             // wrap if needed
9985             var wrap = this.fxWrap(r.pos, o, "hidden");
9986
9987             var st = this.dom.style;
9988             st.visibility = "visible";
9989             st.position = "absolute";
9990
9991             // clear out temp styles after slide and unwrap
9992             var after = function(){
9993                 el.fxUnwrap(wrap, r.pos, o);
9994                 st.width = r.width;
9995                 st.height = r.height;
9996                 el.afterFx(o);
9997             };
9998             // time to calc the positions
9999             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10000
10001             switch(anchor.toLowerCase()){
10002                 case "t":
10003                     wrap.setSize(b.width, 0);
10004                     st.left = st.bottom = "0";
10005                     a = {height: bh};
10006                 break;
10007                 case "l":
10008                     wrap.setSize(0, b.height);
10009                     st.right = st.top = "0";
10010                     a = {width: bw};
10011                 break;
10012                 case "r":
10013                     wrap.setSize(0, b.height);
10014                     wrap.setX(b.right);
10015                     st.left = st.top = "0";
10016                     a = {width: bw, points: pt};
10017                 break;
10018                 case "b":
10019                     wrap.setSize(b.width, 0);
10020                     wrap.setY(b.bottom);
10021                     st.left = st.top = "0";
10022                     a = {height: bh, points: pt};
10023                 break;
10024                 case "tl":
10025                     wrap.setSize(0, 0);
10026                     st.right = st.bottom = "0";
10027                     a = {width: bw, height: bh};
10028                 break;
10029                 case "bl":
10030                     wrap.setSize(0, 0);
10031                     wrap.setY(b.y+b.height);
10032                     st.right = st.top = "0";
10033                     a = {width: bw, height: bh, points: pt};
10034                 break;
10035                 case "br":
10036                     wrap.setSize(0, 0);
10037                     wrap.setXY([b.right, b.bottom]);
10038                     st.left = st.top = "0";
10039                     a = {width: bw, height: bh, points: pt};
10040                 break;
10041                 case "tr":
10042                     wrap.setSize(0, 0);
10043                     wrap.setX(b.x+b.width);
10044                     st.left = st.bottom = "0";
10045                     a = {width: bw, height: bh, points: pt};
10046                 break;
10047             }
10048             this.dom.style.visibility = "visible";
10049             wrap.show();
10050
10051             arguments.callee.anim = wrap.fxanim(a,
10052                 o,
10053                 'motion',
10054                 .5,
10055                 'easeOut', after);
10056         });
10057         return this;
10058     },
10059     
10060         /**
10061          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10062          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10063          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10064          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10065          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10066          * Usage:
10067          *<pre><code>
10068 // default: slide the element out to the top
10069 el.slideOut();
10070
10071 // custom: slide the element out to the right with a 2-second duration
10072 el.slideOut('r', { duration: 2 });
10073
10074 // common config options shown with default values
10075 el.slideOut('t', {
10076     easing: 'easeOut',
10077     duration: .5,
10078     remove: false,
10079     useDisplay: false
10080 });
10081 </code></pre>
10082          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10083          * @param {Object} options (optional) Object literal with any of the Fx config options
10084          * @return {Roo.Element} The Element
10085          */
10086     slideOut : function(anchor, o){
10087         var el = this.getFxEl();
10088         o = o || {};
10089
10090         el.queueFx(o, function(){
10091
10092             anchor = anchor || "t";
10093
10094             // restore values after effect
10095             var r = this.getFxRestore();
10096             
10097             var b = this.getBox();
10098             // fixed size for slide
10099             this.setSize(b);
10100
10101             // wrap if needed
10102             var wrap = this.fxWrap(r.pos, o, "visible");
10103
10104             var st = this.dom.style;
10105             st.visibility = "visible";
10106             st.position = "absolute";
10107
10108             wrap.setSize(b);
10109
10110             var after = function(){
10111                 if(o.useDisplay){
10112                     el.setDisplayed(false);
10113                 }else{
10114                     el.hide();
10115                 }
10116
10117                 el.fxUnwrap(wrap, r.pos, o);
10118
10119                 st.width = r.width;
10120                 st.height = r.height;
10121
10122                 el.afterFx(o);
10123             };
10124
10125             var a, zero = {to: 0};
10126             switch(anchor.toLowerCase()){
10127                 case "t":
10128                     st.left = st.bottom = "0";
10129                     a = {height: zero};
10130                 break;
10131                 case "l":
10132                     st.right = st.top = "0";
10133                     a = {width: zero};
10134                 break;
10135                 case "r":
10136                     st.left = st.top = "0";
10137                     a = {width: zero, points: {to:[b.right, b.y]}};
10138                 break;
10139                 case "b":
10140                     st.left = st.top = "0";
10141                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10142                 break;
10143                 case "tl":
10144                     st.right = st.bottom = "0";
10145                     a = {width: zero, height: zero};
10146                 break;
10147                 case "bl":
10148                     st.right = st.top = "0";
10149                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10150                 break;
10151                 case "br":
10152                     st.left = st.top = "0";
10153                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10154                 break;
10155                 case "tr":
10156                     st.left = st.bottom = "0";
10157                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10158                 break;
10159             }
10160
10161             arguments.callee.anim = wrap.fxanim(a,
10162                 o,
10163                 'motion',
10164                 .5,
10165                 "easeOut", after);
10166         });
10167         return this;
10168     },
10169
10170         /**
10171          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10172          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10173          * The element must be removed from the DOM using the 'remove' config option if desired.
10174          * Usage:
10175          *<pre><code>
10176 // default
10177 el.puff();
10178
10179 // common config options shown with default values
10180 el.puff({
10181     easing: 'easeOut',
10182     duration: .5,
10183     remove: false,
10184     useDisplay: false
10185 });
10186 </code></pre>
10187          * @param {Object} options (optional) Object literal with any of the Fx config options
10188          * @return {Roo.Element} The Element
10189          */
10190     puff : function(o){
10191         var el = this.getFxEl();
10192         o = o || {};
10193
10194         el.queueFx(o, function(){
10195             this.clearOpacity();
10196             this.show();
10197
10198             // restore values after effect
10199             var r = this.getFxRestore();
10200             var st = this.dom.style;
10201
10202             var after = function(){
10203                 if(o.useDisplay){
10204                     el.setDisplayed(false);
10205                 }else{
10206                     el.hide();
10207                 }
10208
10209                 el.clearOpacity();
10210
10211                 el.setPositioning(r.pos);
10212                 st.width = r.width;
10213                 st.height = r.height;
10214                 st.fontSize = '';
10215                 el.afterFx(o);
10216             };
10217
10218             var width = this.getWidth();
10219             var height = this.getHeight();
10220
10221             arguments.callee.anim = this.fxanim({
10222                     width : {to: this.adjustWidth(width * 2)},
10223                     height : {to: this.adjustHeight(height * 2)},
10224                     points : {by: [-(width * .5), -(height * .5)]},
10225                     opacity : {to: 0},
10226                     fontSize: {to:200, unit: "%"}
10227                 },
10228                 o,
10229                 'motion',
10230                 .5,
10231                 "easeOut", after);
10232         });
10233         return this;
10234     },
10235
10236         /**
10237          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10238          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10239          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10240          * Usage:
10241          *<pre><code>
10242 // default
10243 el.switchOff();
10244
10245 // all config options shown with default values
10246 el.switchOff({
10247     easing: 'easeIn',
10248     duration: .3,
10249     remove: false,
10250     useDisplay: false
10251 });
10252 </code></pre>
10253          * @param {Object} options (optional) Object literal with any of the Fx config options
10254          * @return {Roo.Element} The Element
10255          */
10256     switchOff : function(o){
10257         var el = this.getFxEl();
10258         o = o || {};
10259
10260         el.queueFx(o, function(){
10261             this.clearOpacity();
10262             this.clip();
10263
10264             // restore values after effect
10265             var r = this.getFxRestore();
10266             var st = this.dom.style;
10267
10268             var after = function(){
10269                 if(o.useDisplay){
10270                     el.setDisplayed(false);
10271                 }else{
10272                     el.hide();
10273                 }
10274
10275                 el.clearOpacity();
10276                 el.setPositioning(r.pos);
10277                 st.width = r.width;
10278                 st.height = r.height;
10279
10280                 el.afterFx(o);
10281             };
10282
10283             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10284                 this.clearOpacity();
10285                 (function(){
10286                     this.fxanim({
10287                         height:{to:1},
10288                         points:{by:[0, this.getHeight() * .5]}
10289                     }, o, 'motion', 0.3, 'easeIn', after);
10290                 }).defer(100, this);
10291             });
10292         });
10293         return this;
10294     },
10295
10296     /**
10297      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10298      * changed using the "attr" config option) and then fading back to the original color. If no original
10299      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10300      * Usage:
10301 <pre><code>
10302 // default: highlight background to yellow
10303 el.highlight();
10304
10305 // custom: highlight foreground text to blue for 2 seconds
10306 el.highlight("0000ff", { attr: 'color', duration: 2 });
10307
10308 // common config options shown with default values
10309 el.highlight("ffff9c", {
10310     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10311     endColor: (current color) or "ffffff",
10312     easing: 'easeIn',
10313     duration: 1
10314 });
10315 </code></pre>
10316      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10317      * @param {Object} options (optional) Object literal with any of the Fx config options
10318      * @return {Roo.Element} The Element
10319      */ 
10320     highlight : function(color, o){
10321         var el = this.getFxEl();
10322         o = o || {};
10323
10324         el.queueFx(o, function(){
10325             color = color || "ffff9c";
10326             attr = o.attr || "backgroundColor";
10327
10328             this.clearOpacity();
10329             this.show();
10330
10331             var origColor = this.getColor(attr);
10332             var restoreColor = this.dom.style[attr];
10333             endColor = (o.endColor || origColor) || "ffffff";
10334
10335             var after = function(){
10336                 el.dom.style[attr] = restoreColor;
10337                 el.afterFx(o);
10338             };
10339
10340             var a = {};
10341             a[attr] = {from: color, to: endColor};
10342             arguments.callee.anim = this.fxanim(a,
10343                 o,
10344                 'color',
10345                 1,
10346                 'easeIn', after);
10347         });
10348         return this;
10349     },
10350
10351    /**
10352     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10353     * Usage:
10354 <pre><code>
10355 // default: a single light blue ripple
10356 el.frame();
10357
10358 // custom: 3 red ripples lasting 3 seconds total
10359 el.frame("ff0000", 3, { duration: 3 });
10360
10361 // common config options shown with default values
10362 el.frame("C3DAF9", 1, {
10363     duration: 1 //duration of entire animation (not each individual ripple)
10364     // Note: Easing is not configurable and will be ignored if included
10365 });
10366 </code></pre>
10367     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10368     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10369     * @param {Object} options (optional) Object literal with any of the Fx config options
10370     * @return {Roo.Element} The Element
10371     */
10372     frame : function(color, count, o){
10373         var el = this.getFxEl();
10374         o = o || {};
10375
10376         el.queueFx(o, function(){
10377             color = color || "#C3DAF9";
10378             if(color.length == 6){
10379                 color = "#" + color;
10380             }
10381             count = count || 1;
10382             duration = o.duration || 1;
10383             this.show();
10384
10385             var b = this.getBox();
10386             var animFn = function(){
10387                 var proxy = this.createProxy({
10388
10389                      style:{
10390                         visbility:"hidden",
10391                         position:"absolute",
10392                         "z-index":"35000", // yee haw
10393                         border:"0px solid " + color
10394                      }
10395                   });
10396                 var scale = Roo.isBorderBox ? 2 : 1;
10397                 proxy.animate({
10398                     top:{from:b.y, to:b.y - 20},
10399                     left:{from:b.x, to:b.x - 20},
10400                     borderWidth:{from:0, to:10},
10401                     opacity:{from:1, to:0},
10402                     height:{from:b.height, to:(b.height + (20*scale))},
10403                     width:{from:b.width, to:(b.width + (20*scale))}
10404                 }, duration, function(){
10405                     proxy.remove();
10406                 });
10407                 if(--count > 0){
10408                      animFn.defer((duration/2)*1000, this);
10409                 }else{
10410                     el.afterFx(o);
10411                 }
10412             };
10413             animFn.call(this);
10414         });
10415         return this;
10416     },
10417
10418    /**
10419     * Creates a pause before any subsequent queued effects begin.  If there are
10420     * no effects queued after the pause it will have no effect.
10421     * Usage:
10422 <pre><code>
10423 el.pause(1);
10424 </code></pre>
10425     * @param {Number} seconds The length of time to pause (in seconds)
10426     * @return {Roo.Element} The Element
10427     */
10428     pause : function(seconds){
10429         var el = this.getFxEl();
10430         var o = {};
10431
10432         el.queueFx(o, function(){
10433             setTimeout(function(){
10434                 el.afterFx(o);
10435             }, seconds * 1000);
10436         });
10437         return this;
10438     },
10439
10440    /**
10441     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10442     * using the "endOpacity" config option.
10443     * Usage:
10444 <pre><code>
10445 // default: fade in from opacity 0 to 100%
10446 el.fadeIn();
10447
10448 // custom: fade in from opacity 0 to 75% over 2 seconds
10449 el.fadeIn({ endOpacity: .75, duration: 2});
10450
10451 // common config options shown with default values
10452 el.fadeIn({
10453     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10454     easing: 'easeOut',
10455     duration: .5
10456 });
10457 </code></pre>
10458     * @param {Object} options (optional) Object literal with any of the Fx config options
10459     * @return {Roo.Element} The Element
10460     */
10461     fadeIn : function(o){
10462         var el = this.getFxEl();
10463         o = o || {};
10464         el.queueFx(o, function(){
10465             this.setOpacity(0);
10466             this.fixDisplay();
10467             this.dom.style.visibility = 'visible';
10468             var to = o.endOpacity || 1;
10469             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10470                 o, null, .5, "easeOut", function(){
10471                 if(to == 1){
10472                     this.clearOpacity();
10473                 }
10474                 el.afterFx(o);
10475             });
10476         });
10477         return this;
10478     },
10479
10480    /**
10481     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10482     * using the "endOpacity" config option.
10483     * Usage:
10484 <pre><code>
10485 // default: fade out from the element's current opacity to 0
10486 el.fadeOut();
10487
10488 // custom: fade out from the element's current opacity to 25% over 2 seconds
10489 el.fadeOut({ endOpacity: .25, duration: 2});
10490
10491 // common config options shown with default values
10492 el.fadeOut({
10493     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10494     easing: 'easeOut',
10495     duration: .5
10496     remove: false,
10497     useDisplay: false
10498 });
10499 </code></pre>
10500     * @param {Object} options (optional) Object literal with any of the Fx config options
10501     * @return {Roo.Element} The Element
10502     */
10503     fadeOut : function(o){
10504         var el = this.getFxEl();
10505         o = o || {};
10506         el.queueFx(o, function(){
10507             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10508                 o, null, .5, "easeOut", function(){
10509                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10510                      this.dom.style.display = "none";
10511                 }else{
10512                      this.dom.style.visibility = "hidden";
10513                 }
10514                 this.clearOpacity();
10515                 el.afterFx(o);
10516             });
10517         });
10518         return this;
10519     },
10520
10521    /**
10522     * Animates the transition of an element's dimensions from a starting height/width
10523     * to an ending height/width.
10524     * Usage:
10525 <pre><code>
10526 // change height and width to 100x100 pixels
10527 el.scale(100, 100);
10528
10529 // common config options shown with default values.  The height and width will default to
10530 // the element's existing values if passed as null.
10531 el.scale(
10532     [element's width],
10533     [element's height], {
10534     easing: 'easeOut',
10535     duration: .35
10536 });
10537 </code></pre>
10538     * @param {Number} width  The new width (pass undefined to keep the original width)
10539     * @param {Number} height  The new height (pass undefined to keep the original height)
10540     * @param {Object} options (optional) Object literal with any of the Fx config options
10541     * @return {Roo.Element} The Element
10542     */
10543     scale : function(w, h, o){
10544         this.shift(Roo.apply({}, o, {
10545             width: w,
10546             height: h
10547         }));
10548         return this;
10549     },
10550
10551    /**
10552     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10553     * Any of these properties not specified in the config object will not be changed.  This effect 
10554     * requires that at least one new dimension, position or opacity setting must be passed in on
10555     * the config object in order for the function to have any effect.
10556     * Usage:
10557 <pre><code>
10558 // slide the element horizontally to x position 200 while changing the height and opacity
10559 el.shift({ x: 200, height: 50, opacity: .8 });
10560
10561 // common config options shown with default values.
10562 el.shift({
10563     width: [element's width],
10564     height: [element's height],
10565     x: [element's x position],
10566     y: [element's y position],
10567     opacity: [element's opacity],
10568     easing: 'easeOut',
10569     duration: .35
10570 });
10571 </code></pre>
10572     * @param {Object} options  Object literal with any of the Fx config options
10573     * @return {Roo.Element} The Element
10574     */
10575     shift : function(o){
10576         var el = this.getFxEl();
10577         o = o || {};
10578         el.queueFx(o, function(){
10579             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10580             if(w !== undefined){
10581                 a.width = {to: this.adjustWidth(w)};
10582             }
10583             if(h !== undefined){
10584                 a.height = {to: this.adjustHeight(h)};
10585             }
10586             if(x !== undefined || y !== undefined){
10587                 a.points = {to: [
10588                     x !== undefined ? x : this.getX(),
10589                     y !== undefined ? y : this.getY()
10590                 ]};
10591             }
10592             if(op !== undefined){
10593                 a.opacity = {to: op};
10594             }
10595             if(o.xy !== undefined){
10596                 a.points = {to: o.xy};
10597             }
10598             arguments.callee.anim = this.fxanim(a,
10599                 o, 'motion', .35, "easeOut", function(){
10600                 el.afterFx(o);
10601             });
10602         });
10603         return this;
10604     },
10605
10606         /**
10607          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10608          * ending point of the effect.
10609          * Usage:
10610          *<pre><code>
10611 // default: slide the element downward while fading out
10612 el.ghost();
10613
10614 // custom: slide the element out to the right with a 2-second duration
10615 el.ghost('r', { duration: 2 });
10616
10617 // common config options shown with default values
10618 el.ghost('b', {
10619     easing: 'easeOut',
10620     duration: .5
10621     remove: false,
10622     useDisplay: false
10623 });
10624 </code></pre>
10625          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10626          * @param {Object} options (optional) Object literal with any of the Fx config options
10627          * @return {Roo.Element} The Element
10628          */
10629     ghost : function(anchor, o){
10630         var el = this.getFxEl();
10631         o = o || {};
10632
10633         el.queueFx(o, function(){
10634             anchor = anchor || "b";
10635
10636             // restore values after effect
10637             var r = this.getFxRestore();
10638             var w = this.getWidth(),
10639                 h = this.getHeight();
10640
10641             var st = this.dom.style;
10642
10643             var after = function(){
10644                 if(o.useDisplay){
10645                     el.setDisplayed(false);
10646                 }else{
10647                     el.hide();
10648                 }
10649
10650                 el.clearOpacity();
10651                 el.setPositioning(r.pos);
10652                 st.width = r.width;
10653                 st.height = r.height;
10654
10655                 el.afterFx(o);
10656             };
10657
10658             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10659             switch(anchor.toLowerCase()){
10660                 case "t":
10661                     pt.by = [0, -h];
10662                 break;
10663                 case "l":
10664                     pt.by = [-w, 0];
10665                 break;
10666                 case "r":
10667                     pt.by = [w, 0];
10668                 break;
10669                 case "b":
10670                     pt.by = [0, h];
10671                 break;
10672                 case "tl":
10673                     pt.by = [-w, -h];
10674                 break;
10675                 case "bl":
10676                     pt.by = [-w, h];
10677                 break;
10678                 case "br":
10679                     pt.by = [w, h];
10680                 break;
10681                 case "tr":
10682                     pt.by = [w, -h];
10683                 break;
10684             }
10685
10686             arguments.callee.anim = this.fxanim(a,
10687                 o,
10688                 'motion',
10689                 .5,
10690                 "easeOut", after);
10691         });
10692         return this;
10693     },
10694
10695         /**
10696          * Ensures that all effects queued after syncFx is called on the element are
10697          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10698          * @return {Roo.Element} The Element
10699          */
10700     syncFx : function(){
10701         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10702             block : false,
10703             concurrent : true,
10704             stopFx : false
10705         });
10706         return this;
10707     },
10708
10709         /**
10710          * Ensures that all effects queued after sequenceFx is called on the element are
10711          * run in sequence.  This is the opposite of {@link #syncFx}.
10712          * @return {Roo.Element} The Element
10713          */
10714     sequenceFx : function(){
10715         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10716             block : false,
10717             concurrent : false,
10718             stopFx : false
10719         });
10720         return this;
10721     },
10722
10723         /* @private */
10724     nextFx : function(){
10725         var ef = this.fxQueue[0];
10726         if(ef){
10727             ef.call(this);
10728         }
10729     },
10730
10731         /**
10732          * Returns true if the element has any effects actively running or queued, else returns false.
10733          * @return {Boolean} True if element has active effects, else false
10734          */
10735     hasActiveFx : function(){
10736         return this.fxQueue && this.fxQueue[0];
10737     },
10738
10739         /**
10740          * Stops any running effects and clears the element's internal effects queue if it contains
10741          * any additional effects that haven't started yet.
10742          * @return {Roo.Element} The Element
10743          */
10744     stopFx : function(){
10745         if(this.hasActiveFx()){
10746             var cur = this.fxQueue[0];
10747             if(cur && cur.anim && cur.anim.isAnimated()){
10748                 this.fxQueue = [cur]; // clear out others
10749                 cur.anim.stop(true);
10750             }
10751         }
10752         return this;
10753     },
10754
10755         /* @private */
10756     beforeFx : function(o){
10757         if(this.hasActiveFx() && !o.concurrent){
10758            if(o.stopFx){
10759                this.stopFx();
10760                return true;
10761            }
10762            return false;
10763         }
10764         return true;
10765     },
10766
10767         /**
10768          * Returns true if the element is currently blocking so that no other effect can be queued
10769          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10770          * used to ensure that an effect initiated by a user action runs to completion prior to the
10771          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10772          * @return {Boolean} True if blocking, else false
10773          */
10774     hasFxBlock : function(){
10775         var q = this.fxQueue;
10776         return q && q[0] && q[0].block;
10777     },
10778
10779         /* @private */
10780     queueFx : function(o, fn){
10781         if(!this.fxQueue){
10782             this.fxQueue = [];
10783         }
10784         if(!this.hasFxBlock()){
10785             Roo.applyIf(o, this.fxDefaults);
10786             if(!o.concurrent){
10787                 var run = this.beforeFx(o);
10788                 fn.block = o.block;
10789                 this.fxQueue.push(fn);
10790                 if(run){
10791                     this.nextFx();
10792                 }
10793             }else{
10794                 fn.call(this);
10795             }
10796         }
10797         return this;
10798     },
10799
10800         /* @private */
10801     fxWrap : function(pos, o, vis){
10802         var wrap;
10803         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10804             var wrapXY;
10805             if(o.fixPosition){
10806                 wrapXY = this.getXY();
10807             }
10808             var div = document.createElement("div");
10809             div.style.visibility = vis;
10810             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10811             wrap.setPositioning(pos);
10812             if(wrap.getStyle("position") == "static"){
10813                 wrap.position("relative");
10814             }
10815             this.clearPositioning('auto');
10816             wrap.clip();
10817             wrap.dom.appendChild(this.dom);
10818             if(wrapXY){
10819                 wrap.setXY(wrapXY);
10820             }
10821         }
10822         return wrap;
10823     },
10824
10825         /* @private */
10826     fxUnwrap : function(wrap, pos, o){
10827         this.clearPositioning();
10828         this.setPositioning(pos);
10829         if(!o.wrap){
10830             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10831             wrap.remove();
10832         }
10833     },
10834
10835         /* @private */
10836     getFxRestore : function(){
10837         var st = this.dom.style;
10838         return {pos: this.getPositioning(), width: st.width, height : st.height};
10839     },
10840
10841         /* @private */
10842     afterFx : function(o){
10843         if(o.afterStyle){
10844             this.applyStyles(o.afterStyle);
10845         }
10846         if(o.afterCls){
10847             this.addClass(o.afterCls);
10848         }
10849         if(o.remove === true){
10850             this.remove();
10851         }
10852         Roo.callback(o.callback, o.scope, [this]);
10853         if(!o.concurrent){
10854             this.fxQueue.shift();
10855             this.nextFx();
10856         }
10857     },
10858
10859         /* @private */
10860     getFxEl : function(){ // support for composite element fx
10861         return Roo.get(this.dom);
10862     },
10863
10864         /* @private */
10865     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10866         animType = animType || 'run';
10867         opt = opt || {};
10868         var anim = Roo.lib.Anim[animType](
10869             this.dom, args,
10870             (opt.duration || defaultDur) || .35,
10871             (opt.easing || defaultEase) || 'easeOut',
10872             function(){
10873                 Roo.callback(cb, this);
10874             },
10875             this
10876         );
10877         opt.anim = anim;
10878         return anim;
10879     }
10880 };
10881
10882 // backwords compat
10883 Roo.Fx.resize = Roo.Fx.scale;
10884
10885 //When included, Roo.Fx is automatically applied to Element so that all basic
10886 //effects are available directly via the Element API
10887 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10888  * Based on:
10889  * Ext JS Library 1.1.1
10890  * Copyright(c) 2006-2007, Ext JS, LLC.
10891  *
10892  * Originally Released Under LGPL - original licence link has changed is not relivant.
10893  *
10894  * Fork - LGPL
10895  * <script type="text/javascript">
10896  */
10897
10898
10899 /**
10900  * @class Roo.CompositeElement
10901  * Standard composite class. Creates a Roo.Element for every element in the collection.
10902  * <br><br>
10903  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10904  * actions will be performed on all the elements in this collection.</b>
10905  * <br><br>
10906  * All methods return <i>this</i> and can be chained.
10907  <pre><code>
10908  var els = Roo.select("#some-el div.some-class", true);
10909  // or select directly from an existing element
10910  var el = Roo.get('some-el');
10911  el.select('div.some-class', true);
10912
10913  els.setWidth(100); // all elements become 100 width
10914  els.hide(true); // all elements fade out and hide
10915  // or
10916  els.setWidth(100).hide(true);
10917  </code></pre>
10918  */
10919 Roo.CompositeElement = function(els){
10920     this.elements = [];
10921     this.addElements(els);
10922 };
10923 Roo.CompositeElement.prototype = {
10924     isComposite: true,
10925     addElements : function(els){
10926         if(!els) return this;
10927         if(typeof els == "string"){
10928             els = Roo.Element.selectorFunction(els);
10929         }
10930         var yels = this.elements;
10931         var index = yels.length-1;
10932         for(var i = 0, len = els.length; i < len; i++) {
10933                 yels[++index] = Roo.get(els[i]);
10934         }
10935         return this;
10936     },
10937
10938     /**
10939     * Clears this composite and adds the elements returned by the passed selector.
10940     * @param {String/Array} els A string CSS selector, an array of elements or an element
10941     * @return {CompositeElement} this
10942     */
10943     fill : function(els){
10944         this.elements = [];
10945         this.add(els);
10946         return this;
10947     },
10948
10949     /**
10950     * Filters this composite to only elements that match the passed selector.
10951     * @param {String} selector A string CSS selector
10952     * @return {CompositeElement} this
10953     */
10954     filter : function(selector){
10955         var els = [];
10956         this.each(function(el){
10957             if(el.is(selector)){
10958                 els[els.length] = el.dom;
10959             }
10960         });
10961         this.fill(els);
10962         return this;
10963     },
10964
10965     invoke : function(fn, args){
10966         var els = this.elements;
10967         for(var i = 0, len = els.length; i < len; i++) {
10968                 Roo.Element.prototype[fn].apply(els[i], args);
10969         }
10970         return this;
10971     },
10972     /**
10973     * Adds elements to this composite.
10974     * @param {String/Array} els A string CSS selector, an array of elements or an element
10975     * @return {CompositeElement} this
10976     */
10977     add : function(els){
10978         if(typeof els == "string"){
10979             this.addElements(Roo.Element.selectorFunction(els));
10980         }else if(els.length !== undefined){
10981             this.addElements(els);
10982         }else{
10983             this.addElements([els]);
10984         }
10985         return this;
10986     },
10987     /**
10988     * Calls the passed function passing (el, this, index) for each element in this composite.
10989     * @param {Function} fn The function to call
10990     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10991     * @return {CompositeElement} this
10992     */
10993     each : function(fn, scope){
10994         var els = this.elements;
10995         for(var i = 0, len = els.length; i < len; i++){
10996             if(fn.call(scope || els[i], els[i], this, i) === false) {
10997                 break;
10998             }
10999         }
11000         return this;
11001     },
11002
11003     /**
11004      * Returns the Element object at the specified index
11005      * @param {Number} index
11006      * @return {Roo.Element}
11007      */
11008     item : function(index){
11009         return this.elements[index] || null;
11010     },
11011
11012     /**
11013      * Returns the first Element
11014      * @return {Roo.Element}
11015      */
11016     first : function(){
11017         return this.item(0);
11018     },
11019
11020     /**
11021      * Returns the last Element
11022      * @return {Roo.Element}
11023      */
11024     last : function(){
11025         return this.item(this.elements.length-1);
11026     },
11027
11028     /**
11029      * Returns the number of elements in this composite
11030      * @return Number
11031      */
11032     getCount : function(){
11033         return this.elements.length;
11034     },
11035
11036     /**
11037      * Returns true if this composite contains the passed element
11038      * @return Boolean
11039      */
11040     contains : function(el){
11041         return this.indexOf(el) !== -1;
11042     },
11043
11044     /**
11045      * Returns true if this composite contains the passed element
11046      * @return Boolean
11047      */
11048     indexOf : function(el){
11049         return this.elements.indexOf(Roo.get(el));
11050     },
11051
11052
11053     /**
11054     * Removes the specified element(s).
11055     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11056     * or an array of any of those.
11057     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11058     * @return {CompositeElement} this
11059     */
11060     removeElement : function(el, removeDom){
11061         if(el instanceof Array){
11062             for(var i = 0, len = el.length; i < len; i++){
11063                 this.removeElement(el[i]);
11064             }
11065             return this;
11066         }
11067         var index = typeof el == 'number' ? el : this.indexOf(el);
11068         if(index !== -1){
11069             if(removeDom){
11070                 var d = this.elements[index];
11071                 if(d.dom){
11072                     d.remove();
11073                 }else{
11074                     d.parentNode.removeChild(d);
11075                 }
11076             }
11077             this.elements.splice(index, 1);
11078         }
11079         return this;
11080     },
11081
11082     /**
11083     * Replaces the specified element with the passed element.
11084     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11085     * to replace.
11086     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11087     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11088     * @return {CompositeElement} this
11089     */
11090     replaceElement : function(el, replacement, domReplace){
11091         var index = typeof el == 'number' ? el : this.indexOf(el);
11092         if(index !== -1){
11093             if(domReplace){
11094                 this.elements[index].replaceWith(replacement);
11095             }else{
11096                 this.elements.splice(index, 1, Roo.get(replacement))
11097             }
11098         }
11099         return this;
11100     },
11101
11102     /**
11103      * Removes all elements.
11104      */
11105     clear : function(){
11106         this.elements = [];
11107     }
11108 };
11109 (function(){
11110     Roo.CompositeElement.createCall = function(proto, fnName){
11111         if(!proto[fnName]){
11112             proto[fnName] = function(){
11113                 return this.invoke(fnName, arguments);
11114             };
11115         }
11116     };
11117     for(var fnName in Roo.Element.prototype){
11118         if(typeof Roo.Element.prototype[fnName] == "function"){
11119             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11120         }
11121     };
11122 })();
11123 /*
11124  * Based on:
11125  * Ext JS Library 1.1.1
11126  * Copyright(c) 2006-2007, Ext JS, LLC.
11127  *
11128  * Originally Released Under LGPL - original licence link has changed is not relivant.
11129  *
11130  * Fork - LGPL
11131  * <script type="text/javascript">
11132  */
11133
11134 /**
11135  * @class Roo.CompositeElementLite
11136  * @extends Roo.CompositeElement
11137  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11138  <pre><code>
11139  var els = Roo.select("#some-el div.some-class");
11140  // or select directly from an existing element
11141  var el = Roo.get('some-el');
11142  el.select('div.some-class');
11143
11144  els.setWidth(100); // all elements become 100 width
11145  els.hide(true); // all elements fade out and hide
11146  // or
11147  els.setWidth(100).hide(true);
11148  </code></pre><br><br>
11149  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11150  * actions will be performed on all the elements in this collection.</b>
11151  */
11152 Roo.CompositeElementLite = function(els){
11153     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11154     this.el = new Roo.Element.Flyweight();
11155 };
11156 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11157     addElements : function(els){
11158         if(els){
11159             if(els instanceof Array){
11160                 this.elements = this.elements.concat(els);
11161             }else{
11162                 var yels = this.elements;
11163                 var index = yels.length-1;
11164                 for(var i = 0, len = els.length; i < len; i++) {
11165                     yels[++index] = els[i];
11166                 }
11167             }
11168         }
11169         return this;
11170     },
11171     invoke : function(fn, args){
11172         var els = this.elements;
11173         var el = this.el;
11174         for(var i = 0, len = els.length; i < len; i++) {
11175             el.dom = els[i];
11176                 Roo.Element.prototype[fn].apply(el, args);
11177         }
11178         return this;
11179     },
11180     /**
11181      * Returns a flyweight Element of the dom element object at the specified index
11182      * @param {Number} index
11183      * @return {Roo.Element}
11184      */
11185     item : function(index){
11186         if(!this.elements[index]){
11187             return null;
11188         }
11189         this.el.dom = this.elements[index];
11190         return this.el;
11191     },
11192
11193     // fixes scope with flyweight
11194     addListener : function(eventName, handler, scope, opt){
11195         var els = this.elements;
11196         for(var i = 0, len = els.length; i < len; i++) {
11197             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11198         }
11199         return this;
11200     },
11201
11202     /**
11203     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11204     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11205     * a reference to the dom node, use el.dom.</b>
11206     * @param {Function} fn The function to call
11207     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11208     * @return {CompositeElement} this
11209     */
11210     each : function(fn, scope){
11211         var els = this.elements;
11212         var el = this.el;
11213         for(var i = 0, len = els.length; i < len; i++){
11214             el.dom = els[i];
11215                 if(fn.call(scope || el, el, this, i) === false){
11216                 break;
11217             }
11218         }
11219         return this;
11220     },
11221
11222     indexOf : function(el){
11223         return this.elements.indexOf(Roo.getDom(el));
11224     },
11225
11226     replaceElement : function(el, replacement, domReplace){
11227         var index = typeof el == 'number' ? el : this.indexOf(el);
11228         if(index !== -1){
11229             replacement = Roo.getDom(replacement);
11230             if(domReplace){
11231                 var d = this.elements[index];
11232                 d.parentNode.insertBefore(replacement, d);
11233                 d.parentNode.removeChild(d);
11234             }
11235             this.elements.splice(index, 1, replacement);
11236         }
11237         return this;
11238     }
11239 });
11240 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11241
11242 /*
11243  * Based on:
11244  * Ext JS Library 1.1.1
11245  * Copyright(c) 2006-2007, Ext JS, LLC.
11246  *
11247  * Originally Released Under LGPL - original licence link has changed is not relivant.
11248  *
11249  * Fork - LGPL
11250  * <script type="text/javascript">
11251  */
11252
11253  
11254
11255 /**
11256  * @class Roo.data.Connection
11257  * @extends Roo.util.Observable
11258  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11259  * either to a configured URL, or to a URL specified at request time.<br><br>
11260  * <p>
11261  * Requests made by this class are asynchronous, and will return immediately. No data from
11262  * the server will be available to the statement immediately following the {@link #request} call.
11263  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11264  * <p>
11265  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11266  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11267  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11268  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11269  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11270  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11271  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11272  * standard DOM methods.
11273  * @constructor
11274  * @param {Object} config a configuration object.
11275  */
11276 Roo.data.Connection = function(config){
11277     Roo.apply(this, config);
11278     this.addEvents({
11279         /**
11280          * @event beforerequest
11281          * Fires before a network request is made to retrieve a data object.
11282          * @param {Connection} conn This Connection object.
11283          * @param {Object} options The options config object passed to the {@link #request} method.
11284          */
11285         "beforerequest" : true,
11286         /**
11287          * @event requestcomplete
11288          * Fires if the request was successfully completed.
11289          * @param {Connection} conn This Connection object.
11290          * @param {Object} response The XHR object containing the response data.
11291          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11292          * @param {Object} options The options config object passed to the {@link #request} method.
11293          */
11294         "requestcomplete" : true,
11295         /**
11296          * @event requestexception
11297          * Fires if an error HTTP status was returned from the server.
11298          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11299          * @param {Connection} conn This Connection object.
11300          * @param {Object} response The XHR object containing the response data.
11301          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11302          * @param {Object} options The options config object passed to the {@link #request} method.
11303          */
11304         "requestexception" : true
11305     });
11306     Roo.data.Connection.superclass.constructor.call(this);
11307 };
11308
11309 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11310     /**
11311      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11312      */
11313     /**
11314      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11315      * extra parameters to each request made by this object. (defaults to undefined)
11316      */
11317     /**
11318      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11319      *  to each request made by this object. (defaults to undefined)
11320      */
11321     /**
11322      * @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)
11323      */
11324     /**
11325      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11326      */
11327     timeout : 30000,
11328     /**
11329      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11330      * @type Boolean
11331      */
11332     autoAbort:false,
11333
11334     /**
11335      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11336      * @type Boolean
11337      */
11338     disableCaching: true,
11339
11340     /**
11341      * Sends an HTTP request to a remote server.
11342      * @param {Object} options An object which may contain the following properties:<ul>
11343      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11344      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11345      * request, a url encoded string or a function to call to get either.</li>
11346      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11347      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11348      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11349      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11350      * <li>options {Object} The parameter to the request call.</li>
11351      * <li>success {Boolean} True if the request succeeded.</li>
11352      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11353      * </ul></li>
11354      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11355      * The callback is passed the following parameters:<ul>
11356      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11357      * <li>options {Object} The parameter to the request call.</li>
11358      * </ul></li>
11359      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11360      * The callback is passed the following parameters:<ul>
11361      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11362      * <li>options {Object} The parameter to the request call.</li>
11363      * </ul></li>
11364      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11365      * for the callback function. Defaults to the browser window.</li>
11366      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11367      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11368      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11369      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11370      * params for the post data. Any params will be appended to the URL.</li>
11371      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11372      * </ul>
11373      * @return {Number} transactionId
11374      */
11375     request : function(o){
11376         if(this.fireEvent("beforerequest", this, o) !== false){
11377             var p = o.params;
11378
11379             if(typeof p == "function"){
11380                 p = p.call(o.scope||window, o);
11381             }
11382             if(typeof p == "object"){
11383                 p = Roo.urlEncode(o.params);
11384             }
11385             if(this.extraParams){
11386                 var extras = Roo.urlEncode(this.extraParams);
11387                 p = p ? (p + '&' + extras) : extras;
11388             }
11389
11390             var url = o.url || this.url;
11391             if(typeof url == 'function'){
11392                 url = url.call(o.scope||window, o);
11393             }
11394
11395             if(o.form){
11396                 var form = Roo.getDom(o.form);
11397                 url = url || form.action;
11398
11399                 var enctype = form.getAttribute("enctype");
11400                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11401                     return this.doFormUpload(o, p, url);
11402                 }
11403                 var f = Roo.lib.Ajax.serializeForm(form);
11404                 p = p ? (p + '&' + f) : f;
11405             }
11406
11407             var hs = o.headers;
11408             if(this.defaultHeaders){
11409                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11410                 if(!o.headers){
11411                     o.headers = hs;
11412                 }
11413             }
11414
11415             var cb = {
11416                 success: this.handleResponse,
11417                 failure: this.handleFailure,
11418                 scope: this,
11419                 argument: {options: o},
11420                 timeout : o.timeout || this.timeout
11421             };
11422
11423             var method = o.method||this.method||(p ? "POST" : "GET");
11424
11425             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11426                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11427             }
11428
11429             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11430                 if(o.autoAbort){
11431                     this.abort();
11432                 }
11433             }else if(this.autoAbort !== false){
11434                 this.abort();
11435             }
11436
11437             if((method == 'GET' && p) || o.xmlData){
11438                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11439                 p = '';
11440             }
11441             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11442             return this.transId;
11443         }else{
11444             Roo.callback(o.callback, o.scope, [o, null, null]);
11445             return null;
11446         }
11447     },
11448
11449     /**
11450      * Determine whether this object has a request outstanding.
11451      * @param {Number} transactionId (Optional) defaults to the last transaction
11452      * @return {Boolean} True if there is an outstanding request.
11453      */
11454     isLoading : function(transId){
11455         if(transId){
11456             return Roo.lib.Ajax.isCallInProgress(transId);
11457         }else{
11458             return this.transId ? true : false;
11459         }
11460     },
11461
11462     /**
11463      * Aborts any outstanding request.
11464      * @param {Number} transactionId (Optional) defaults to the last transaction
11465      */
11466     abort : function(transId){
11467         if(transId || this.isLoading()){
11468             Roo.lib.Ajax.abort(transId || this.transId);
11469         }
11470     },
11471
11472     // private
11473     handleResponse : function(response){
11474         this.transId = false;
11475         var options = response.argument.options;
11476         response.argument = options ? options.argument : null;
11477         this.fireEvent("requestcomplete", this, response, options);
11478         Roo.callback(options.success, options.scope, [response, options]);
11479         Roo.callback(options.callback, options.scope, [options, true, response]);
11480     },
11481
11482     // private
11483     handleFailure : function(response, e){
11484         this.transId = false;
11485         var options = response.argument.options;
11486         response.argument = options ? options.argument : null;
11487         this.fireEvent("requestexception", this, response, options, e);
11488         Roo.callback(options.failure, options.scope, [response, options]);
11489         Roo.callback(options.callback, options.scope, [options, false, response]);
11490     },
11491
11492     // private
11493     doFormUpload : function(o, ps, url){
11494         var id = Roo.id();
11495         var frame = document.createElement('iframe');
11496         frame.id = id;
11497         frame.name = id;
11498         frame.className = 'x-hidden';
11499         if(Roo.isIE){
11500             frame.src = Roo.SSL_SECURE_URL;
11501         }
11502         document.body.appendChild(frame);
11503
11504         if(Roo.isIE){
11505            document.frames[id].name = id;
11506         }
11507
11508         var form = Roo.getDom(o.form);
11509         form.target = id;
11510         form.method = 'POST';
11511         form.enctype = form.encoding = 'multipart/form-data';
11512         if(url){
11513             form.action = url;
11514         }
11515
11516         var hiddens, hd;
11517         if(ps){ // add dynamic params
11518             hiddens = [];
11519             ps = Roo.urlDecode(ps, false);
11520             for(var k in ps){
11521                 if(ps.hasOwnProperty(k)){
11522                     hd = document.createElement('input');
11523                     hd.type = 'hidden';
11524                     hd.name = k;
11525                     hd.value = ps[k];
11526                     form.appendChild(hd);
11527                     hiddens.push(hd);
11528                 }
11529             }
11530         }
11531
11532         function cb(){
11533             var r = {  // bogus response object
11534                 responseText : '',
11535                 responseXML : null
11536             };
11537
11538             r.argument = o ? o.argument : null;
11539
11540             try { //
11541                 var doc;
11542                 if(Roo.isIE){
11543                     doc = frame.contentWindow.document;
11544                 }else {
11545                     doc = (frame.contentDocument || window.frames[id].document);
11546                 }
11547                 if(doc && doc.body){
11548                     r.responseText = doc.body.innerHTML;
11549                 }
11550                 if(doc && doc.XMLDocument){
11551                     r.responseXML = doc.XMLDocument;
11552                 }else {
11553                     r.responseXML = doc;
11554                 }
11555             }
11556             catch(e) {
11557                 // ignore
11558             }
11559
11560             Roo.EventManager.removeListener(frame, 'load', cb, this);
11561
11562             this.fireEvent("requestcomplete", this, r, o);
11563             Roo.callback(o.success, o.scope, [r, o]);
11564             Roo.callback(o.callback, o.scope, [o, true, r]);
11565
11566             setTimeout(function(){document.body.removeChild(frame);}, 100);
11567         }
11568
11569         Roo.EventManager.on(frame, 'load', cb, this);
11570         form.submit();
11571
11572         if(hiddens){ // remove dynamic params
11573             for(var i = 0, len = hiddens.length; i < len; i++){
11574                 form.removeChild(hiddens[i]);
11575             }
11576         }
11577     }
11578 });
11579 /*
11580  * Based on:
11581  * Ext JS Library 1.1.1
11582  * Copyright(c) 2006-2007, Ext JS, LLC.
11583  *
11584  * Originally Released Under LGPL - original licence link has changed is not relivant.
11585  *
11586  * Fork - LGPL
11587  * <script type="text/javascript">
11588  */
11589  
11590 /**
11591  * Global Ajax request class.
11592  * 
11593  * @class Roo.Ajax
11594  * @extends Roo.data.Connection
11595  * @static
11596  * 
11597  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11598  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11599  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11600  * @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)
11601  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11602  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11603  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11604  */
11605 Roo.Ajax = new Roo.data.Connection({
11606     // fix up the docs
11607     /**
11608      * @scope Roo.Ajax
11609      * @type {Boolear} 
11610      */
11611     autoAbort : false,
11612
11613     /**
11614      * Serialize the passed form into a url encoded string
11615      * @scope Roo.Ajax
11616      * @param {String/HTMLElement} form
11617      * @return {String}
11618      */
11619     serializeForm : function(form){
11620         return Roo.lib.Ajax.serializeForm(form);
11621     }
11622 });/*
11623  * Based on:
11624  * Ext JS Library 1.1.1
11625  * Copyright(c) 2006-2007, Ext JS, LLC.
11626  *
11627  * Originally Released Under LGPL - original licence link has changed is not relivant.
11628  *
11629  * Fork - LGPL
11630  * <script type="text/javascript">
11631  */
11632
11633  
11634 /**
11635  * @class Roo.UpdateManager
11636  * @extends Roo.util.Observable
11637  * Provides AJAX-style update for Element object.<br><br>
11638  * Usage:<br>
11639  * <pre><code>
11640  * // Get it from a Roo.Element object
11641  * var el = Roo.get("foo");
11642  * var mgr = el.getUpdateManager();
11643  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11644  * ...
11645  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11646  * <br>
11647  * // or directly (returns the same UpdateManager instance)
11648  * var mgr = new Roo.UpdateManager("myElementId");
11649  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11650  * mgr.on("update", myFcnNeedsToKnow);
11651  * <br>
11652    // short handed call directly from the element object
11653    Roo.get("foo").load({
11654         url: "bar.php",
11655         scripts:true,
11656         params: "for=bar",
11657         text: "Loading Foo..."
11658    });
11659  * </code></pre>
11660  * @constructor
11661  * Create new UpdateManager directly.
11662  * @param {String/HTMLElement/Roo.Element} el The element to update
11663  * @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).
11664  */
11665 Roo.UpdateManager = function(el, forceNew){
11666     el = Roo.get(el);
11667     if(!forceNew && el.updateManager){
11668         return el.updateManager;
11669     }
11670     /**
11671      * The Element object
11672      * @type Roo.Element
11673      */
11674     this.el = el;
11675     /**
11676      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11677      * @type String
11678      */
11679     this.defaultUrl = null;
11680
11681     this.addEvents({
11682         /**
11683          * @event beforeupdate
11684          * Fired before an update is made, return false from your handler and the update is cancelled.
11685          * @param {Roo.Element} el
11686          * @param {String/Object/Function} url
11687          * @param {String/Object} params
11688          */
11689         "beforeupdate": true,
11690         /**
11691          * @event update
11692          * Fired after successful update is made.
11693          * @param {Roo.Element} el
11694          * @param {Object} oResponseObject The response Object
11695          */
11696         "update": true,
11697         /**
11698          * @event failure
11699          * Fired on update failure.
11700          * @param {Roo.Element} el
11701          * @param {Object} oResponseObject The response Object
11702          */
11703         "failure": true
11704     });
11705     var d = Roo.UpdateManager.defaults;
11706     /**
11707      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11708      * @type String
11709      */
11710     this.sslBlankUrl = d.sslBlankUrl;
11711     /**
11712      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11713      * @type Boolean
11714      */
11715     this.disableCaching = d.disableCaching;
11716     /**
11717      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11718      * @type String
11719      */
11720     this.indicatorText = d.indicatorText;
11721     /**
11722      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11723      * @type String
11724      */
11725     this.showLoadIndicator = d.showLoadIndicator;
11726     /**
11727      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11728      * @type Number
11729      */
11730     this.timeout = d.timeout;
11731
11732     /**
11733      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11734      * @type Boolean
11735      */
11736     this.loadScripts = d.loadScripts;
11737
11738     /**
11739      * Transaction object of current executing transaction
11740      */
11741     this.transaction = null;
11742
11743     /**
11744      * @private
11745      */
11746     this.autoRefreshProcId = null;
11747     /**
11748      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11749      * @type Function
11750      */
11751     this.refreshDelegate = this.refresh.createDelegate(this);
11752     /**
11753      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11754      * @type Function
11755      */
11756     this.updateDelegate = this.update.createDelegate(this);
11757     /**
11758      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11759      * @type Function
11760      */
11761     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11762     /**
11763      * @private
11764      */
11765     this.successDelegate = this.processSuccess.createDelegate(this);
11766     /**
11767      * @private
11768      */
11769     this.failureDelegate = this.processFailure.createDelegate(this);
11770
11771     if(!this.renderer){
11772      /**
11773       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11774       */
11775     this.renderer = new Roo.UpdateManager.BasicRenderer();
11776     }
11777     
11778     Roo.UpdateManager.superclass.constructor.call(this);
11779 };
11780
11781 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11782     /**
11783      * Get the Element this UpdateManager is bound to
11784      * @return {Roo.Element} The element
11785      */
11786     getEl : function(){
11787         return this.el;
11788     },
11789     /**
11790      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11791      * @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:
11792 <pre><code>
11793 um.update({<br/>
11794     url: "your-url.php",<br/>
11795     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11796     callback: yourFunction,<br/>
11797     scope: yourObject, //(optional scope)  <br/>
11798     discardUrl: false, <br/>
11799     nocache: false,<br/>
11800     text: "Loading...",<br/>
11801     timeout: 30,<br/>
11802     scripts: false<br/>
11803 });
11804 </code></pre>
11805      * The only required property is url. The optional properties nocache, text and scripts
11806      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11807      * @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}
11808      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11809      * @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.
11810      */
11811     update : function(url, params, callback, discardUrl){
11812         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11813             var method = this.method,
11814                 cfg;
11815             if(typeof url == "object"){ // must be config object
11816                 cfg = url;
11817                 url = cfg.url;
11818                 params = params || cfg.params;
11819                 callback = callback || cfg.callback;
11820                 discardUrl = discardUrl || cfg.discardUrl;
11821                 if(callback && cfg.scope){
11822                     callback = callback.createDelegate(cfg.scope);
11823                 }
11824                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11825                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11826                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11827                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11828                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11829             }
11830             this.showLoading();
11831             if(!discardUrl){
11832                 this.defaultUrl = url;
11833             }
11834             if(typeof url == "function"){
11835                 url = url.call(this);
11836             }
11837
11838             method = method || (params ? "POST" : "GET");
11839             if(method == "GET"){
11840                 url = this.prepareUrl(url);
11841             }
11842
11843             var o = Roo.apply(cfg ||{}, {
11844                 url : url,
11845                 params: params,
11846                 success: this.successDelegate,
11847                 failure: this.failureDelegate,
11848                 callback: undefined,
11849                 timeout: (this.timeout*1000),
11850                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11851             });
11852             Roo.log("updated manager called with timeout of " + o.timeout);
11853             this.transaction = Roo.Ajax.request(o);
11854         }
11855     },
11856
11857     /**
11858      * 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.
11859      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11860      * @param {String/HTMLElement} form The form Id or form element
11861      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11862      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11863      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11864      */
11865     formUpdate : function(form, url, reset, callback){
11866         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11867             if(typeof url == "function"){
11868                 url = url.call(this);
11869             }
11870             form = Roo.getDom(form);
11871             this.transaction = Roo.Ajax.request({
11872                 form: form,
11873                 url:url,
11874                 success: this.successDelegate,
11875                 failure: this.failureDelegate,
11876                 timeout: (this.timeout*1000),
11877                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11878             });
11879             this.showLoading.defer(1, this);
11880         }
11881     },
11882
11883     /**
11884      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11885      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11886      */
11887     refresh : function(callback){
11888         if(this.defaultUrl == null){
11889             return;
11890         }
11891         this.update(this.defaultUrl, null, callback, true);
11892     },
11893
11894     /**
11895      * Set this element to auto refresh.
11896      * @param {Number} interval How often to update (in seconds).
11897      * @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)
11898      * @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}
11899      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11900      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11901      */
11902     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11903         if(refreshNow){
11904             this.update(url || this.defaultUrl, params, callback, true);
11905         }
11906         if(this.autoRefreshProcId){
11907             clearInterval(this.autoRefreshProcId);
11908         }
11909         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11910     },
11911
11912     /**
11913      * Stop auto refresh on this element.
11914      */
11915      stopAutoRefresh : function(){
11916         if(this.autoRefreshProcId){
11917             clearInterval(this.autoRefreshProcId);
11918             delete this.autoRefreshProcId;
11919         }
11920     },
11921
11922     isAutoRefreshing : function(){
11923        return this.autoRefreshProcId ? true : false;
11924     },
11925     /**
11926      * Called to update the element to "Loading" state. Override to perform custom action.
11927      */
11928     showLoading : function(){
11929         if(this.showLoadIndicator){
11930             this.el.update(this.indicatorText);
11931         }
11932     },
11933
11934     /**
11935      * Adds unique parameter to query string if disableCaching = true
11936      * @private
11937      */
11938     prepareUrl : function(url){
11939         if(this.disableCaching){
11940             var append = "_dc=" + (new Date().getTime());
11941             if(url.indexOf("?") !== -1){
11942                 url += "&" + append;
11943             }else{
11944                 url += "?" + append;
11945             }
11946         }
11947         return url;
11948     },
11949
11950     /**
11951      * @private
11952      */
11953     processSuccess : function(response){
11954         this.transaction = null;
11955         if(response.argument.form && response.argument.reset){
11956             try{ // put in try/catch since some older FF releases had problems with this
11957                 response.argument.form.reset();
11958             }catch(e){}
11959         }
11960         if(this.loadScripts){
11961             this.renderer.render(this.el, response, this,
11962                 this.updateComplete.createDelegate(this, [response]));
11963         }else{
11964             this.renderer.render(this.el, response, this);
11965             this.updateComplete(response);
11966         }
11967     },
11968
11969     updateComplete : function(response){
11970         this.fireEvent("update", this.el, response);
11971         if(typeof response.argument.callback == "function"){
11972             response.argument.callback(this.el, true, response);
11973         }
11974     },
11975
11976     /**
11977      * @private
11978      */
11979     processFailure : function(response){
11980         this.transaction = null;
11981         this.fireEvent("failure", this.el, response);
11982         if(typeof response.argument.callback == "function"){
11983             response.argument.callback(this.el, false, response);
11984         }
11985     },
11986
11987     /**
11988      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11989      * @param {Object} renderer The object implementing the render() method
11990      */
11991     setRenderer : function(renderer){
11992         this.renderer = renderer;
11993     },
11994
11995     getRenderer : function(){
11996        return this.renderer;
11997     },
11998
11999     /**
12000      * Set the defaultUrl used for updates
12001      * @param {String/Function} defaultUrl The url or a function to call to get the url
12002      */
12003     setDefaultUrl : function(defaultUrl){
12004         this.defaultUrl = defaultUrl;
12005     },
12006
12007     /**
12008      * Aborts the executing transaction
12009      */
12010     abort : function(){
12011         if(this.transaction){
12012             Roo.Ajax.abort(this.transaction);
12013         }
12014     },
12015
12016     /**
12017      * Returns true if an update is in progress
12018      * @return {Boolean}
12019      */
12020     isUpdating : function(){
12021         if(this.transaction){
12022             return Roo.Ajax.isLoading(this.transaction);
12023         }
12024         return false;
12025     }
12026 });
12027
12028 /**
12029  * @class Roo.UpdateManager.defaults
12030  * @static (not really - but it helps the doc tool)
12031  * The defaults collection enables customizing the default properties of UpdateManager
12032  */
12033    Roo.UpdateManager.defaults = {
12034        /**
12035          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12036          * @type Number
12037          */
12038          timeout : 30,
12039
12040          /**
12041          * True to process scripts by default (Defaults to false).
12042          * @type Boolean
12043          */
12044         loadScripts : false,
12045
12046         /**
12047         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12048         * @type String
12049         */
12050         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12051         /**
12052          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12053          * @type Boolean
12054          */
12055         disableCaching : false,
12056         /**
12057          * Whether to show indicatorText when loading (Defaults to true).
12058          * @type Boolean
12059          */
12060         showLoadIndicator : true,
12061         /**
12062          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12063          * @type String
12064          */
12065         indicatorText : '<div class="loading-indicator">Loading...</div>'
12066    };
12067
12068 /**
12069  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12070  *Usage:
12071  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12072  * @param {String/HTMLElement/Roo.Element} el The element to update
12073  * @param {String} url The url
12074  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12075  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12076  * @static
12077  * @deprecated
12078  * @member Roo.UpdateManager
12079  */
12080 Roo.UpdateManager.updateElement = function(el, url, params, options){
12081     var um = Roo.get(el, true).getUpdateManager();
12082     Roo.apply(um, options);
12083     um.update(url, params, options ? options.callback : null);
12084 };
12085 // alias for backwards compat
12086 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12087 /**
12088  * @class Roo.UpdateManager.BasicRenderer
12089  * Default Content renderer. Updates the elements innerHTML with the responseText.
12090  */
12091 Roo.UpdateManager.BasicRenderer = function(){};
12092
12093 Roo.UpdateManager.BasicRenderer.prototype = {
12094     /**
12095      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12096      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12097      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12098      * @param {Roo.Element} el The element being rendered
12099      * @param {Object} response The YUI Connect response object
12100      * @param {UpdateManager} updateManager The calling update manager
12101      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12102      */
12103      render : function(el, response, updateManager, callback){
12104         el.update(response.responseText, updateManager.loadScripts, callback);
12105     }
12106 };
12107 /*
12108  * Based on:
12109  * Roo JS
12110  * (c)) Alan Knowles
12111  * Licence : LGPL
12112  */
12113
12114
12115 /**
12116  * @class Roo.DomTemplate
12117  * @extends Roo.Template
12118  * An effort at a dom based template engine..
12119  *
12120  * Similar to XTemplate, except it uses dom parsing to create the template..
12121  *
12122  * Supported features:
12123  *
12124  *  Tags:
12125
12126 <pre><code>
12127       {a_variable} - output encoded.
12128       {a_variable.format:("Y-m-d")} - call a method on the variable
12129       {a_variable:raw} - unencoded output
12130       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12131       {a_variable:this.method_on_template(...)} - call a method on the template object.
12132  
12133 </code></pre>
12134  *  The tpl tag:
12135 <pre><code>
12136         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12137         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12138         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12139         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12140   
12141 </code></pre>
12142  *      
12143  */
12144 Roo.DomTemplate = function()
12145 {
12146      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12147      if (this.html) {
12148         this.compile();
12149      }
12150 };
12151
12152
12153 Roo.extend(Roo.DomTemplate, Roo.Template, {
12154     /**
12155      * id counter for sub templates.
12156      */
12157     id : 0,
12158     /**
12159      * flag to indicate if dom parser is inside a pre,
12160      * it will strip whitespace if not.
12161      */
12162     inPre : false,
12163     
12164     /**
12165      * The various sub templates
12166      */
12167     tpls : false,
12168     
12169     
12170     
12171     /**
12172      *
12173      * basic tag replacing syntax
12174      * WORD:WORD()
12175      *
12176      * // you can fake an object call by doing this
12177      *  x.t:(test,tesT) 
12178      * 
12179      */
12180     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12181     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12182     
12183     iterChild : function (node, method) {
12184         
12185         var oldPre = this.inPre;
12186         if (node.tagName == 'PRE') {
12187             this.inPre = true;
12188         }
12189         for( var i = 0; i < node.childNodes.length; i++) {
12190             method.call(this, node.childNodes[i]);
12191         }
12192         this.inPre = oldPre;
12193     },
12194     
12195     
12196     
12197     /**
12198      * compile the template
12199      *
12200      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12201      *
12202      */
12203     compile: function()
12204     {
12205         var s = this.html;
12206         
12207         // covert the html into DOM...
12208         var doc = false;
12209         var div =false;
12210         try {
12211             doc = document.implementation.createHTMLDocument("");
12212             doc.documentElement.innerHTML =   this.html  ;
12213             div = doc.documentElement;
12214         } catch (e) {
12215             // old IE... - nasty -- it causes all sorts of issues.. with
12216             // images getting pulled from server..
12217             div = document.createElement('div');
12218             div.innerHTML = this.html;
12219         }
12220         //doc.documentElement.innerHTML = htmlBody
12221          
12222         
12223         
12224         this.tpls = [];
12225         var _t = this;
12226         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12227         
12228         var tpls = this.tpls;
12229         
12230         // create a top level template from the snippet..
12231         
12232         //Roo.log(div.innerHTML);
12233         
12234         var tpl = {
12235             uid : 'master',
12236             id : this.id++,
12237             attr : false,
12238             value : false,
12239             body : div.innerHTML,
12240             
12241             forCall : false,
12242             execCall : false,
12243             dom : div,
12244             isTop : true
12245             
12246         };
12247         tpls.unshift(tpl);
12248         
12249         
12250         // compile them...
12251         this.tpls = [];
12252         Roo.each(tpls, function(tp){
12253             this.compileTpl(tp);
12254             this.tpls[tp.id] = tp;
12255         }, this);
12256         
12257         this.master = tpls[0];
12258         return this;
12259         
12260         
12261     },
12262     
12263     compileNode : function(node, istop) {
12264         // test for
12265         //Roo.log(node);
12266         
12267         
12268         // skip anything not a tag..
12269         if (node.nodeType != 1) {
12270             if (node.nodeType == 3 && !this.inPre) {
12271                 // reduce white space..
12272                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12273                 
12274             }
12275             return;
12276         }
12277         
12278         var tpl = {
12279             uid : false,
12280             id : false,
12281             attr : false,
12282             value : false,
12283             body : '',
12284             
12285             forCall : false,
12286             execCall : false,
12287             dom : false,
12288             isTop : istop
12289             
12290             
12291         };
12292         
12293         
12294         switch(true) {
12295             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12296             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12297             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12298             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12299             // no default..
12300         }
12301         
12302         
12303         if (!tpl.attr) {
12304             // just itterate children..
12305             this.iterChild(node,this.compileNode);
12306             return;
12307         }
12308         tpl.uid = this.id++;
12309         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12310         node.removeAttribute('roo-'+ tpl.attr);
12311         if (tpl.attr != 'name') {
12312             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12313             node.parentNode.replaceChild(placeholder,  node);
12314         } else {
12315             
12316             var placeholder =  document.createElement('span');
12317             placeholder.className = 'roo-tpl-' + tpl.value;
12318             node.parentNode.replaceChild(placeholder,  node);
12319         }
12320         
12321         // parent now sees '{domtplXXXX}
12322         this.iterChild(node,this.compileNode);
12323         
12324         // we should now have node body...
12325         var div = document.createElement('div');
12326         div.appendChild(node);
12327         tpl.dom = node;
12328         // this has the unfortunate side effect of converting tagged attributes
12329         // eg. href="{...}" into %7C...%7D
12330         // this has been fixed by searching for those combo's although it's a bit hacky..
12331         
12332         
12333         tpl.body = div.innerHTML;
12334         
12335         
12336          
12337         tpl.id = tpl.uid;
12338         switch(tpl.attr) {
12339             case 'for' :
12340                 switch (tpl.value) {
12341                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12342                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12343                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12344                 }
12345                 break;
12346             
12347             case 'exec':
12348                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12349                 break;
12350             
12351             case 'if':     
12352                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12353                 break;
12354             
12355             case 'name':
12356                 tpl.id  = tpl.value; // replace non characters???
12357                 break;
12358             
12359         }
12360         
12361         
12362         this.tpls.push(tpl);
12363         
12364         
12365         
12366     },
12367     
12368     
12369     
12370     
12371     /**
12372      * Compile a segment of the template into a 'sub-template'
12373      *
12374      * 
12375      * 
12376      *
12377      */
12378     compileTpl : function(tpl)
12379     {
12380         var fm = Roo.util.Format;
12381         var useF = this.disableFormats !== true;
12382         
12383         var sep = Roo.isGecko ? "+\n" : ",\n";
12384         
12385         var undef = function(str) {
12386             Roo.debug && Roo.log("Property not found :"  + str);
12387             return '';
12388         };
12389           
12390         //Roo.log(tpl.body);
12391         
12392         
12393         
12394         var fn = function(m, lbrace, name, format, args)
12395         {
12396             //Roo.log("ARGS");
12397             //Roo.log(arguments);
12398             args = args ? args.replace(/\\'/g,"'") : args;
12399             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12400             if (typeof(format) == 'undefined') {
12401                 format =  'htmlEncode'; 
12402             }
12403             if (format == 'raw' ) {
12404                 format = false;
12405             }
12406             
12407             if(name.substr(0, 6) == 'domtpl'){
12408                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12409             }
12410             
12411             // build an array of options to determine if value is undefined..
12412             
12413             // basically get 'xxxx.yyyy' then do
12414             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12415             //    (function () { Roo.log("Property not found"); return ''; })() :
12416             //    ......
12417             
12418             var udef_ar = [];
12419             var lookfor = '';
12420             Roo.each(name.split('.'), function(st) {
12421                 lookfor += (lookfor.length ? '.': '') + st;
12422                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12423             });
12424             
12425             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12426             
12427             
12428             if(format && useF){
12429                 
12430                 args = args ? ',' + args : "";
12431                  
12432                 if(format.substr(0, 5) != "this."){
12433                     format = "fm." + format + '(';
12434                 }else{
12435                     format = 'this.call("'+ format.substr(5) + '", ';
12436                     args = ", values";
12437                 }
12438                 
12439                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12440             }
12441              
12442             if (args && args.length) {
12443                 // called with xxyx.yuu:(test,test)
12444                 // change to ()
12445                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12446             }
12447             // raw.. - :raw modifier..
12448             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12449             
12450         };
12451         var body;
12452         // branched to use + in gecko and [].join() in others
12453         if(Roo.isGecko){
12454             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12455                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12456                     "';};};";
12457         }else{
12458             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12459             body.push(tpl.body.replace(/(\r\n|\n)/g,
12460                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12461             body.push("'].join('');};};");
12462             body = body.join('');
12463         }
12464         
12465         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12466        
12467         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12468         eval(body);
12469         
12470         return this;
12471     },
12472      
12473     /**
12474      * same as applyTemplate, except it's done to one of the subTemplates
12475      * when using named templates, you can do:
12476      *
12477      * var str = pl.applySubTemplate('your-name', values);
12478      *
12479      * 
12480      * @param {Number} id of the template
12481      * @param {Object} values to apply to template
12482      * @param {Object} parent (normaly the instance of this object)
12483      */
12484     applySubTemplate : function(id, values, parent)
12485     {
12486         
12487         
12488         var t = this.tpls[id];
12489         
12490         
12491         try { 
12492             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12493                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12494                 return '';
12495             }
12496         } catch(e) {
12497             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12498             Roo.log(values);
12499           
12500             return '';
12501         }
12502         try { 
12503             
12504             if(t.execCall && t.execCall.call(this, values, parent)){
12505                 return '';
12506             }
12507         } catch(e) {
12508             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12509             Roo.log(values);
12510             return '';
12511         }
12512         
12513         try {
12514             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12515             parent = t.target ? values : parent;
12516             if(t.forCall && vs instanceof Array){
12517                 var buf = [];
12518                 for(var i = 0, len = vs.length; i < len; i++){
12519                     try {
12520                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12521                     } catch (e) {
12522                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12523                         Roo.log(e.body);
12524                         //Roo.log(t.compiled);
12525                         Roo.log(vs[i]);
12526                     }   
12527                 }
12528                 return buf.join('');
12529             }
12530         } catch (e) {
12531             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12532             Roo.log(values);
12533             return '';
12534         }
12535         try {
12536             return t.compiled.call(this, vs, parent);
12537         } catch (e) {
12538             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12539             Roo.log(e.body);
12540             //Roo.log(t.compiled);
12541             Roo.log(values);
12542             return '';
12543         }
12544     },
12545
12546    
12547
12548     applyTemplate : function(values){
12549         return this.master.compiled.call(this, values, {});
12550         //var s = this.subs;
12551     },
12552
12553     apply : function(){
12554         return this.applyTemplate.apply(this, arguments);
12555     }
12556
12557  });
12558
12559 Roo.DomTemplate.from = function(el){
12560     el = Roo.getDom(el);
12561     return new Roo.Domtemplate(el.value || el.innerHTML);
12562 };/*
12563  * Based on:
12564  * Ext JS Library 1.1.1
12565  * Copyright(c) 2006-2007, Ext JS, LLC.
12566  *
12567  * Originally Released Under LGPL - original licence link has changed is not relivant.
12568  *
12569  * Fork - LGPL
12570  * <script type="text/javascript">
12571  */
12572
12573 /**
12574  * @class Roo.util.DelayedTask
12575  * Provides a convenient method of performing setTimeout where a new
12576  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12577  * You can use this class to buffer
12578  * the keypress events for a certain number of milliseconds, and perform only if they stop
12579  * for that amount of time.
12580  * @constructor The parameters to this constructor serve as defaults and are not required.
12581  * @param {Function} fn (optional) The default function to timeout
12582  * @param {Object} scope (optional) The default scope of that timeout
12583  * @param {Array} args (optional) The default Array of arguments
12584  */
12585 Roo.util.DelayedTask = function(fn, scope, args){
12586     var id = null, d, t;
12587
12588     var call = function(){
12589         var now = new Date().getTime();
12590         if(now - t >= d){
12591             clearInterval(id);
12592             id = null;
12593             fn.apply(scope, args || []);
12594         }
12595     };
12596     /**
12597      * Cancels any pending timeout and queues a new one
12598      * @param {Number} delay The milliseconds to delay
12599      * @param {Function} newFn (optional) Overrides function passed to constructor
12600      * @param {Object} newScope (optional) Overrides scope passed to constructor
12601      * @param {Array} newArgs (optional) Overrides args passed to constructor
12602      */
12603     this.delay = function(delay, newFn, newScope, newArgs){
12604         if(id && delay != d){
12605             this.cancel();
12606         }
12607         d = delay;
12608         t = new Date().getTime();
12609         fn = newFn || fn;
12610         scope = newScope || scope;
12611         args = newArgs || args;
12612         if(!id){
12613             id = setInterval(call, d);
12614         }
12615     };
12616
12617     /**
12618      * Cancel the last queued timeout
12619      */
12620     this.cancel = function(){
12621         if(id){
12622             clearInterval(id);
12623             id = null;
12624         }
12625     };
12626 };/*
12627  * Based on:
12628  * Ext JS Library 1.1.1
12629  * Copyright(c) 2006-2007, Ext JS, LLC.
12630  *
12631  * Originally Released Under LGPL - original licence link has changed is not relivant.
12632  *
12633  * Fork - LGPL
12634  * <script type="text/javascript">
12635  */
12636  
12637  
12638 Roo.util.TaskRunner = function(interval){
12639     interval = interval || 10;
12640     var tasks = [], removeQueue = [];
12641     var id = 0;
12642     var running = false;
12643
12644     var stopThread = function(){
12645         running = false;
12646         clearInterval(id);
12647         id = 0;
12648     };
12649
12650     var startThread = function(){
12651         if(!running){
12652             running = true;
12653             id = setInterval(runTasks, interval);
12654         }
12655     };
12656
12657     var removeTask = function(task){
12658         removeQueue.push(task);
12659         if(task.onStop){
12660             task.onStop();
12661         }
12662     };
12663
12664     var runTasks = function(){
12665         if(removeQueue.length > 0){
12666             for(var i = 0, len = removeQueue.length; i < len; i++){
12667                 tasks.remove(removeQueue[i]);
12668             }
12669             removeQueue = [];
12670             if(tasks.length < 1){
12671                 stopThread();
12672                 return;
12673             }
12674         }
12675         var now = new Date().getTime();
12676         for(var i = 0, len = tasks.length; i < len; ++i){
12677             var t = tasks[i];
12678             var itime = now - t.taskRunTime;
12679             if(t.interval <= itime){
12680                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12681                 t.taskRunTime = now;
12682                 if(rt === false || t.taskRunCount === t.repeat){
12683                     removeTask(t);
12684                     return;
12685                 }
12686             }
12687             if(t.duration && t.duration <= (now - t.taskStartTime)){
12688                 removeTask(t);
12689             }
12690         }
12691     };
12692
12693     /**
12694      * Queues a new task.
12695      * @param {Object} task
12696      */
12697     this.start = function(task){
12698         tasks.push(task);
12699         task.taskStartTime = new Date().getTime();
12700         task.taskRunTime = 0;
12701         task.taskRunCount = 0;
12702         startThread();
12703         return task;
12704     };
12705
12706     this.stop = function(task){
12707         removeTask(task);
12708         return task;
12709     };
12710
12711     this.stopAll = function(){
12712         stopThread();
12713         for(var i = 0, len = tasks.length; i < len; i++){
12714             if(tasks[i].onStop){
12715                 tasks[i].onStop();
12716             }
12717         }
12718         tasks = [];
12719         removeQueue = [];
12720     };
12721 };
12722
12723 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12724  * Based on:
12725  * Ext JS Library 1.1.1
12726  * Copyright(c) 2006-2007, Ext JS, LLC.
12727  *
12728  * Originally Released Under LGPL - original licence link has changed is not relivant.
12729  *
12730  * Fork - LGPL
12731  * <script type="text/javascript">
12732  */
12733
12734  
12735 /**
12736  * @class Roo.util.MixedCollection
12737  * @extends Roo.util.Observable
12738  * A Collection class that maintains both numeric indexes and keys and exposes events.
12739  * @constructor
12740  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12741  * collection (defaults to false)
12742  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12743  * and return the key value for that item.  This is used when available to look up the key on items that
12744  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12745  * equivalent to providing an implementation for the {@link #getKey} method.
12746  */
12747 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12748     this.items = [];
12749     this.map = {};
12750     this.keys = [];
12751     this.length = 0;
12752     this.addEvents({
12753         /**
12754          * @event clear
12755          * Fires when the collection is cleared.
12756          */
12757         "clear" : true,
12758         /**
12759          * @event add
12760          * Fires when an item is added to the collection.
12761          * @param {Number} index The index at which the item was added.
12762          * @param {Object} o The item added.
12763          * @param {String} key The key associated with the added item.
12764          */
12765         "add" : true,
12766         /**
12767          * @event replace
12768          * Fires when an item is replaced in the collection.
12769          * @param {String} key he key associated with the new added.
12770          * @param {Object} old The item being replaced.
12771          * @param {Object} new The new item.
12772          */
12773         "replace" : true,
12774         /**
12775          * @event remove
12776          * Fires when an item is removed from the collection.
12777          * @param {Object} o The item being removed.
12778          * @param {String} key (optional) The key associated with the removed item.
12779          */
12780         "remove" : true,
12781         "sort" : true
12782     });
12783     this.allowFunctions = allowFunctions === true;
12784     if(keyFn){
12785         this.getKey = keyFn;
12786     }
12787     Roo.util.MixedCollection.superclass.constructor.call(this);
12788 };
12789
12790 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12791     allowFunctions : false,
12792     
12793 /**
12794  * Adds an item to the collection.
12795  * @param {String} key The key to associate with the item
12796  * @param {Object} o The item to add.
12797  * @return {Object} The item added.
12798  */
12799     add : function(key, o){
12800         if(arguments.length == 1){
12801             o = arguments[0];
12802             key = this.getKey(o);
12803         }
12804         if(typeof key == "undefined" || key === null){
12805             this.length++;
12806             this.items.push(o);
12807             this.keys.push(null);
12808         }else{
12809             var old = this.map[key];
12810             if(old){
12811                 return this.replace(key, o);
12812             }
12813             this.length++;
12814             this.items.push(o);
12815             this.map[key] = o;
12816             this.keys.push(key);
12817         }
12818         this.fireEvent("add", this.length-1, o, key);
12819         return o;
12820     },
12821        
12822 /**
12823   * MixedCollection has a generic way to fetch keys if you implement getKey.
12824 <pre><code>
12825 // normal way
12826 var mc = new Roo.util.MixedCollection();
12827 mc.add(someEl.dom.id, someEl);
12828 mc.add(otherEl.dom.id, otherEl);
12829 //and so on
12830
12831 // using getKey
12832 var mc = new Roo.util.MixedCollection();
12833 mc.getKey = function(el){
12834    return el.dom.id;
12835 };
12836 mc.add(someEl);
12837 mc.add(otherEl);
12838
12839 // or via the constructor
12840 var mc = new Roo.util.MixedCollection(false, function(el){
12841    return el.dom.id;
12842 });
12843 mc.add(someEl);
12844 mc.add(otherEl);
12845 </code></pre>
12846  * @param o {Object} The item for which to find the key.
12847  * @return {Object} The key for the passed item.
12848  */
12849     getKey : function(o){
12850          return o.id; 
12851     },
12852    
12853 /**
12854  * Replaces an item in the collection.
12855  * @param {String} key The key associated with the item to replace, or the item to replace.
12856  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12857  * @return {Object}  The new item.
12858  */
12859     replace : function(key, o){
12860         if(arguments.length == 1){
12861             o = arguments[0];
12862             key = this.getKey(o);
12863         }
12864         var old = this.item(key);
12865         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12866              return this.add(key, o);
12867         }
12868         var index = this.indexOfKey(key);
12869         this.items[index] = o;
12870         this.map[key] = o;
12871         this.fireEvent("replace", key, old, o);
12872         return o;
12873     },
12874    
12875 /**
12876  * Adds all elements of an Array or an Object to the collection.
12877  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12878  * an Array of values, each of which are added to the collection.
12879  */
12880     addAll : function(objs){
12881         if(arguments.length > 1 || objs instanceof Array){
12882             var args = arguments.length > 1 ? arguments : objs;
12883             for(var i = 0, len = args.length; i < len; i++){
12884                 this.add(args[i]);
12885             }
12886         }else{
12887             for(var key in objs){
12888                 if(this.allowFunctions || typeof objs[key] != "function"){
12889                     this.add(key, objs[key]);
12890                 }
12891             }
12892         }
12893     },
12894    
12895 /**
12896  * Executes the specified function once for every item in the collection, passing each
12897  * item as the first and only parameter. returning false from the function will stop the iteration.
12898  * @param {Function} fn The function to execute for each item.
12899  * @param {Object} scope (optional) The scope in which to execute the function.
12900  */
12901     each : function(fn, scope){
12902         var items = [].concat(this.items); // each safe for removal
12903         for(var i = 0, len = items.length; i < len; i++){
12904             if(fn.call(scope || items[i], items[i], i, len) === false){
12905                 break;
12906             }
12907         }
12908     },
12909    
12910 /**
12911  * Executes the specified function once for every key in the collection, passing each
12912  * key, and its associated item as the first two parameters.
12913  * @param {Function} fn The function to execute for each item.
12914  * @param {Object} scope (optional) The scope in which to execute the function.
12915  */
12916     eachKey : function(fn, scope){
12917         for(var i = 0, len = this.keys.length; i < len; i++){
12918             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12919         }
12920     },
12921    
12922 /**
12923  * Returns the first item in the collection which elicits a true return value from the
12924  * passed selection function.
12925  * @param {Function} fn The selection function to execute for each item.
12926  * @param {Object} scope (optional) The scope in which to execute the function.
12927  * @return {Object} The first item in the collection which returned true from the selection function.
12928  */
12929     find : function(fn, scope){
12930         for(var i = 0, len = this.items.length; i < len; i++){
12931             if(fn.call(scope || window, this.items[i], this.keys[i])){
12932                 return this.items[i];
12933             }
12934         }
12935         return null;
12936     },
12937    
12938 /**
12939  * Inserts an item at the specified index in the collection.
12940  * @param {Number} index The index to insert the item at.
12941  * @param {String} key The key to associate with the new item, or the item itself.
12942  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12943  * @return {Object} The item inserted.
12944  */
12945     insert : function(index, key, o){
12946         if(arguments.length == 2){
12947             o = arguments[1];
12948             key = this.getKey(o);
12949         }
12950         if(index >= this.length){
12951             return this.add(key, o);
12952         }
12953         this.length++;
12954         this.items.splice(index, 0, o);
12955         if(typeof key != "undefined" && key != null){
12956             this.map[key] = o;
12957         }
12958         this.keys.splice(index, 0, key);
12959         this.fireEvent("add", index, o, key);
12960         return o;
12961     },
12962    
12963 /**
12964  * Removed an item from the collection.
12965  * @param {Object} o The item to remove.
12966  * @return {Object} The item removed.
12967  */
12968     remove : function(o){
12969         return this.removeAt(this.indexOf(o));
12970     },
12971    
12972 /**
12973  * Remove an item from a specified index in the collection.
12974  * @param {Number} index The index within the collection of the item to remove.
12975  */
12976     removeAt : function(index){
12977         if(index < this.length && index >= 0){
12978             this.length--;
12979             var o = this.items[index];
12980             this.items.splice(index, 1);
12981             var key = this.keys[index];
12982             if(typeof key != "undefined"){
12983                 delete this.map[key];
12984             }
12985             this.keys.splice(index, 1);
12986             this.fireEvent("remove", o, key);
12987         }
12988     },
12989    
12990 /**
12991  * Removed an item associated with the passed key fom the collection.
12992  * @param {String} key The key of the item to remove.
12993  */
12994     removeKey : function(key){
12995         return this.removeAt(this.indexOfKey(key));
12996     },
12997    
12998 /**
12999  * Returns the number of items in the collection.
13000  * @return {Number} the number of items in the collection.
13001  */
13002     getCount : function(){
13003         return this.length; 
13004     },
13005    
13006 /**
13007  * Returns index within the collection of the passed Object.
13008  * @param {Object} o The item to find the index of.
13009  * @return {Number} index of the item.
13010  */
13011     indexOf : function(o){
13012         if(!this.items.indexOf){
13013             for(var i = 0, len = this.items.length; i < len; i++){
13014                 if(this.items[i] == o) return i;
13015             }
13016             return -1;
13017         }else{
13018             return this.items.indexOf(o);
13019         }
13020     },
13021    
13022 /**
13023  * Returns index within the collection of the passed key.
13024  * @param {String} key The key to find the index of.
13025  * @return {Number} index of the key.
13026  */
13027     indexOfKey : function(key){
13028         if(!this.keys.indexOf){
13029             for(var i = 0, len = this.keys.length; i < len; i++){
13030                 if(this.keys[i] == key) return i;
13031             }
13032             return -1;
13033         }else{
13034             return this.keys.indexOf(key);
13035         }
13036     },
13037    
13038 /**
13039  * Returns the item associated with the passed key OR index. Key has priority over index.
13040  * @param {String/Number} key The key or index of the item.
13041  * @return {Object} The item associated with the passed key.
13042  */
13043     item : function(key){
13044         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13045         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13046     },
13047     
13048 /**
13049  * Returns the item at the specified index.
13050  * @param {Number} index The index of the item.
13051  * @return {Object}
13052  */
13053     itemAt : function(index){
13054         return this.items[index];
13055     },
13056     
13057 /**
13058  * Returns the item associated with the passed key.
13059  * @param {String/Number} key The key of the item.
13060  * @return {Object} The item associated with the passed key.
13061  */
13062     key : function(key){
13063         return this.map[key];
13064     },
13065    
13066 /**
13067  * Returns true if the collection contains the passed Object as an item.
13068  * @param {Object} o  The Object to look for in the collection.
13069  * @return {Boolean} True if the collection contains the Object as an item.
13070  */
13071     contains : function(o){
13072         return this.indexOf(o) != -1;
13073     },
13074    
13075 /**
13076  * Returns true if the collection contains the passed Object as a key.
13077  * @param {String} key The key to look for in the collection.
13078  * @return {Boolean} True if the collection contains the Object as a key.
13079  */
13080     containsKey : function(key){
13081         return typeof this.map[key] != "undefined";
13082     },
13083    
13084 /**
13085  * Removes all items from the collection.
13086  */
13087     clear : function(){
13088         this.length = 0;
13089         this.items = [];
13090         this.keys = [];
13091         this.map = {};
13092         this.fireEvent("clear");
13093     },
13094    
13095 /**
13096  * Returns the first item in the collection.
13097  * @return {Object} the first item in the collection..
13098  */
13099     first : function(){
13100         return this.items[0]; 
13101     },
13102    
13103 /**
13104  * Returns the last item in the collection.
13105  * @return {Object} the last item in the collection..
13106  */
13107     last : function(){
13108         return this.items[this.length-1];   
13109     },
13110     
13111     _sort : function(property, dir, fn){
13112         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13113         fn = fn || function(a, b){
13114             return a-b;
13115         };
13116         var c = [], k = this.keys, items = this.items;
13117         for(var i = 0, len = items.length; i < len; i++){
13118             c[c.length] = {key: k[i], value: items[i], index: i};
13119         }
13120         c.sort(function(a, b){
13121             var v = fn(a[property], b[property]) * dsc;
13122             if(v == 0){
13123                 v = (a.index < b.index ? -1 : 1);
13124             }
13125             return v;
13126         });
13127         for(var i = 0, len = c.length; i < len; i++){
13128             items[i] = c[i].value;
13129             k[i] = c[i].key;
13130         }
13131         this.fireEvent("sort", this);
13132     },
13133     
13134     /**
13135      * Sorts this collection with the passed comparison function
13136      * @param {String} direction (optional) "ASC" or "DESC"
13137      * @param {Function} fn (optional) comparison function
13138      */
13139     sort : function(dir, fn){
13140         this._sort("value", dir, fn);
13141     },
13142     
13143     /**
13144      * Sorts this collection by keys
13145      * @param {String} direction (optional) "ASC" or "DESC"
13146      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13147      */
13148     keySort : function(dir, fn){
13149         this._sort("key", dir, fn || function(a, b){
13150             return String(a).toUpperCase()-String(b).toUpperCase();
13151         });
13152     },
13153     
13154     /**
13155      * Returns a range of items in this collection
13156      * @param {Number} startIndex (optional) defaults to 0
13157      * @param {Number} endIndex (optional) default to the last item
13158      * @return {Array} An array of items
13159      */
13160     getRange : function(start, end){
13161         var items = this.items;
13162         if(items.length < 1){
13163             return [];
13164         }
13165         start = start || 0;
13166         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13167         var r = [];
13168         if(start <= end){
13169             for(var i = start; i <= end; i++) {
13170                     r[r.length] = items[i];
13171             }
13172         }else{
13173             for(var i = start; i >= end; i--) {
13174                     r[r.length] = items[i];
13175             }
13176         }
13177         return r;
13178     },
13179         
13180     /**
13181      * Filter the <i>objects</i> in this collection by a specific property. 
13182      * Returns a new collection that has been filtered.
13183      * @param {String} property A property on your objects
13184      * @param {String/RegExp} value Either string that the property values 
13185      * should start with or a RegExp to test against the property
13186      * @return {MixedCollection} The new filtered collection
13187      */
13188     filter : function(property, value){
13189         if(!value.exec){ // not a regex
13190             value = String(value);
13191             if(value.length == 0){
13192                 return this.clone();
13193             }
13194             value = new RegExp("^" + Roo.escapeRe(value), "i");
13195         }
13196         return this.filterBy(function(o){
13197             return o && value.test(o[property]);
13198         });
13199         },
13200     
13201     /**
13202      * Filter by a function. * Returns a new collection that has been filtered.
13203      * The passed function will be called with each 
13204      * object in the collection. If the function returns true, the value is included 
13205      * otherwise it is filtered.
13206      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13207      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13208      * @return {MixedCollection} The new filtered collection
13209      */
13210     filterBy : function(fn, scope){
13211         var r = new Roo.util.MixedCollection();
13212         r.getKey = this.getKey;
13213         var k = this.keys, it = this.items;
13214         for(var i = 0, len = it.length; i < len; i++){
13215             if(fn.call(scope||this, it[i], k[i])){
13216                                 r.add(k[i], it[i]);
13217                         }
13218         }
13219         return r;
13220     },
13221     
13222     /**
13223      * Creates a duplicate of this collection
13224      * @return {MixedCollection}
13225      */
13226     clone : function(){
13227         var r = new Roo.util.MixedCollection();
13228         var k = this.keys, it = this.items;
13229         for(var i = 0, len = it.length; i < len; i++){
13230             r.add(k[i], it[i]);
13231         }
13232         r.getKey = this.getKey;
13233         return r;
13234     }
13235 });
13236 /**
13237  * Returns the item associated with the passed key or index.
13238  * @method
13239  * @param {String/Number} key The key or index of the item.
13240  * @return {Object} The item associated with the passed key.
13241  */
13242 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13243  * Based on:
13244  * Ext JS Library 1.1.1
13245  * Copyright(c) 2006-2007, Ext JS, LLC.
13246  *
13247  * Originally Released Under LGPL - original licence link has changed is not relivant.
13248  *
13249  * Fork - LGPL
13250  * <script type="text/javascript">
13251  */
13252 /**
13253  * @class Roo.util.JSON
13254  * Modified version of Douglas Crockford"s json.js that doesn"t
13255  * mess with the Object prototype 
13256  * http://www.json.org/js.html
13257  * @singleton
13258  */
13259 Roo.util.JSON = new (function(){
13260     var useHasOwn = {}.hasOwnProperty ? true : false;
13261     
13262     // crashes Safari in some instances
13263     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13264     
13265     var pad = function(n) {
13266         return n < 10 ? "0" + n : n;
13267     };
13268     
13269     var m = {
13270         "\b": '\\b',
13271         "\t": '\\t',
13272         "\n": '\\n',
13273         "\f": '\\f',
13274         "\r": '\\r',
13275         '"' : '\\"',
13276         "\\": '\\\\'
13277     };
13278
13279     var encodeString = function(s){
13280         if (/["\\\x00-\x1f]/.test(s)) {
13281             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13282                 var c = m[b];
13283                 if(c){
13284                     return c;
13285                 }
13286                 c = b.charCodeAt();
13287                 return "\\u00" +
13288                     Math.floor(c / 16).toString(16) +
13289                     (c % 16).toString(16);
13290             }) + '"';
13291         }
13292         return '"' + s + '"';
13293     };
13294     
13295     var encodeArray = function(o){
13296         var a = ["["], b, i, l = o.length, v;
13297             for (i = 0; i < l; i += 1) {
13298                 v = o[i];
13299                 switch (typeof v) {
13300                     case "undefined":
13301                     case "function":
13302                     case "unknown":
13303                         break;
13304                     default:
13305                         if (b) {
13306                             a.push(',');
13307                         }
13308                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13309                         b = true;
13310                 }
13311             }
13312             a.push("]");
13313             return a.join("");
13314     };
13315     
13316     var encodeDate = function(o){
13317         return '"' + o.getFullYear() + "-" +
13318                 pad(o.getMonth() + 1) + "-" +
13319                 pad(o.getDate()) + "T" +
13320                 pad(o.getHours()) + ":" +
13321                 pad(o.getMinutes()) + ":" +
13322                 pad(o.getSeconds()) + '"';
13323     };
13324     
13325     /**
13326      * Encodes an Object, Array or other value
13327      * @param {Mixed} o The variable to encode
13328      * @return {String} The JSON string
13329      */
13330     this.encode = function(o)
13331     {
13332         // should this be extended to fully wrap stringify..
13333         
13334         if(typeof o == "undefined" || o === null){
13335             return "null";
13336         }else if(o instanceof Array){
13337             return encodeArray(o);
13338         }else if(o instanceof Date){
13339             return encodeDate(o);
13340         }else if(typeof o == "string"){
13341             return encodeString(o);
13342         }else if(typeof o == "number"){
13343             return isFinite(o) ? String(o) : "null";
13344         }else if(typeof o == "boolean"){
13345             return String(o);
13346         }else {
13347             var a = ["{"], b, i, v;
13348             for (i in o) {
13349                 if(!useHasOwn || o.hasOwnProperty(i)) {
13350                     v = o[i];
13351                     switch (typeof v) {
13352                     case "undefined":
13353                     case "function":
13354                     case "unknown":
13355                         break;
13356                     default:
13357                         if(b){
13358                             a.push(',');
13359                         }
13360                         a.push(this.encode(i), ":",
13361                                 v === null ? "null" : this.encode(v));
13362                         b = true;
13363                     }
13364                 }
13365             }
13366             a.push("}");
13367             return a.join("");
13368         }
13369     };
13370     
13371     /**
13372      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13373      * @param {String} json The JSON string
13374      * @return {Object} The resulting object
13375      */
13376     this.decode = function(json){
13377         
13378         return  /** eval:var:json */ eval("(" + json + ')');
13379     };
13380 })();
13381 /** 
13382  * Shorthand for {@link Roo.util.JSON#encode}
13383  * @member Roo encode 
13384  * @method */
13385 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13386 /** 
13387  * Shorthand for {@link Roo.util.JSON#decode}
13388  * @member Roo decode 
13389  * @method */
13390 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13391 /*
13392  * Based on:
13393  * Ext JS Library 1.1.1
13394  * Copyright(c) 2006-2007, Ext JS, LLC.
13395  *
13396  * Originally Released Under LGPL - original licence link has changed is not relivant.
13397  *
13398  * Fork - LGPL
13399  * <script type="text/javascript">
13400  */
13401  
13402 /**
13403  * @class Roo.util.Format
13404  * Reusable data formatting functions
13405  * @singleton
13406  */
13407 Roo.util.Format = function(){
13408     var trimRe = /^\s+|\s+$/g;
13409     return {
13410         /**
13411          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13412          * @param {String} value The string to truncate
13413          * @param {Number} length The maximum length to allow before truncating
13414          * @return {String} The converted text
13415          */
13416         ellipsis : function(value, len){
13417             if(value && value.length > len){
13418                 return value.substr(0, len-3)+"...";
13419             }
13420             return value;
13421         },
13422
13423         /**
13424          * Checks a reference and converts it to empty string if it is undefined
13425          * @param {Mixed} value Reference to check
13426          * @return {Mixed} Empty string if converted, otherwise the original value
13427          */
13428         undef : function(value){
13429             return typeof value != "undefined" ? value : "";
13430         },
13431
13432         /**
13433          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13434          * @param {String} value The string to encode
13435          * @return {String} The encoded text
13436          */
13437         htmlEncode : function(value){
13438             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13439         },
13440
13441         /**
13442          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13443          * @param {String} value The string to decode
13444          * @return {String} The decoded text
13445          */
13446         htmlDecode : function(value){
13447             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13448         },
13449
13450         /**
13451          * Trims any whitespace from either side of a string
13452          * @param {String} value The text to trim
13453          * @return {String} The trimmed text
13454          */
13455         trim : function(value){
13456             return String(value).replace(trimRe, "");
13457         },
13458
13459         /**
13460          * Returns a substring from within an original string
13461          * @param {String} value The original text
13462          * @param {Number} start The start index of the substring
13463          * @param {Number} length The length of the substring
13464          * @return {String} The substring
13465          */
13466         substr : function(value, start, length){
13467             return String(value).substr(start, length);
13468         },
13469
13470         /**
13471          * Converts a string to all lower case letters
13472          * @param {String} value The text to convert
13473          * @return {String} The converted text
13474          */
13475         lowercase : function(value){
13476             return String(value).toLowerCase();
13477         },
13478
13479         /**
13480          * Converts a string to all upper case letters
13481          * @param {String} value The text to convert
13482          * @return {String} The converted text
13483          */
13484         uppercase : function(value){
13485             return String(value).toUpperCase();
13486         },
13487
13488         /**
13489          * Converts the first character only of a string to upper case
13490          * @param {String} value The text to convert
13491          * @return {String} The converted text
13492          */
13493         capitalize : function(value){
13494             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13495         },
13496
13497         // private
13498         call : function(value, fn){
13499             if(arguments.length > 2){
13500                 var args = Array.prototype.slice.call(arguments, 2);
13501                 args.unshift(value);
13502                  
13503                 return /** eval:var:value */  eval(fn).apply(window, args);
13504             }else{
13505                 /** eval:var:value */
13506                 return /** eval:var:value */ eval(fn).call(window, value);
13507             }
13508         },
13509
13510        
13511         /**
13512          * safer version of Math.toFixed..??/
13513          * @param {Number/String} value The numeric value to format
13514          * @param {Number/String} value Decimal places 
13515          * @return {String} The formatted currency string
13516          */
13517         toFixed : function(v, n)
13518         {
13519             // why not use to fixed - precision is buggered???
13520             if (!n) {
13521                 return Math.round(v-0);
13522             }
13523             var fact = Math.pow(10,n+1);
13524             v = (Math.round((v-0)*fact))/fact;
13525             var z = (''+fact).substring(2);
13526             if (v == Math.floor(v)) {
13527                 return Math.floor(v) + '.' + z;
13528             }
13529             
13530             // now just padd decimals..
13531             var ps = String(v).split('.');
13532             var fd = (ps[1] + z);
13533             var r = fd.substring(0,n); 
13534             var rm = fd.substring(n); 
13535             if (rm < 5) {
13536                 return ps[0] + '.' + r;
13537             }
13538             r*=1; // turn it into a number;
13539             r++;
13540             if (String(r).length != n) {
13541                 ps[0]*=1;
13542                 ps[0]++;
13543                 r = String(r).substring(1); // chop the end off.
13544             }
13545             
13546             return ps[0] + '.' + r;
13547              
13548         },
13549         
13550         /**
13551          * Format a number as US currency
13552          * @param {Number/String} value The numeric value to format
13553          * @return {String} The formatted currency string
13554          */
13555         usMoney : function(v){
13556             return '$' + Roo.util.Format.number(v);
13557         },
13558         
13559         /**
13560          * Format a number
13561          * eventually this should probably emulate php's number_format
13562          * @param {Number/String} value The numeric value to format
13563          * @param {Number} decimals number of decimal places
13564          * @return {String} The formatted currency string
13565          */
13566         number : function(v,decimals)
13567         {
13568             // multiply and round.
13569             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13570             var mul = Math.pow(10, decimals);
13571             var zero = String(mul).substring(1);
13572             v = (Math.round((v-0)*mul))/mul;
13573             
13574             // if it's '0' number.. then
13575             
13576             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13577             v = String(v);
13578             var ps = v.split('.');
13579             var whole = ps[0];
13580             
13581             
13582             var r = /(\d+)(\d{3})/;
13583             // add comma's
13584             while (r.test(whole)) {
13585                 whole = whole.replace(r, '$1' + ',' + '$2');
13586             }
13587             
13588             
13589             var sub = ps[1] ?
13590                     // has decimals..
13591                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13592                     // does not have decimals
13593                     (decimals ? ('.' + zero) : '');
13594             
13595             
13596             return whole + sub ;
13597         },
13598         
13599         /**
13600          * Parse a value into a formatted date using the specified format pattern.
13601          * @param {Mixed} value The value to format
13602          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13603          * @return {String} The formatted date string
13604          */
13605         date : function(v, format){
13606             if(!v){
13607                 return "";
13608             }
13609             if(!(v instanceof Date)){
13610                 v = new Date(Date.parse(v));
13611             }
13612             return v.dateFormat(format || Roo.util.Format.defaults.date);
13613         },
13614
13615         /**
13616          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13617          * @param {String} format Any valid date format string
13618          * @return {Function} The date formatting function
13619          */
13620         dateRenderer : function(format){
13621             return function(v){
13622                 return Roo.util.Format.date(v, format);  
13623             };
13624         },
13625
13626         // private
13627         stripTagsRE : /<\/?[^>]+>/gi,
13628         
13629         /**
13630          * Strips all HTML tags
13631          * @param {Mixed} value The text from which to strip tags
13632          * @return {String} The stripped text
13633          */
13634         stripTags : function(v){
13635             return !v ? v : String(v).replace(this.stripTagsRE, "");
13636         }
13637     };
13638 }();
13639 Roo.util.Format.defaults = {
13640     date : 'd/M/Y'
13641 };/*
13642  * Based on:
13643  * Ext JS Library 1.1.1
13644  * Copyright(c) 2006-2007, Ext JS, LLC.
13645  *
13646  * Originally Released Under LGPL - original licence link has changed is not relivant.
13647  *
13648  * Fork - LGPL
13649  * <script type="text/javascript">
13650  */
13651
13652
13653  
13654
13655 /**
13656  * @class Roo.MasterTemplate
13657  * @extends Roo.Template
13658  * Provides a template that can have child templates. The syntax is:
13659 <pre><code>
13660 var t = new Roo.MasterTemplate(
13661         '&lt;select name="{name}"&gt;',
13662                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13663         '&lt;/select&gt;'
13664 );
13665 t.add('options', {value: 'foo', text: 'bar'});
13666 // or you can add multiple child elements in one shot
13667 t.addAll('options', [
13668     {value: 'foo', text: 'bar'},
13669     {value: 'foo2', text: 'bar2'},
13670     {value: 'foo3', text: 'bar3'}
13671 ]);
13672 // then append, applying the master template values
13673 t.append('my-form', {name: 'my-select'});
13674 </code></pre>
13675 * A name attribute for the child template is not required if you have only one child
13676 * template or you want to refer to them by index.
13677  */
13678 Roo.MasterTemplate = function(){
13679     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13680     this.originalHtml = this.html;
13681     var st = {};
13682     var m, re = this.subTemplateRe;
13683     re.lastIndex = 0;
13684     var subIndex = 0;
13685     while(m = re.exec(this.html)){
13686         var name = m[1], content = m[2];
13687         st[subIndex] = {
13688             name: name,
13689             index: subIndex,
13690             buffer: [],
13691             tpl : new Roo.Template(content)
13692         };
13693         if(name){
13694             st[name] = st[subIndex];
13695         }
13696         st[subIndex].tpl.compile();
13697         st[subIndex].tpl.call = this.call.createDelegate(this);
13698         subIndex++;
13699     }
13700     this.subCount = subIndex;
13701     this.subs = st;
13702 };
13703 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13704     /**
13705     * The regular expression used to match sub templates
13706     * @type RegExp
13707     * @property
13708     */
13709     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13710
13711     /**
13712      * Applies the passed values to a child template.
13713      * @param {String/Number} name (optional) The name or index of the child template
13714      * @param {Array/Object} values The values to be applied to the template
13715      * @return {MasterTemplate} this
13716      */
13717      add : function(name, values){
13718         if(arguments.length == 1){
13719             values = arguments[0];
13720             name = 0;
13721         }
13722         var s = this.subs[name];
13723         s.buffer[s.buffer.length] = s.tpl.apply(values);
13724         return this;
13725     },
13726
13727     /**
13728      * Applies all the passed values to a child template.
13729      * @param {String/Number} name (optional) The name or index of the child template
13730      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13731      * @param {Boolean} reset (optional) True to reset the template first
13732      * @return {MasterTemplate} this
13733      */
13734     fill : function(name, values, reset){
13735         var a = arguments;
13736         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13737             values = a[0];
13738             name = 0;
13739             reset = a[1];
13740         }
13741         if(reset){
13742             this.reset();
13743         }
13744         for(var i = 0, len = values.length; i < len; i++){
13745             this.add(name, values[i]);
13746         }
13747         return this;
13748     },
13749
13750     /**
13751      * Resets the template for reuse
13752      * @return {MasterTemplate} this
13753      */
13754      reset : function(){
13755         var s = this.subs;
13756         for(var i = 0; i < this.subCount; i++){
13757             s[i].buffer = [];
13758         }
13759         return this;
13760     },
13761
13762     applyTemplate : function(values){
13763         var s = this.subs;
13764         var replaceIndex = -1;
13765         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13766             return s[++replaceIndex].buffer.join("");
13767         });
13768         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13769     },
13770
13771     apply : function(){
13772         return this.applyTemplate.apply(this, arguments);
13773     },
13774
13775     compile : function(){return this;}
13776 });
13777
13778 /**
13779  * Alias for fill().
13780  * @method
13781  */
13782 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13783  /**
13784  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13785  * var tpl = Roo.MasterTemplate.from('element-id');
13786  * @param {String/HTMLElement} el
13787  * @param {Object} config
13788  * @static
13789  */
13790 Roo.MasterTemplate.from = function(el, config){
13791     el = Roo.getDom(el);
13792     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13793 };/*
13794  * Based on:
13795  * Ext JS Library 1.1.1
13796  * Copyright(c) 2006-2007, Ext JS, LLC.
13797  *
13798  * Originally Released Under LGPL - original licence link has changed is not relivant.
13799  *
13800  * Fork - LGPL
13801  * <script type="text/javascript">
13802  */
13803
13804  
13805 /**
13806  * @class Roo.util.CSS
13807  * Utility class for manipulating CSS rules
13808  * @singleton
13809  */
13810 Roo.util.CSS = function(){
13811         var rules = null;
13812         var doc = document;
13813
13814     var camelRe = /(-[a-z])/gi;
13815     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13816
13817    return {
13818    /**
13819     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13820     * tag and appended to the HEAD of the document.
13821     * @param {String|Object} cssText The text containing the css rules
13822     * @param {String} id An id to add to the stylesheet for later removal
13823     * @return {StyleSheet}
13824     */
13825     createStyleSheet : function(cssText, id){
13826         var ss;
13827         var head = doc.getElementsByTagName("head")[0];
13828         var nrules = doc.createElement("style");
13829         nrules.setAttribute("type", "text/css");
13830         if(id){
13831             nrules.setAttribute("id", id);
13832         }
13833         if (typeof(cssText) != 'string') {
13834             // support object maps..
13835             // not sure if this a good idea.. 
13836             // perhaps it should be merged with the general css handling
13837             // and handle js style props.
13838             var cssTextNew = [];
13839             for(var n in cssText) {
13840                 var citems = [];
13841                 for(var k in cssText[n]) {
13842                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13843                 }
13844                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13845                 
13846             }
13847             cssText = cssTextNew.join("\n");
13848             
13849         }
13850        
13851        
13852        if(Roo.isIE){
13853            head.appendChild(nrules);
13854            ss = nrules.styleSheet;
13855            ss.cssText = cssText;
13856        }else{
13857            try{
13858                 nrules.appendChild(doc.createTextNode(cssText));
13859            }catch(e){
13860                nrules.cssText = cssText; 
13861            }
13862            head.appendChild(nrules);
13863            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13864        }
13865        this.cacheStyleSheet(ss);
13866        return ss;
13867    },
13868
13869    /**
13870     * Removes a style or link tag by id
13871     * @param {String} id The id of the tag
13872     */
13873    removeStyleSheet : function(id){
13874        var existing = doc.getElementById(id);
13875        if(existing){
13876            existing.parentNode.removeChild(existing);
13877        }
13878    },
13879
13880    /**
13881     * Dynamically swaps an existing stylesheet reference for a new one
13882     * @param {String} id The id of an existing link tag to remove
13883     * @param {String} url The href of the new stylesheet to include
13884     */
13885    swapStyleSheet : function(id, url){
13886        this.removeStyleSheet(id);
13887        var ss = doc.createElement("link");
13888        ss.setAttribute("rel", "stylesheet");
13889        ss.setAttribute("type", "text/css");
13890        ss.setAttribute("id", id);
13891        ss.setAttribute("href", url);
13892        doc.getElementsByTagName("head")[0].appendChild(ss);
13893    },
13894    
13895    /**
13896     * Refresh the rule cache if you have dynamically added stylesheets
13897     * @return {Object} An object (hash) of rules indexed by selector
13898     */
13899    refreshCache : function(){
13900        return this.getRules(true);
13901    },
13902
13903    // private
13904    cacheStyleSheet : function(stylesheet){
13905        if(!rules){
13906            rules = {};
13907        }
13908        try{// try catch for cross domain access issue
13909            var ssRules = stylesheet.cssRules || stylesheet.rules;
13910            for(var j = ssRules.length-1; j >= 0; --j){
13911                rules[ssRules[j].selectorText] = ssRules[j];
13912            }
13913        }catch(e){}
13914    },
13915    
13916    /**
13917     * Gets all css rules for the document
13918     * @param {Boolean} refreshCache true to refresh the internal cache
13919     * @return {Object} An object (hash) of rules indexed by selector
13920     */
13921    getRules : function(refreshCache){
13922                 if(rules == null || refreshCache){
13923                         rules = {};
13924                         var ds = doc.styleSheets;
13925                         for(var i =0, len = ds.length; i < len; i++){
13926                             try{
13927                         this.cacheStyleSheet(ds[i]);
13928                     }catch(e){} 
13929                 }
13930                 }
13931                 return rules;
13932         },
13933         
13934         /**
13935     * Gets an an individual CSS rule by selector(s)
13936     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13937     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13938     * @return {CSSRule} The CSS rule or null if one is not found
13939     */
13940    getRule : function(selector, refreshCache){
13941                 var rs = this.getRules(refreshCache);
13942                 if(!(selector instanceof Array)){
13943                     return rs[selector];
13944                 }
13945                 for(var i = 0; i < selector.length; i++){
13946                         if(rs[selector[i]]){
13947                                 return rs[selector[i]];
13948                         }
13949                 }
13950                 return null;
13951         },
13952         
13953         
13954         /**
13955     * Updates a rule property
13956     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13957     * @param {String} property The css property
13958     * @param {String} value The new value for the property
13959     * @return {Boolean} true If a rule was found and updated
13960     */
13961    updateRule : function(selector, property, value){
13962                 if(!(selector instanceof Array)){
13963                         var rule = this.getRule(selector);
13964                         if(rule){
13965                                 rule.style[property.replace(camelRe, camelFn)] = value;
13966                                 return true;
13967                         }
13968                 }else{
13969                         for(var i = 0; i < selector.length; i++){
13970                                 if(this.updateRule(selector[i], property, value)){
13971                                         return true;
13972                                 }
13973                         }
13974                 }
13975                 return false;
13976         }
13977    };   
13978 }();/*
13979  * Based on:
13980  * Ext JS Library 1.1.1
13981  * Copyright(c) 2006-2007, Ext JS, LLC.
13982  *
13983  * Originally Released Under LGPL - original licence link has changed is not relivant.
13984  *
13985  * Fork - LGPL
13986  * <script type="text/javascript">
13987  */
13988
13989  
13990
13991 /**
13992  * @class Roo.util.ClickRepeater
13993  * @extends Roo.util.Observable
13994  * 
13995  * A wrapper class which can be applied to any element. Fires a "click" event while the
13996  * mouse is pressed. The interval between firings may be specified in the config but
13997  * defaults to 10 milliseconds.
13998  * 
13999  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14000  * 
14001  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14002  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14003  * Similar to an autorepeat key delay.
14004  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14005  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14006  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14007  *           "interval" and "delay" are ignored. "immediate" is honored.
14008  * @cfg {Boolean} preventDefault True to prevent the default click event
14009  * @cfg {Boolean} stopDefault True to stop the default click event
14010  * 
14011  * @history
14012  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14013  *     2007-02-02 jvs Renamed to ClickRepeater
14014  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14015  *
14016  *  @constructor
14017  * @param {String/HTMLElement/Element} el The element to listen on
14018  * @param {Object} config
14019  **/
14020 Roo.util.ClickRepeater = function(el, config)
14021 {
14022     this.el = Roo.get(el);
14023     this.el.unselectable();
14024
14025     Roo.apply(this, config);
14026
14027     this.addEvents({
14028     /**
14029      * @event mousedown
14030      * Fires when the mouse button is depressed.
14031      * @param {Roo.util.ClickRepeater} this
14032      */
14033         "mousedown" : true,
14034     /**
14035      * @event click
14036      * Fires on a specified interval during the time the element is pressed.
14037      * @param {Roo.util.ClickRepeater} this
14038      */
14039         "click" : true,
14040     /**
14041      * @event mouseup
14042      * Fires when the mouse key is released.
14043      * @param {Roo.util.ClickRepeater} this
14044      */
14045         "mouseup" : true
14046     });
14047
14048     this.el.on("mousedown", this.handleMouseDown, this);
14049     if(this.preventDefault || this.stopDefault){
14050         this.el.on("click", function(e){
14051             if(this.preventDefault){
14052                 e.preventDefault();
14053             }
14054             if(this.stopDefault){
14055                 e.stopEvent();
14056             }
14057         }, this);
14058     }
14059
14060     // allow inline handler
14061     if(this.handler){
14062         this.on("click", this.handler,  this.scope || this);
14063     }
14064
14065     Roo.util.ClickRepeater.superclass.constructor.call(this);
14066 };
14067
14068 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14069     interval : 20,
14070     delay: 250,
14071     preventDefault : true,
14072     stopDefault : false,
14073     timer : 0,
14074
14075     // private
14076     handleMouseDown : function(){
14077         clearTimeout(this.timer);
14078         this.el.blur();
14079         if(this.pressClass){
14080             this.el.addClass(this.pressClass);
14081         }
14082         this.mousedownTime = new Date();
14083
14084         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14085         this.el.on("mouseout", this.handleMouseOut, this);
14086
14087         this.fireEvent("mousedown", this);
14088         this.fireEvent("click", this);
14089         
14090         this.timer = this.click.defer(this.delay || this.interval, this);
14091     },
14092
14093     // private
14094     click : function(){
14095         this.fireEvent("click", this);
14096         this.timer = this.click.defer(this.getInterval(), this);
14097     },
14098
14099     // private
14100     getInterval: function(){
14101         if(!this.accelerate){
14102             return this.interval;
14103         }
14104         var pressTime = this.mousedownTime.getElapsed();
14105         if(pressTime < 500){
14106             return 400;
14107         }else if(pressTime < 1700){
14108             return 320;
14109         }else if(pressTime < 2600){
14110             return 250;
14111         }else if(pressTime < 3500){
14112             return 180;
14113         }else if(pressTime < 4400){
14114             return 140;
14115         }else if(pressTime < 5300){
14116             return 80;
14117         }else if(pressTime < 6200){
14118             return 50;
14119         }else{
14120             return 10;
14121         }
14122     },
14123
14124     // private
14125     handleMouseOut : function(){
14126         clearTimeout(this.timer);
14127         if(this.pressClass){
14128             this.el.removeClass(this.pressClass);
14129         }
14130         this.el.on("mouseover", this.handleMouseReturn, this);
14131     },
14132
14133     // private
14134     handleMouseReturn : function(){
14135         this.el.un("mouseover", this.handleMouseReturn);
14136         if(this.pressClass){
14137             this.el.addClass(this.pressClass);
14138         }
14139         this.click();
14140     },
14141
14142     // private
14143     handleMouseUp : function(){
14144         clearTimeout(this.timer);
14145         this.el.un("mouseover", this.handleMouseReturn);
14146         this.el.un("mouseout", this.handleMouseOut);
14147         Roo.get(document).un("mouseup", this.handleMouseUp);
14148         this.el.removeClass(this.pressClass);
14149         this.fireEvent("mouseup", this);
14150     }
14151 });/*
14152  * Based on:
14153  * Ext JS Library 1.1.1
14154  * Copyright(c) 2006-2007, Ext JS, LLC.
14155  *
14156  * Originally Released Under LGPL - original licence link has changed is not relivant.
14157  *
14158  * Fork - LGPL
14159  * <script type="text/javascript">
14160  */
14161
14162  
14163 /**
14164  * @class Roo.KeyNav
14165  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14166  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14167  * way to implement custom navigation schemes for any UI component.</p>
14168  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14169  * pageUp, pageDown, del, home, end.  Usage:</p>
14170  <pre><code>
14171 var nav = new Roo.KeyNav("my-element", {
14172     "left" : function(e){
14173         this.moveLeft(e.ctrlKey);
14174     },
14175     "right" : function(e){
14176         this.moveRight(e.ctrlKey);
14177     },
14178     "enter" : function(e){
14179         this.save();
14180     },
14181     scope : this
14182 });
14183 </code></pre>
14184  * @constructor
14185  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14186  * @param {Object} config The config
14187  */
14188 Roo.KeyNav = function(el, config){
14189     this.el = Roo.get(el);
14190     Roo.apply(this, config);
14191     if(!this.disabled){
14192         this.disabled = true;
14193         this.enable();
14194     }
14195 };
14196
14197 Roo.KeyNav.prototype = {
14198     /**
14199      * @cfg {Boolean} disabled
14200      * True to disable this KeyNav instance (defaults to false)
14201      */
14202     disabled : false,
14203     /**
14204      * @cfg {String} defaultEventAction
14205      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14206      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14207      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14208      */
14209     defaultEventAction: "stopEvent",
14210     /**
14211      * @cfg {Boolean} forceKeyDown
14212      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14213      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14214      * handle keydown instead of keypress.
14215      */
14216     forceKeyDown : false,
14217
14218     // private
14219     prepareEvent : function(e){
14220         var k = e.getKey();
14221         var h = this.keyToHandler[k];
14222         //if(h && this[h]){
14223         //    e.stopPropagation();
14224         //}
14225         if(Roo.isSafari && h && k >= 37 && k <= 40){
14226             e.stopEvent();
14227         }
14228     },
14229
14230     // private
14231     relay : function(e){
14232         var k = e.getKey();
14233         var h = this.keyToHandler[k];
14234         if(h && this[h]){
14235             if(this.doRelay(e, this[h], h) !== true){
14236                 e[this.defaultEventAction]();
14237             }
14238         }
14239     },
14240
14241     // private
14242     doRelay : function(e, h, hname){
14243         return h.call(this.scope || this, e);
14244     },
14245
14246     // possible handlers
14247     enter : false,
14248     left : false,
14249     right : false,
14250     up : false,
14251     down : false,
14252     tab : false,
14253     esc : false,
14254     pageUp : false,
14255     pageDown : false,
14256     del : false,
14257     home : false,
14258     end : false,
14259
14260     // quick lookup hash
14261     keyToHandler : {
14262         37 : "left",
14263         39 : "right",
14264         38 : "up",
14265         40 : "down",
14266         33 : "pageUp",
14267         34 : "pageDown",
14268         46 : "del",
14269         36 : "home",
14270         35 : "end",
14271         13 : "enter",
14272         27 : "esc",
14273         9  : "tab"
14274     },
14275
14276         /**
14277          * Enable this KeyNav
14278          */
14279         enable: function(){
14280                 if(this.disabled){
14281             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14282             // the EventObject will normalize Safari automatically
14283             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14284                 this.el.on("keydown", this.relay,  this);
14285             }else{
14286                 this.el.on("keydown", this.prepareEvent,  this);
14287                 this.el.on("keypress", this.relay,  this);
14288             }
14289                     this.disabled = false;
14290                 }
14291         },
14292
14293         /**
14294          * Disable this KeyNav
14295          */
14296         disable: function(){
14297                 if(!this.disabled){
14298                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14299                 this.el.un("keydown", this.relay);
14300             }else{
14301                 this.el.un("keydown", this.prepareEvent);
14302                 this.el.un("keypress", this.relay);
14303             }
14304                     this.disabled = true;
14305                 }
14306         }
14307 };/*
14308  * Based on:
14309  * Ext JS Library 1.1.1
14310  * Copyright(c) 2006-2007, Ext JS, LLC.
14311  *
14312  * Originally Released Under LGPL - original licence link has changed is not relivant.
14313  *
14314  * Fork - LGPL
14315  * <script type="text/javascript">
14316  */
14317
14318  
14319 /**
14320  * @class Roo.KeyMap
14321  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14322  * The constructor accepts the same config object as defined by {@link #addBinding}.
14323  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14324  * combination it will call the function with this signature (if the match is a multi-key
14325  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14326  * A KeyMap can also handle a string representation of keys.<br />
14327  * Usage:
14328  <pre><code>
14329 // map one key by key code
14330 var map = new Roo.KeyMap("my-element", {
14331     key: 13, // or Roo.EventObject.ENTER
14332     fn: myHandler,
14333     scope: myObject
14334 });
14335
14336 // map multiple keys to one action by string
14337 var map = new Roo.KeyMap("my-element", {
14338     key: "a\r\n\t",
14339     fn: myHandler,
14340     scope: myObject
14341 });
14342
14343 // map multiple keys to multiple actions by strings and array of codes
14344 var map = new Roo.KeyMap("my-element", [
14345     {
14346         key: [10,13],
14347         fn: function(){ alert("Return was pressed"); }
14348     }, {
14349         key: "abc",
14350         fn: function(){ alert('a, b or c was pressed'); }
14351     }, {
14352         key: "\t",
14353         ctrl:true,
14354         shift:true,
14355         fn: function(){ alert('Control + shift + tab was pressed.'); }
14356     }
14357 ]);
14358 </code></pre>
14359  * <b>Note: A KeyMap starts enabled</b>
14360  * @constructor
14361  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14362  * @param {Object} config The config (see {@link #addBinding})
14363  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14364  */
14365 Roo.KeyMap = function(el, config, eventName){
14366     this.el  = Roo.get(el);
14367     this.eventName = eventName || "keydown";
14368     this.bindings = [];
14369     if(config){
14370         this.addBinding(config);
14371     }
14372     this.enable();
14373 };
14374
14375 Roo.KeyMap.prototype = {
14376     /**
14377      * True to stop the event from bubbling and prevent the default browser action if the
14378      * key was handled by the KeyMap (defaults to false)
14379      * @type Boolean
14380      */
14381     stopEvent : false,
14382
14383     /**
14384      * Add a new binding to this KeyMap. The following config object properties are supported:
14385      * <pre>
14386 Property    Type             Description
14387 ----------  ---------------  ----------------------------------------------------------------------
14388 key         String/Array     A single keycode or an array of keycodes to handle
14389 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14390 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14391 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14392 fn          Function         The function to call when KeyMap finds the expected key combination
14393 scope       Object           The scope of the callback function
14394 </pre>
14395      *
14396      * Usage:
14397      * <pre><code>
14398 // Create a KeyMap
14399 var map = new Roo.KeyMap(document, {
14400     key: Roo.EventObject.ENTER,
14401     fn: handleKey,
14402     scope: this
14403 });
14404
14405 //Add a new binding to the existing KeyMap later
14406 map.addBinding({
14407     key: 'abc',
14408     shift: true,
14409     fn: handleKey,
14410     scope: this
14411 });
14412 </code></pre>
14413      * @param {Object/Array} config A single KeyMap config or an array of configs
14414      */
14415         addBinding : function(config){
14416         if(config instanceof Array){
14417             for(var i = 0, len = config.length; i < len; i++){
14418                 this.addBinding(config[i]);
14419             }
14420             return;
14421         }
14422         var keyCode = config.key,
14423             shift = config.shift, 
14424             ctrl = config.ctrl, 
14425             alt = config.alt,
14426             fn = config.fn,
14427             scope = config.scope;
14428         if(typeof keyCode == "string"){
14429             var ks = [];
14430             var keyString = keyCode.toUpperCase();
14431             for(var j = 0, len = keyString.length; j < len; j++){
14432                 ks.push(keyString.charCodeAt(j));
14433             }
14434             keyCode = ks;
14435         }
14436         var keyArray = keyCode instanceof Array;
14437         var handler = function(e){
14438             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14439                 var k = e.getKey();
14440                 if(keyArray){
14441                     for(var i = 0, len = keyCode.length; i < len; i++){
14442                         if(keyCode[i] == k){
14443                           if(this.stopEvent){
14444                               e.stopEvent();
14445                           }
14446                           fn.call(scope || window, k, e);
14447                           return;
14448                         }
14449                     }
14450                 }else{
14451                     if(k == keyCode){
14452                         if(this.stopEvent){
14453                            e.stopEvent();
14454                         }
14455                         fn.call(scope || window, k, e);
14456                     }
14457                 }
14458             }
14459         };
14460         this.bindings.push(handler);  
14461         },
14462
14463     /**
14464      * Shorthand for adding a single key listener
14465      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14466      * following options:
14467      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14468      * @param {Function} fn The function to call
14469      * @param {Object} scope (optional) The scope of the function
14470      */
14471     on : function(key, fn, scope){
14472         var keyCode, shift, ctrl, alt;
14473         if(typeof key == "object" && !(key instanceof Array)){
14474             keyCode = key.key;
14475             shift = key.shift;
14476             ctrl = key.ctrl;
14477             alt = key.alt;
14478         }else{
14479             keyCode = key;
14480         }
14481         this.addBinding({
14482             key: keyCode,
14483             shift: shift,
14484             ctrl: ctrl,
14485             alt: alt,
14486             fn: fn,
14487             scope: scope
14488         })
14489     },
14490
14491     // private
14492     handleKeyDown : function(e){
14493             if(this.enabled){ //just in case
14494             var b = this.bindings;
14495             for(var i = 0, len = b.length; i < len; i++){
14496                 b[i].call(this, e);
14497             }
14498             }
14499         },
14500         
14501         /**
14502          * Returns true if this KeyMap is enabled
14503          * @return {Boolean} 
14504          */
14505         isEnabled : function(){
14506             return this.enabled;  
14507         },
14508         
14509         /**
14510          * Enables this KeyMap
14511          */
14512         enable: function(){
14513                 if(!this.enabled){
14514                     this.el.on(this.eventName, this.handleKeyDown, this);
14515                     this.enabled = true;
14516                 }
14517         },
14518
14519         /**
14520          * Disable this KeyMap
14521          */
14522         disable: function(){
14523                 if(this.enabled){
14524                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14525                     this.enabled = false;
14526                 }
14527         }
14528 };/*
14529  * Based on:
14530  * Ext JS Library 1.1.1
14531  * Copyright(c) 2006-2007, Ext JS, LLC.
14532  *
14533  * Originally Released Under LGPL - original licence link has changed is not relivant.
14534  *
14535  * Fork - LGPL
14536  * <script type="text/javascript">
14537  */
14538
14539  
14540 /**
14541  * @class Roo.util.TextMetrics
14542  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14543  * wide, in pixels, a given block of text will be.
14544  * @singleton
14545  */
14546 Roo.util.TextMetrics = function(){
14547     var shared;
14548     return {
14549         /**
14550          * Measures the size of the specified text
14551          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14552          * that can affect the size of the rendered text
14553          * @param {String} text The text to measure
14554          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14555          * in order to accurately measure the text height
14556          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14557          */
14558         measure : function(el, text, fixedWidth){
14559             if(!shared){
14560                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14561             }
14562             shared.bind(el);
14563             shared.setFixedWidth(fixedWidth || 'auto');
14564             return shared.getSize(text);
14565         },
14566
14567         /**
14568          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14569          * the overhead of multiple calls to initialize the style properties on each measurement.
14570          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14571          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14572          * in order to accurately measure the text height
14573          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14574          */
14575         createInstance : function(el, fixedWidth){
14576             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14577         }
14578     };
14579 }();
14580
14581  
14582
14583 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14584     var ml = new Roo.Element(document.createElement('div'));
14585     document.body.appendChild(ml.dom);
14586     ml.position('absolute');
14587     ml.setLeftTop(-1000, -1000);
14588     ml.hide();
14589
14590     if(fixedWidth){
14591         ml.setWidth(fixedWidth);
14592     }
14593      
14594     var instance = {
14595         /**
14596          * Returns the size of the specified text based on the internal element's style and width properties
14597          * @memberOf Roo.util.TextMetrics.Instance#
14598          * @param {String} text The text to measure
14599          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14600          */
14601         getSize : function(text){
14602             ml.update(text);
14603             var s = ml.getSize();
14604             ml.update('');
14605             return s;
14606         },
14607
14608         /**
14609          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14610          * that can affect the size of the rendered text
14611          * @memberOf Roo.util.TextMetrics.Instance#
14612          * @param {String/HTMLElement} el The element, dom node or id
14613          */
14614         bind : function(el){
14615             ml.setStyle(
14616                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14617             );
14618         },
14619
14620         /**
14621          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14622          * to set a fixed width in order to accurately measure the text height.
14623          * @memberOf Roo.util.TextMetrics.Instance#
14624          * @param {Number} width The width to set on the element
14625          */
14626         setFixedWidth : function(width){
14627             ml.setWidth(width);
14628         },
14629
14630         /**
14631          * Returns the measured width of the specified text
14632          * @memberOf Roo.util.TextMetrics.Instance#
14633          * @param {String} text The text to measure
14634          * @return {Number} width The width in pixels
14635          */
14636         getWidth : function(text){
14637             ml.dom.style.width = 'auto';
14638             return this.getSize(text).width;
14639         },
14640
14641         /**
14642          * Returns the measured height of the specified text.  For multiline text, be sure to call
14643          * {@link #setFixedWidth} if necessary.
14644          * @memberOf Roo.util.TextMetrics.Instance#
14645          * @param {String} text The text to measure
14646          * @return {Number} height The height in pixels
14647          */
14648         getHeight : function(text){
14649             return this.getSize(text).height;
14650         }
14651     };
14652
14653     instance.bind(bindTo);
14654
14655     return instance;
14656 };
14657
14658 // backwards compat
14659 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14660  * Based on:
14661  * Ext JS Library 1.1.1
14662  * Copyright(c) 2006-2007, Ext JS, LLC.
14663  *
14664  * Originally Released Under LGPL - original licence link has changed is not relivant.
14665  *
14666  * Fork - LGPL
14667  * <script type="text/javascript">
14668  */
14669
14670 /**
14671  * @class Roo.state.Provider
14672  * Abstract base class for state provider implementations. This class provides methods
14673  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14674  * Provider interface.
14675  */
14676 Roo.state.Provider = function(){
14677     /**
14678      * @event statechange
14679      * Fires when a state change occurs.
14680      * @param {Provider} this This state provider
14681      * @param {String} key The state key which was changed
14682      * @param {String} value The encoded value for the state
14683      */
14684     this.addEvents({
14685         "statechange": true
14686     });
14687     this.state = {};
14688     Roo.state.Provider.superclass.constructor.call(this);
14689 };
14690 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14691     /**
14692      * Returns the current value for a key
14693      * @param {String} name The key name
14694      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14695      * @return {Mixed} The state data
14696      */
14697     get : function(name, defaultValue){
14698         return typeof this.state[name] == "undefined" ?
14699             defaultValue : this.state[name];
14700     },
14701     
14702     /**
14703      * Clears a value from the state
14704      * @param {String} name The key name
14705      */
14706     clear : function(name){
14707         delete this.state[name];
14708         this.fireEvent("statechange", this, name, null);
14709     },
14710     
14711     /**
14712      * Sets the value for a key
14713      * @param {String} name The key name
14714      * @param {Mixed} value The value to set
14715      */
14716     set : function(name, value){
14717         this.state[name] = value;
14718         this.fireEvent("statechange", this, name, value);
14719     },
14720     
14721     /**
14722      * Decodes a string previously encoded with {@link #encodeValue}.
14723      * @param {String} value The value to decode
14724      * @return {Mixed} The decoded value
14725      */
14726     decodeValue : function(cookie){
14727         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14728         var matches = re.exec(unescape(cookie));
14729         if(!matches || !matches[1]) return; // non state cookie
14730         var type = matches[1];
14731         var v = matches[2];
14732         switch(type){
14733             case "n":
14734                 return parseFloat(v);
14735             case "d":
14736                 return new Date(Date.parse(v));
14737             case "b":
14738                 return (v == "1");
14739             case "a":
14740                 var all = [];
14741                 var values = v.split("^");
14742                 for(var i = 0, len = values.length; i < len; i++){
14743                     all.push(this.decodeValue(values[i]));
14744                 }
14745                 return all;
14746            case "o":
14747                 var all = {};
14748                 var values = v.split("^");
14749                 for(var i = 0, len = values.length; i < len; i++){
14750                     var kv = values[i].split("=");
14751                     all[kv[0]] = this.decodeValue(kv[1]);
14752                 }
14753                 return all;
14754            default:
14755                 return v;
14756         }
14757     },
14758     
14759     /**
14760      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14761      * @param {Mixed} value The value to encode
14762      * @return {String} The encoded value
14763      */
14764     encodeValue : function(v){
14765         var enc;
14766         if(typeof v == "number"){
14767             enc = "n:" + v;
14768         }else if(typeof v == "boolean"){
14769             enc = "b:" + (v ? "1" : "0");
14770         }else if(v instanceof Date){
14771             enc = "d:" + v.toGMTString();
14772         }else if(v instanceof Array){
14773             var flat = "";
14774             for(var i = 0, len = v.length; i < len; i++){
14775                 flat += this.encodeValue(v[i]);
14776                 if(i != len-1) flat += "^";
14777             }
14778             enc = "a:" + flat;
14779         }else if(typeof v == "object"){
14780             var flat = "";
14781             for(var key in v){
14782                 if(typeof v[key] != "function"){
14783                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14784                 }
14785             }
14786             enc = "o:" + flat.substring(0, flat.length-1);
14787         }else{
14788             enc = "s:" + v;
14789         }
14790         return escape(enc);        
14791     }
14792 });
14793
14794 /*
14795  * Based on:
14796  * Ext JS Library 1.1.1
14797  * Copyright(c) 2006-2007, Ext JS, LLC.
14798  *
14799  * Originally Released Under LGPL - original licence link has changed is not relivant.
14800  *
14801  * Fork - LGPL
14802  * <script type="text/javascript">
14803  */
14804 /**
14805  * @class Roo.state.Manager
14806  * This is the global state manager. By default all components that are "state aware" check this class
14807  * for state information if you don't pass them a custom state provider. In order for this class
14808  * to be useful, it must be initialized with a provider when your application initializes.
14809  <pre><code>
14810 // in your initialization function
14811 init : function(){
14812    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14813    ...
14814    // supposed you have a {@link Roo.BorderLayout}
14815    var layout = new Roo.BorderLayout(...);
14816    layout.restoreState();
14817    // or a {Roo.BasicDialog}
14818    var dialog = new Roo.BasicDialog(...);
14819    dialog.restoreState();
14820  </code></pre>
14821  * @singleton
14822  */
14823 Roo.state.Manager = function(){
14824     var provider = new Roo.state.Provider();
14825     
14826     return {
14827         /**
14828          * Configures the default state provider for your application
14829          * @param {Provider} stateProvider The state provider to set
14830          */
14831         setProvider : function(stateProvider){
14832             provider = stateProvider;
14833         },
14834         
14835         /**
14836          * Returns the current value for a key
14837          * @param {String} name The key name
14838          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14839          * @return {Mixed} The state data
14840          */
14841         get : function(key, defaultValue){
14842             return provider.get(key, defaultValue);
14843         },
14844         
14845         /**
14846          * Sets the value for a key
14847          * @param {String} name The key name
14848          * @param {Mixed} value The state data
14849          */
14850          set : function(key, value){
14851             provider.set(key, value);
14852         },
14853         
14854         /**
14855          * Clears a value from the state
14856          * @param {String} name The key name
14857          */
14858         clear : function(key){
14859             provider.clear(key);
14860         },
14861         
14862         /**
14863          * Gets the currently configured state provider
14864          * @return {Provider} The state provider
14865          */
14866         getProvider : function(){
14867             return provider;
14868         }
14869     };
14870 }();
14871 /*
14872  * Based on:
14873  * Ext JS Library 1.1.1
14874  * Copyright(c) 2006-2007, Ext JS, LLC.
14875  *
14876  * Originally Released Under LGPL - original licence link has changed is not relivant.
14877  *
14878  * Fork - LGPL
14879  * <script type="text/javascript">
14880  */
14881 /**
14882  * @class Roo.state.CookieProvider
14883  * @extends Roo.state.Provider
14884  * The default Provider implementation which saves state via cookies.
14885  * <br />Usage:
14886  <pre><code>
14887    var cp = new Roo.state.CookieProvider({
14888        path: "/cgi-bin/",
14889        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14890        domain: "roojs.com"
14891    })
14892    Roo.state.Manager.setProvider(cp);
14893  </code></pre>
14894  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14895  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14896  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14897  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14898  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14899  * domain the page is running on including the 'www' like 'www.roojs.com')
14900  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14901  * @constructor
14902  * Create a new CookieProvider
14903  * @param {Object} config The configuration object
14904  */
14905 Roo.state.CookieProvider = function(config){
14906     Roo.state.CookieProvider.superclass.constructor.call(this);
14907     this.path = "/";
14908     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14909     this.domain = null;
14910     this.secure = false;
14911     Roo.apply(this, config);
14912     this.state = this.readCookies();
14913 };
14914
14915 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14916     // private
14917     set : function(name, value){
14918         if(typeof value == "undefined" || value === null){
14919             this.clear(name);
14920             return;
14921         }
14922         this.setCookie(name, value);
14923         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14924     },
14925
14926     // private
14927     clear : function(name){
14928         this.clearCookie(name);
14929         Roo.state.CookieProvider.superclass.clear.call(this, name);
14930     },
14931
14932     // private
14933     readCookies : function(){
14934         var cookies = {};
14935         var c = document.cookie + ";";
14936         var re = /\s?(.*?)=(.*?);/g;
14937         var matches;
14938         while((matches = re.exec(c)) != null){
14939             var name = matches[1];
14940             var value = matches[2];
14941             if(name && name.substring(0,3) == "ys-"){
14942                 cookies[name.substr(3)] = this.decodeValue(value);
14943             }
14944         }
14945         return cookies;
14946     },
14947
14948     // private
14949     setCookie : function(name, value){
14950         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14951            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14952            ((this.path == null) ? "" : ("; path=" + this.path)) +
14953            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14954            ((this.secure == true) ? "; secure" : "");
14955     },
14956
14957     // private
14958     clearCookie : function(name){
14959         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14960            ((this.path == null) ? "" : ("; path=" + this.path)) +
14961            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14962            ((this.secure == true) ? "; secure" : "");
14963     }
14964 });/*
14965  * Based on:
14966  * Ext JS Library 1.1.1
14967  * Copyright(c) 2006-2007, Ext JS, LLC.
14968  *
14969  * Originally Released Under LGPL - original licence link has changed is not relivant.
14970  *
14971  * Fork - LGPL
14972  * <script type="text/javascript">
14973  */
14974  
14975
14976 /**
14977  * @class Roo.ComponentMgr
14978  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14979  * @singleton
14980  */
14981 Roo.ComponentMgr = function(){
14982     var all = new Roo.util.MixedCollection();
14983
14984     return {
14985         /**
14986          * Registers a component.
14987          * @param {Roo.Component} c The component
14988          */
14989         register : function(c){
14990             all.add(c);
14991         },
14992
14993         /**
14994          * Unregisters a component.
14995          * @param {Roo.Component} c The component
14996          */
14997         unregister : function(c){
14998             all.remove(c);
14999         },
15000
15001         /**
15002          * Returns a component by id
15003          * @param {String} id The component id
15004          */
15005         get : function(id){
15006             return all.get(id);
15007         },
15008
15009         /**
15010          * Registers a function that will be called when a specified component is added to ComponentMgr
15011          * @param {String} id The component id
15012          * @param {Funtction} fn The callback function
15013          * @param {Object} scope The scope of the callback
15014          */
15015         onAvailable : function(id, fn, scope){
15016             all.on("add", function(index, o){
15017                 if(o.id == id){
15018                     fn.call(scope || o, o);
15019                     all.un("add", fn, scope);
15020                 }
15021             });
15022         }
15023     };
15024 }();/*
15025  * Based on:
15026  * Ext JS Library 1.1.1
15027  * Copyright(c) 2006-2007, Ext JS, LLC.
15028  *
15029  * Originally Released Under LGPL - original licence link has changed is not relivant.
15030  *
15031  * Fork - LGPL
15032  * <script type="text/javascript">
15033  */
15034  
15035 /**
15036  * @class Roo.Component
15037  * @extends Roo.util.Observable
15038  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15039  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15040  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15041  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15042  * All visual components (widgets) that require rendering into a layout should subclass Component.
15043  * @constructor
15044  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15045  * 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
15046  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15047  */
15048 Roo.Component = function(config){
15049     config = config || {};
15050     if(config.tagName || config.dom || typeof config == "string"){ // element object
15051         config = {el: config, id: config.id || config};
15052     }
15053     this.initialConfig = config;
15054
15055     Roo.apply(this, config);
15056     this.addEvents({
15057         /**
15058          * @event disable
15059          * Fires after the component is disabled.
15060              * @param {Roo.Component} this
15061              */
15062         disable : true,
15063         /**
15064          * @event enable
15065          * Fires after the component is enabled.
15066              * @param {Roo.Component} this
15067              */
15068         enable : true,
15069         /**
15070          * @event beforeshow
15071          * Fires before the component is shown.  Return false to stop the show.
15072              * @param {Roo.Component} this
15073              */
15074         beforeshow : true,
15075         /**
15076          * @event show
15077          * Fires after the component is shown.
15078              * @param {Roo.Component} this
15079              */
15080         show : true,
15081         /**
15082          * @event beforehide
15083          * Fires before the component is hidden. Return false to stop the hide.
15084              * @param {Roo.Component} this
15085              */
15086         beforehide : true,
15087         /**
15088          * @event hide
15089          * Fires after the component is hidden.
15090              * @param {Roo.Component} this
15091              */
15092         hide : true,
15093         /**
15094          * @event beforerender
15095          * Fires before the component is rendered. Return false to stop the render.
15096              * @param {Roo.Component} this
15097              */
15098         beforerender : true,
15099         /**
15100          * @event render
15101          * Fires after the component is rendered.
15102              * @param {Roo.Component} this
15103              */
15104         render : true,
15105         /**
15106          * @event beforedestroy
15107          * Fires before the component is destroyed. Return false to stop the destroy.
15108              * @param {Roo.Component} this
15109              */
15110         beforedestroy : true,
15111         /**
15112          * @event destroy
15113          * Fires after the component is destroyed.
15114              * @param {Roo.Component} this
15115              */
15116         destroy : true
15117     });
15118     if(!this.id){
15119         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15120     }
15121     Roo.ComponentMgr.register(this);
15122     Roo.Component.superclass.constructor.call(this);
15123     this.initComponent();
15124     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15125         this.render(this.renderTo);
15126         delete this.renderTo;
15127     }
15128 };
15129
15130 /** @private */
15131 Roo.Component.AUTO_ID = 1000;
15132
15133 Roo.extend(Roo.Component, Roo.util.Observable, {
15134     /**
15135      * @scope Roo.Component.prototype
15136      * @type {Boolean}
15137      * true if this component is hidden. Read-only.
15138      */
15139     hidden : false,
15140     /**
15141      * @type {Boolean}
15142      * true if this component is disabled. Read-only.
15143      */
15144     disabled : false,
15145     /**
15146      * @type {Boolean}
15147      * true if this component has been rendered. Read-only.
15148      */
15149     rendered : false,
15150     
15151     /** @cfg {String} disableClass
15152      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15153      */
15154     disabledClass : "x-item-disabled",
15155         /** @cfg {Boolean} allowDomMove
15156          * Whether the component can move the Dom node when rendering (defaults to true).
15157          */
15158     allowDomMove : true,
15159     /** @cfg {String} hideMode
15160      * How this component should hidden. Supported values are
15161      * "visibility" (css visibility), "offsets" (negative offset position) and
15162      * "display" (css display) - defaults to "display".
15163      */
15164     hideMode: 'display',
15165
15166     /** @private */
15167     ctype : "Roo.Component",
15168
15169     /**
15170      * @cfg {String} actionMode 
15171      * which property holds the element that used for  hide() / show() / disable() / enable()
15172      * default is 'el' 
15173      */
15174     actionMode : "el",
15175
15176     /** @private */
15177     getActionEl : function(){
15178         return this[this.actionMode];
15179     },
15180
15181     initComponent : Roo.emptyFn,
15182     /**
15183      * If this is a lazy rendering component, render it to its container element.
15184      * @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.
15185      */
15186     render : function(container, position){
15187         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15188             if(!container && this.el){
15189                 this.el = Roo.get(this.el);
15190                 container = this.el.dom.parentNode;
15191                 this.allowDomMove = false;
15192             }
15193             this.container = Roo.get(container);
15194             this.rendered = true;
15195             if(position !== undefined){
15196                 if(typeof position == 'number'){
15197                     position = this.container.dom.childNodes[position];
15198                 }else{
15199                     position = Roo.getDom(position);
15200                 }
15201             }
15202             this.onRender(this.container, position || null);
15203             if(this.cls){
15204                 this.el.addClass(this.cls);
15205                 delete this.cls;
15206             }
15207             if(this.style){
15208                 this.el.applyStyles(this.style);
15209                 delete this.style;
15210             }
15211             this.fireEvent("render", this);
15212             this.afterRender(this.container);
15213             if(this.hidden){
15214                 this.hide();
15215             }
15216             if(this.disabled){
15217                 this.disable();
15218             }
15219         }
15220         return this;
15221     },
15222
15223     /** @private */
15224     // default function is not really useful
15225     onRender : function(ct, position){
15226         if(this.el){
15227             this.el = Roo.get(this.el);
15228             if(this.allowDomMove !== false){
15229                 ct.dom.insertBefore(this.el.dom, position);
15230             }
15231         }
15232     },
15233
15234     /** @private */
15235     getAutoCreate : function(){
15236         var cfg = typeof this.autoCreate == "object" ?
15237                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15238         if(this.id && !cfg.id){
15239             cfg.id = this.id;
15240         }
15241         return cfg;
15242     },
15243
15244     /** @private */
15245     afterRender : Roo.emptyFn,
15246
15247     /**
15248      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15249      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15250      */
15251     destroy : function(){
15252         if(this.fireEvent("beforedestroy", this) !== false){
15253             this.purgeListeners();
15254             this.beforeDestroy();
15255             if(this.rendered){
15256                 this.el.removeAllListeners();
15257                 this.el.remove();
15258                 if(this.actionMode == "container"){
15259                     this.container.remove();
15260                 }
15261             }
15262             this.onDestroy();
15263             Roo.ComponentMgr.unregister(this);
15264             this.fireEvent("destroy", this);
15265         }
15266     },
15267
15268         /** @private */
15269     beforeDestroy : function(){
15270
15271     },
15272
15273         /** @private */
15274         onDestroy : function(){
15275
15276     },
15277
15278     /**
15279      * Returns the underlying {@link Roo.Element}.
15280      * @return {Roo.Element} The element
15281      */
15282     getEl : function(){
15283         return this.el;
15284     },
15285
15286     /**
15287      * Returns the id of this component.
15288      * @return {String}
15289      */
15290     getId : function(){
15291         return this.id;
15292     },
15293
15294     /**
15295      * Try to focus this component.
15296      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15297      * @return {Roo.Component} this
15298      */
15299     focus : function(selectText){
15300         if(this.rendered){
15301             this.el.focus();
15302             if(selectText === true){
15303                 this.el.dom.select();
15304             }
15305         }
15306         return this;
15307     },
15308
15309     /** @private */
15310     blur : function(){
15311         if(this.rendered){
15312             this.el.blur();
15313         }
15314         return this;
15315     },
15316
15317     /**
15318      * Disable this component.
15319      * @return {Roo.Component} this
15320      */
15321     disable : function(){
15322         if(this.rendered){
15323             this.onDisable();
15324         }
15325         this.disabled = true;
15326         this.fireEvent("disable", this);
15327         return this;
15328     },
15329
15330         // private
15331     onDisable : function(){
15332         this.getActionEl().addClass(this.disabledClass);
15333         this.el.dom.disabled = true;
15334     },
15335
15336     /**
15337      * Enable this component.
15338      * @return {Roo.Component} this
15339      */
15340     enable : function(){
15341         if(this.rendered){
15342             this.onEnable();
15343         }
15344         this.disabled = false;
15345         this.fireEvent("enable", this);
15346         return this;
15347     },
15348
15349         // private
15350     onEnable : function(){
15351         this.getActionEl().removeClass(this.disabledClass);
15352         this.el.dom.disabled = false;
15353     },
15354
15355     /**
15356      * Convenience function for setting disabled/enabled by boolean.
15357      * @param {Boolean} disabled
15358      */
15359     setDisabled : function(disabled){
15360         this[disabled ? "disable" : "enable"]();
15361     },
15362
15363     /**
15364      * Show this component.
15365      * @return {Roo.Component} this
15366      */
15367     show: function(){
15368         if(this.fireEvent("beforeshow", this) !== false){
15369             this.hidden = false;
15370             if(this.rendered){
15371                 this.onShow();
15372             }
15373             this.fireEvent("show", this);
15374         }
15375         return this;
15376     },
15377
15378     // private
15379     onShow : function(){
15380         var ae = this.getActionEl();
15381         if(this.hideMode == 'visibility'){
15382             ae.dom.style.visibility = "visible";
15383         }else if(this.hideMode == 'offsets'){
15384             ae.removeClass('x-hidden');
15385         }else{
15386             ae.dom.style.display = "";
15387         }
15388     },
15389
15390     /**
15391      * Hide this component.
15392      * @return {Roo.Component} this
15393      */
15394     hide: function(){
15395         if(this.fireEvent("beforehide", this) !== false){
15396             this.hidden = true;
15397             if(this.rendered){
15398                 this.onHide();
15399             }
15400             this.fireEvent("hide", this);
15401         }
15402         return this;
15403     },
15404
15405     // private
15406     onHide : function(){
15407         var ae = this.getActionEl();
15408         if(this.hideMode == 'visibility'){
15409             ae.dom.style.visibility = "hidden";
15410         }else if(this.hideMode == 'offsets'){
15411             ae.addClass('x-hidden');
15412         }else{
15413             ae.dom.style.display = "none";
15414         }
15415     },
15416
15417     /**
15418      * Convenience function to hide or show this component by boolean.
15419      * @param {Boolean} visible True to show, false to hide
15420      * @return {Roo.Component} this
15421      */
15422     setVisible: function(visible){
15423         if(visible) {
15424             this.show();
15425         }else{
15426             this.hide();
15427         }
15428         return this;
15429     },
15430
15431     /**
15432      * Returns true if this component is visible.
15433      */
15434     isVisible : function(){
15435         return this.getActionEl().isVisible();
15436     },
15437
15438     cloneConfig : function(overrides){
15439         overrides = overrides || {};
15440         var id = overrides.id || Roo.id();
15441         var cfg = Roo.applyIf(overrides, this.initialConfig);
15442         cfg.id = id; // prevent dup id
15443         return new this.constructor(cfg);
15444     }
15445 });/*
15446  * Based on:
15447  * Ext JS Library 1.1.1
15448  * Copyright(c) 2006-2007, Ext JS, LLC.
15449  *
15450  * Originally Released Under LGPL - original licence link has changed is not relivant.
15451  *
15452  * Fork - LGPL
15453  * <script type="text/javascript">
15454  */
15455
15456 /**
15457  * @class Roo.BoxComponent
15458  * @extends Roo.Component
15459  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15460  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15461  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15462  * layout containers.
15463  * @constructor
15464  * @param {Roo.Element/String/Object} config The configuration options.
15465  */
15466 Roo.BoxComponent = function(config){
15467     Roo.Component.call(this, config);
15468     this.addEvents({
15469         /**
15470          * @event resize
15471          * Fires after the component is resized.
15472              * @param {Roo.Component} this
15473              * @param {Number} adjWidth The box-adjusted width that was set
15474              * @param {Number} adjHeight The box-adjusted height that was set
15475              * @param {Number} rawWidth The width that was originally specified
15476              * @param {Number} rawHeight The height that was originally specified
15477              */
15478         resize : true,
15479         /**
15480          * @event move
15481          * Fires after the component is moved.
15482              * @param {Roo.Component} this
15483              * @param {Number} x The new x position
15484              * @param {Number} y The new y position
15485              */
15486         move : true
15487     });
15488 };
15489
15490 Roo.extend(Roo.BoxComponent, Roo.Component, {
15491     // private, set in afterRender to signify that the component has been rendered
15492     boxReady : false,
15493     // private, used to defer height settings to subclasses
15494     deferHeight: false,
15495     /** @cfg {Number} width
15496      * width (optional) size of component
15497      */
15498      /** @cfg {Number} height
15499      * height (optional) size of component
15500      */
15501      
15502     /**
15503      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15504      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15505      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15506      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15507      * @return {Roo.BoxComponent} this
15508      */
15509     setSize : function(w, h){
15510         // support for standard size objects
15511         if(typeof w == 'object'){
15512             h = w.height;
15513             w = w.width;
15514         }
15515         // not rendered
15516         if(!this.boxReady){
15517             this.width = w;
15518             this.height = h;
15519             return this;
15520         }
15521
15522         // prevent recalcs when not needed
15523         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15524             return this;
15525         }
15526         this.lastSize = {width: w, height: h};
15527
15528         var adj = this.adjustSize(w, h);
15529         var aw = adj.width, ah = adj.height;
15530         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15531             var rz = this.getResizeEl();
15532             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15533                 rz.setSize(aw, ah);
15534             }else if(!this.deferHeight && ah !== undefined){
15535                 rz.setHeight(ah);
15536             }else if(aw !== undefined){
15537                 rz.setWidth(aw);
15538             }
15539             this.onResize(aw, ah, w, h);
15540             this.fireEvent('resize', this, aw, ah, w, h);
15541         }
15542         return this;
15543     },
15544
15545     /**
15546      * Gets the current size of the component's underlying element.
15547      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15548      */
15549     getSize : function(){
15550         return this.el.getSize();
15551     },
15552
15553     /**
15554      * Gets the current XY position of the component's underlying element.
15555      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15556      * @return {Array} The XY position of the element (e.g., [100, 200])
15557      */
15558     getPosition : function(local){
15559         if(local === true){
15560             return [this.el.getLeft(true), this.el.getTop(true)];
15561         }
15562         return this.xy || this.el.getXY();
15563     },
15564
15565     /**
15566      * Gets the current box measurements of the component's underlying element.
15567      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15568      * @returns {Object} box An object in the format {x, y, width, height}
15569      */
15570     getBox : function(local){
15571         var s = this.el.getSize();
15572         if(local){
15573             s.x = this.el.getLeft(true);
15574             s.y = this.el.getTop(true);
15575         }else{
15576             var xy = this.xy || this.el.getXY();
15577             s.x = xy[0];
15578             s.y = xy[1];
15579         }
15580         return s;
15581     },
15582
15583     /**
15584      * Sets the current box measurements of the component's underlying element.
15585      * @param {Object} box An object in the format {x, y, width, height}
15586      * @returns {Roo.BoxComponent} this
15587      */
15588     updateBox : function(box){
15589         this.setSize(box.width, box.height);
15590         this.setPagePosition(box.x, box.y);
15591         return this;
15592     },
15593
15594     // protected
15595     getResizeEl : function(){
15596         return this.resizeEl || this.el;
15597     },
15598
15599     // protected
15600     getPositionEl : function(){
15601         return this.positionEl || this.el;
15602     },
15603
15604     /**
15605      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15606      * This method fires the move event.
15607      * @param {Number} left The new left
15608      * @param {Number} top The new top
15609      * @returns {Roo.BoxComponent} this
15610      */
15611     setPosition : function(x, y){
15612         this.x = x;
15613         this.y = y;
15614         if(!this.boxReady){
15615             return this;
15616         }
15617         var adj = this.adjustPosition(x, y);
15618         var ax = adj.x, ay = adj.y;
15619
15620         var el = this.getPositionEl();
15621         if(ax !== undefined || ay !== undefined){
15622             if(ax !== undefined && ay !== undefined){
15623                 el.setLeftTop(ax, ay);
15624             }else if(ax !== undefined){
15625                 el.setLeft(ax);
15626             }else if(ay !== undefined){
15627                 el.setTop(ay);
15628             }
15629             this.onPosition(ax, ay);
15630             this.fireEvent('move', this, ax, ay);
15631         }
15632         return this;
15633     },
15634
15635     /**
15636      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15637      * This method fires the move event.
15638      * @param {Number} x The new x position
15639      * @param {Number} y The new y position
15640      * @returns {Roo.BoxComponent} this
15641      */
15642     setPagePosition : function(x, y){
15643         this.pageX = x;
15644         this.pageY = y;
15645         if(!this.boxReady){
15646             return;
15647         }
15648         if(x === undefined || y === undefined){ // cannot translate undefined points
15649             return;
15650         }
15651         var p = this.el.translatePoints(x, y);
15652         this.setPosition(p.left, p.top);
15653         return this;
15654     },
15655
15656     // private
15657     onRender : function(ct, position){
15658         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15659         if(this.resizeEl){
15660             this.resizeEl = Roo.get(this.resizeEl);
15661         }
15662         if(this.positionEl){
15663             this.positionEl = Roo.get(this.positionEl);
15664         }
15665     },
15666
15667     // private
15668     afterRender : function(){
15669         Roo.BoxComponent.superclass.afterRender.call(this);
15670         this.boxReady = true;
15671         this.setSize(this.width, this.height);
15672         if(this.x || this.y){
15673             this.setPosition(this.x, this.y);
15674         }
15675         if(this.pageX || this.pageY){
15676             this.setPagePosition(this.pageX, this.pageY);
15677         }
15678     },
15679
15680     /**
15681      * Force the component's size to recalculate based on the underlying element's current height and width.
15682      * @returns {Roo.BoxComponent} this
15683      */
15684     syncSize : function(){
15685         delete this.lastSize;
15686         this.setSize(this.el.getWidth(), this.el.getHeight());
15687         return this;
15688     },
15689
15690     /**
15691      * Called after the component is resized, this method is empty by default but can be implemented by any
15692      * subclass that needs to perform custom logic after a resize occurs.
15693      * @param {Number} adjWidth The box-adjusted width that was set
15694      * @param {Number} adjHeight The box-adjusted height that was set
15695      * @param {Number} rawWidth The width that was originally specified
15696      * @param {Number} rawHeight The height that was originally specified
15697      */
15698     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15699
15700     },
15701
15702     /**
15703      * Called after the component is moved, this method is empty by default but can be implemented by any
15704      * subclass that needs to perform custom logic after a move occurs.
15705      * @param {Number} x The new x position
15706      * @param {Number} y The new y position
15707      */
15708     onPosition : function(x, y){
15709
15710     },
15711
15712     // private
15713     adjustSize : function(w, h){
15714         if(this.autoWidth){
15715             w = 'auto';
15716         }
15717         if(this.autoHeight){
15718             h = 'auto';
15719         }
15720         return {width : w, height: h};
15721     },
15722
15723     // private
15724     adjustPosition : function(x, y){
15725         return {x : x, y: y};
15726     }
15727 });/*
15728  * Original code for Roojs - LGPL
15729  * <script type="text/javascript">
15730  */
15731  
15732 /**
15733  * @class Roo.XComponent
15734  * A delayed Element creator...
15735  * Or a way to group chunks of interface together.
15736  * 
15737  * Mypart.xyx = new Roo.XComponent({
15738
15739     parent : 'Mypart.xyz', // empty == document.element.!!
15740     order : '001',
15741     name : 'xxxx'
15742     region : 'xxxx'
15743     disabled : function() {} 
15744      
15745     tree : function() { // return an tree of xtype declared components
15746         var MODULE = this;
15747         return 
15748         {
15749             xtype : 'NestedLayoutPanel',
15750             // technicall
15751         }
15752      ]
15753  *})
15754  *
15755  *
15756  * It can be used to build a big heiracy, with parent etc.
15757  * or you can just use this to render a single compoent to a dom element
15758  * MYPART.render(Roo.Element | String(id) | dom_element )
15759  * 
15760  * @extends Roo.util.Observable
15761  * @constructor
15762  * @param cfg {Object} configuration of component
15763  * 
15764  */
15765 Roo.XComponent = function(cfg) {
15766     Roo.apply(this, cfg);
15767     this.addEvents({ 
15768         /**
15769              * @event built
15770              * Fires when this the componnt is built
15771              * @param {Roo.XComponent} c the component
15772              */
15773         'built' : true
15774         
15775     });
15776     this.region = this.region || 'center'; // default..
15777     Roo.XComponent.register(this);
15778     this.modules = false;
15779     this.el = false; // where the layout goes..
15780     
15781     
15782 }
15783 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15784     /**
15785      * @property el
15786      * The created element (with Roo.factory())
15787      * @type {Roo.Layout}
15788      */
15789     el  : false,
15790     
15791     /**
15792      * @property el
15793      * for BC  - use el in new code
15794      * @type {Roo.Layout}
15795      */
15796     panel : false,
15797     
15798     /**
15799      * @property layout
15800      * for BC  - use el in new code
15801      * @type {Roo.Layout}
15802      */
15803     layout : false,
15804     
15805      /**
15806      * @cfg {Function|boolean} disabled
15807      * If this module is disabled by some rule, return true from the funtion
15808      */
15809     disabled : false,
15810     
15811     /**
15812      * @cfg {String} parent 
15813      * Name of parent element which it get xtype added to..
15814      */
15815     parent: false,
15816     
15817     /**
15818      * @cfg {String} order
15819      * Used to set the order in which elements are created (usefull for multiple tabs)
15820      */
15821     
15822     order : false,
15823     /**
15824      * @cfg {String} name
15825      * String to display while loading.
15826      */
15827     name : false,
15828     /**
15829      * @cfg {String} region
15830      * Region to render component to (defaults to center)
15831      */
15832     region : 'center',
15833     
15834     /**
15835      * @cfg {Array} items
15836      * A single item array - the first element is the root of the tree..
15837      * It's done this way to stay compatible with the Xtype system...
15838      */
15839     items : false,
15840     
15841     /**
15842      * @property _tree
15843      * The method that retuns the tree of parts that make up this compoennt 
15844      * @type {function}
15845      */
15846     _tree  : false,
15847     
15848      /**
15849      * render
15850      * render element to dom or tree
15851      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15852      */
15853     
15854     render : function(el)
15855     {
15856         
15857         el = el || false;
15858         var hp = this.parent ? 1 : 0;
15859         
15860         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15861             // if parent is a '#.....' string, then let's use that..
15862             var ename = this.parent.substr(1)
15863             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15864             el = Roo.get(ename);
15865             if (!el && !this.parent) {
15866                 Roo.log("Warning - element can not be found :#" + ename );
15867                 return;
15868             }
15869         }
15870         
15871         
15872         if (!this.parent) {
15873             
15874             el = el ? Roo.get(el) : false;      
15875             
15876             // it's a top level one..
15877             this.parent =  {
15878                 el : new Roo.BorderLayout(el || document.body, {
15879                 
15880                      center: {
15881                          titlebar: false,
15882                          autoScroll:false,
15883                          closeOnTab: true,
15884                          tabPosition: 'top',
15885                           //resizeTabs: true,
15886                          alwaysShowTabs: el && hp? false :  true,
15887                          hideTabs: el || !hp ? true :  false,
15888                          minTabWidth: 140
15889                      }
15890                  })
15891             }
15892         }
15893         
15894                 if (!this.parent.el) {
15895                         // probably an old style ctor, which has been disabled.
15896                         return;
15897                         
15898                 }
15899                 // The 'tree' method is  '_tree now' 
15900             
15901         var tree = this._tree ? this._tree() : this.tree();
15902         tree.region = tree.region || this.region;
15903         
15904         if (this.parent.el === true) {
15905             // bootstrap... - body..
15906             this.parent.el = Roo.factory(tree);
15907         }
15908         
15909         this.el = this.parent.el.addxtype(tree);
15910         this.fireEvent('built', this);
15911         
15912         this.panel = this.el;
15913         this.layout = this.panel.layout;
15914                 this.parentLayout = this.parent.layout  || false;  
15915          
15916     }
15917     
15918 });
15919
15920 Roo.apply(Roo.XComponent, {
15921     /**
15922      * @property  hideProgress
15923      * true to disable the building progress bar.. usefull on single page renders.
15924      * @type Boolean
15925      */
15926     hideProgress : false,
15927     /**
15928      * @property  buildCompleted
15929      * True when the builder has completed building the interface.
15930      * @type Boolean
15931      */
15932     buildCompleted : false,
15933      
15934     /**
15935      * @property  topModule
15936      * the upper most module - uses document.element as it's constructor.
15937      * @type Object
15938      */
15939      
15940     topModule  : false,
15941       
15942     /**
15943      * @property  modules
15944      * array of modules to be created by registration system.
15945      * @type {Array} of Roo.XComponent
15946      */
15947     
15948     modules : [],
15949     /**
15950      * @property  elmodules
15951      * array of modules to be created by which use #ID 
15952      * @type {Array} of Roo.XComponent
15953      */
15954      
15955     elmodules : [],
15956
15957      /**
15958      * @property  build_from_html
15959      * Build elements from html - used by bootstrap HTML stuff 
15960      *    - this is cleared after build is completed
15961      * @type {boolean} true  (default false)
15962      */
15963      
15964     build_from_html : false,
15965
15966     /**
15967      * Register components to be built later.
15968      *
15969      * This solves the following issues
15970      * - Building is not done on page load, but after an authentication process has occured.
15971      * - Interface elements are registered on page load
15972      * - Parent Interface elements may not be loaded before child, so this handles that..
15973      * 
15974      *
15975      * example:
15976      * 
15977      * MyApp.register({
15978           order : '000001',
15979           module : 'Pman.Tab.projectMgr',
15980           region : 'center',
15981           parent : 'Pman.layout',
15982           disabled : false,  // or use a function..
15983         })
15984      
15985      * * @param {Object} details about module
15986      */
15987     register : function(obj) {
15988                 
15989         Roo.XComponent.event.fireEvent('register', obj);
15990         switch(typeof(obj.disabled) ) {
15991                 
15992             case 'undefined':
15993                 break;
15994             
15995             case 'function':
15996                 if ( obj.disabled() ) {
15997                         return;
15998                 }
15999                 break;
16000             
16001             default:
16002                 if (obj.disabled) {
16003                         return;
16004                 }
16005                 break;
16006         }
16007                 
16008         this.modules.push(obj);
16009          
16010     },
16011     /**
16012      * convert a string to an object..
16013      * eg. 'AAA.BBB' -> finds AAA.BBB
16014
16015      */
16016     
16017     toObject : function(str)
16018     {
16019         if (!str || typeof(str) == 'object') {
16020             return str;
16021         }
16022         if (str.substring(0,1) == '#') {
16023             return str;
16024         }
16025
16026         var ar = str.split('.');
16027         var rt, o;
16028         rt = ar.shift();
16029             /** eval:var:o */
16030         try {
16031             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16032         } catch (e) {
16033             throw "Module not found : " + str;
16034         }
16035         
16036         if (o === false) {
16037             throw "Module not found : " + str;
16038         }
16039         Roo.each(ar, function(e) {
16040             if (typeof(o[e]) == 'undefined') {
16041                 throw "Module not found : " + str;
16042             }
16043             o = o[e];
16044         });
16045         
16046         return o;
16047         
16048     },
16049     
16050     
16051     /**
16052      * move modules into their correct place in the tree..
16053      * 
16054      */
16055     preBuild : function ()
16056     {
16057         var _t = this;
16058         Roo.each(this.modules , function (obj)
16059         {
16060             Roo.XComponent.event.fireEvent('beforebuild', obj);
16061             
16062             var opar = obj.parent;
16063             try { 
16064                 obj.parent = this.toObject(opar);
16065             } catch(e) {
16066                 Roo.log("parent:toObject failed: " + e.toString());
16067                 return;
16068             }
16069             
16070             if (!obj.parent) {
16071                 Roo.debug && Roo.log("GOT top level module");
16072                 Roo.debug && Roo.log(obj);
16073                 obj.modules = new Roo.util.MixedCollection(false, 
16074                     function(o) { return o.order + '' }
16075                 );
16076                 this.topModule = obj;
16077                 return;
16078             }
16079                         // parent is a string (usually a dom element name..)
16080             if (typeof(obj.parent) == 'string') {
16081                 this.elmodules.push(obj);
16082                 return;
16083             }
16084             if (obj.parent.constructor != Roo.XComponent) {
16085                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16086             }
16087             if (!obj.parent.modules) {
16088                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16089                     function(o) { return o.order + '' }
16090                 );
16091             }
16092             if (obj.parent.disabled) {
16093                 obj.disabled = true;
16094             }
16095             obj.parent.modules.add(obj);
16096         }, this);
16097     },
16098     
16099      /**
16100      * make a list of modules to build.
16101      * @return {Array} list of modules. 
16102      */ 
16103     
16104     buildOrder : function()
16105     {
16106         var _this = this;
16107         var cmp = function(a,b) {   
16108             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16109         };
16110         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16111             throw "No top level modules to build";
16112         }
16113         
16114         // make a flat list in order of modules to build.
16115         var mods = this.topModule ? [ this.topModule ] : [];
16116                 
16117         
16118         // elmodules (is a list of DOM based modules )
16119         Roo.each(this.elmodules, function(e) {
16120             mods.push(e);
16121             if (!this.topModule &&
16122                 typeof(e.parent) == 'string' &&
16123                 e.parent.substring(0,1) == '#' &&
16124                 Roo.get(e.parent.substr(1))
16125                ) {
16126                 
16127                 _this.topModule = e;
16128             }
16129             
16130         });
16131
16132         
16133         // add modules to their parents..
16134         var addMod = function(m) {
16135             Roo.debug && Roo.log("build Order: add: " + m.name);
16136                 
16137             mods.push(m);
16138             if (m.modules && !m.disabled) {
16139                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16140                 m.modules.keySort('ASC',  cmp );
16141                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16142     
16143                 m.modules.each(addMod);
16144             } else {
16145                 Roo.debug && Roo.log("build Order: no child modules");
16146             }
16147             // not sure if this is used any more..
16148             if (m.finalize) {
16149                 m.finalize.name = m.name + " (clean up) ";
16150                 mods.push(m.finalize);
16151             }
16152             
16153         }
16154         if (this.topModule && this.topModule.modules) { 
16155             this.topModule.modules.keySort('ASC',  cmp );
16156             this.topModule.modules.each(addMod);
16157         } 
16158         return mods;
16159     },
16160     
16161      /**
16162      * Build the registered modules.
16163      * @param {Object} parent element.
16164      * @param {Function} optional method to call after module has been added.
16165      * 
16166      */ 
16167    
16168     build : function(opts) 
16169     {
16170         
16171         if (typeof(opts) != 'undefined') {
16172             Roo.apply(this,opts);
16173         }
16174         
16175         this.preBuild();
16176         var mods = this.buildOrder();
16177       
16178         //this.allmods = mods;
16179         //Roo.debug && Roo.log(mods);
16180         //return;
16181         if (!mods.length) { // should not happen
16182             throw "NO modules!!!";
16183         }
16184         
16185         
16186         var msg = "Building Interface...";
16187         // flash it up as modal - so we store the mask!?
16188         if (!this.hideProgress && Roo.MessageBox) {
16189             Roo.MessageBox.show({ title: 'loading' });
16190             Roo.MessageBox.show({
16191                title: "Please wait...",
16192                msg: msg,
16193                width:450,
16194                progress:true,
16195                closable:false,
16196                modal: false
16197               
16198             });
16199         }
16200         var total = mods.length;
16201         
16202         var _this = this;
16203         var progressRun = function() {
16204             if (!mods.length) {
16205                 Roo.debug && Roo.log('hide?');
16206                 if (!this.hideProgress && Roo.MessageBox) {
16207                     Roo.MessageBox.hide();
16208                 }
16209                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16210                 
16211                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16212                 
16213                 // THE END...
16214                 return false;   
16215             }
16216             
16217             var m = mods.shift();
16218             
16219             
16220             Roo.debug && Roo.log(m);
16221             // not sure if this is supported any more.. - modules that are are just function
16222             if (typeof(m) == 'function') { 
16223                 m.call(this);
16224                 return progressRun.defer(10, _this);
16225             } 
16226             
16227             
16228             msg = "Building Interface " + (total  - mods.length) + 
16229                     " of " + total + 
16230                     (m.name ? (' - ' + m.name) : '');
16231                         Roo.debug && Roo.log(msg);
16232             if (!this.hideProgress &&  Roo.MessageBox) { 
16233                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16234             }
16235             
16236          
16237             // is the module disabled?
16238             var disabled = (typeof(m.disabled) == 'function') ?
16239                 m.disabled.call(m.module.disabled) : m.disabled;    
16240             
16241             
16242             if (disabled) {
16243                 return progressRun(); // we do not update the display!
16244             }
16245             
16246             // now build 
16247             
16248                         
16249                         
16250             m.render();
16251             // it's 10 on top level, and 1 on others??? why...
16252             return progressRun.defer(10, _this);
16253              
16254         }
16255         progressRun.defer(1, _this);
16256      
16257         
16258         
16259     },
16260         
16261         
16262         /**
16263          * Event Object.
16264          *
16265          *
16266          */
16267         event: false, 
16268     /**
16269          * wrapper for event.on - aliased later..  
16270          * Typically use to register a event handler for register:
16271          *
16272          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16273          *
16274          */
16275     on : false
16276    
16277     
16278     
16279 });
16280
16281 Roo.XComponent.event = new Roo.util.Observable({
16282                 events : { 
16283                         /**
16284                          * @event register
16285                          * Fires when an Component is registered,
16286                          * set the disable property on the Component to stop registration.
16287                          * @param {Roo.XComponent} c the component being registerd.
16288                          * 
16289                          */
16290                         'register' : true,
16291             /**
16292                          * @event beforebuild
16293                          * Fires before each Component is built
16294                          * can be used to apply permissions.
16295                          * @param {Roo.XComponent} c the component being registerd.
16296                          * 
16297                          */
16298                         'beforebuild' : true,
16299                         /**
16300                          * @event buildcomplete
16301                          * Fires on the top level element when all elements have been built
16302                          * @param {Roo.XComponent} the top level component.
16303                          */
16304                         'buildcomplete' : true
16305                         
16306                 }
16307 });
16308
16309 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16310