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             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618         /** @type Boolean */
619         isTouch : isTouch,
620
621         /**
622          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623          * you may want to set this to true.
624          * @type Boolean
625          */
626         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
627         
628         
629                 
630         /**
631          * Selects a single element as a Roo Element
632          * This is about as close as you can get to jQuery's $('do crazy stuff')
633          * @param {String} selector The selector/xpath query
634          * @param {Node} root (optional) The start of the query (defaults to document).
635          * @return {Roo.Element}
636          */
637         selectNode : function(selector, root) 
638         {
639             var node = Roo.DomQuery.selectNode(selector,root);
640             return node ? Roo.get(node) : new Roo.Element(false);
641         }
642         
643     });
644
645
646 })();
647
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 /*
651  * Based on:
652  * Ext JS Library 1.1.1
653  * Copyright(c) 2006-2007, Ext JS, LLC.
654  *
655  * Originally Released Under LGPL - original licence link has changed is not relivant.
656  *
657  * Fork - LGPL
658  * <script type="text/javascript">
659  */
660
661 (function() {    
662     // wrappedn so fnCleanup is not in global scope...
663     if(Roo.isIE) {
664         function fnCleanUp() {
665             var p = Function.prototype;
666             delete p.createSequence;
667             delete p.defer;
668             delete p.createDelegate;
669             delete p.createCallback;
670             delete p.createInterceptor;
671
672             window.detachEvent("onunload", fnCleanUp);
673         }
674         window.attachEvent("onunload", fnCleanUp);
675     }
676 })();
677
678
679 /**
680  * @class Function
681  * These functions are available on every Function object (any JavaScript function).
682  */
683 Roo.apply(Function.prototype, {
684      /**
685      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687      * Will create a function that is bound to those 2 args.
688      * @return {Function} The new function
689     */
690     createCallback : function(/*args...*/){
691         // make args available, in function below
692         var args = arguments;
693         var method = this;
694         return function() {
695             return method.apply(window, args);
696         };
697     },
698
699     /**
700      * Creates a delegate (callback) that sets the scope to obj.
701      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702      * Will create a function that is automatically scoped to this.
703      * @param {Object} obj (optional) The object for which the scope is set
704      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706      *                                             if a number the args are inserted at the specified position
707      * @return {Function} The new function
708      */
709     createDelegate : function(obj, args, appendArgs){
710         var method = this;
711         return function() {
712             var callArgs = args || arguments;
713             if(appendArgs === true){
714                 callArgs = Array.prototype.slice.call(arguments, 0);
715                 callArgs = callArgs.concat(args);
716             }else if(typeof appendArgs == "number"){
717                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
720             }
721             return method.apply(obj || window, callArgs);
722         };
723     },
724
725     /**
726      * Calls this function after the number of millseconds specified.
727      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728      * @param {Object} obj (optional) The object for which the scope is set
729      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731      *                                             if a number the args are inserted at the specified position
732      * @return {Number} The timeout id that can be used with clearTimeout
733      */
734     defer : function(millis, obj, args, appendArgs){
735         var fn = this.createDelegate(obj, args, appendArgs);
736         if(millis){
737             return setTimeout(fn, millis);
738         }
739         fn();
740         return 0;
741     },
742     /**
743      * Create a combined function call sequence of the original function + the passed function.
744      * The resulting function returns the results of the original function.
745      * The passed fcn is called with the parameters of the original function
746      * @param {Function} fcn The function to sequence
747      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748      * @return {Function} The new function
749      */
750     createSequence : function(fcn, scope){
751         if(typeof fcn != "function"){
752             return this;
753         }
754         var method = this;
755         return function() {
756             var retval = method.apply(this || window, arguments);
757             fcn.apply(scope || this || window, arguments);
758             return retval;
759         };
760     },
761
762     /**
763      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function.
766      * @addon
767      * @param {Function} fcn The function to call before the original
768      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769      * @return {Function} The new function
770      */
771     createInterceptor : function(fcn, scope){
772         if(typeof fcn != "function"){
773             return this;
774         }
775         var method = this;
776         return function() {
777             fcn.target = this;
778             fcn.method = method;
779             if(fcn.apply(scope || this || window, arguments) === false){
780                 return;
781             }
782             return method.apply(this || window, arguments);
783         };
784     }
785 });
786 /*
787  * Based on:
788  * Ext JS Library 1.1.1
789  * Copyright(c) 2006-2007, Ext JS, LLC.
790  *
791  * Originally Released Under LGPL - original licence link has changed is not relivant.
792  *
793  * Fork - LGPL
794  * <script type="text/javascript">
795  */
796
797 Roo.applyIf(String, {
798     
799     /** @scope String */
800     
801     /**
802      * Escapes the passed string for ' and \
803      * @param {String} string The string to escape
804      * @return {String} The escaped string
805      * @static
806      */
807     escape : function(string) {
808         return string.replace(/('|\\)/g, "\\$1");
809     },
810
811     /**
812      * Pads the left side of a string with a specified character.  This is especially useful
813      * for normalizing number and date strings.  Example usage:
814      * <pre><code>
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
817 </code></pre>
818      * @param {String} string The original string
819      * @param {Number} size The total length of the output string
820      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821      * @return {String} The padded string
822      * @static
823      */
824     leftPad : function (val, size, ch) {
825         var result = new String(val);
826         if(ch === null || ch === undefined || ch === '') {
827             ch = " ";
828         }
829         while (result.length < size) {
830             result = ch + result;
831         }
832         return result;
833     },
834
835     /**
836      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
837      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
838      * <pre><code>
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
842 </code></pre>
843      * @param {String} string The tokenized string to be formatted
844      * @param {String} value1 The value to replace token {0}
845      * @param {String} value2 Etc...
846      * @return {String} The formatted string
847      * @static
848      */
849     format : function(format){
850         var args = Array.prototype.slice.call(arguments, 1);
851         return format.replace(/\{(\d+)\}/g, function(m, i){
852             return Roo.util.Format.htmlEncode(args[i]);
853         });
854     }
855 });
856
857 /**
858  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
859  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
860  * they are already different, the first value passed in is returned.  Note that this method returns the new value
861  * but does not change the current string.
862  * <pre><code>
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
865
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
868 </code></pre>
869  * @param {String} value The value to compare to the current string
870  * @param {String} other The new value to use if the string already equals the first value passed in
871  * @return {String} The new value
872  */
873  
874 String.prototype.toggle = function(value, other){
875     return this == value ? other : value;
876 };/*
877  * Based on:
878  * Ext JS Library 1.1.1
879  * Copyright(c) 2006-2007, Ext JS, LLC.
880  *
881  * Originally Released Under LGPL - original licence link has changed is not relivant.
882  *
883  * Fork - LGPL
884  * <script type="text/javascript">
885  */
886
887  /**
888  * @class Number
889  */
890 Roo.applyIf(Number.prototype, {
891     /**
892      * Checks whether or not the current number is within a desired range.  If the number is already within the
893      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894      * exceeded.  Note that this method returns the constrained value but does not change the current number.
895      * @param {Number} min The minimum number in the range
896      * @param {Number} max The maximum number in the range
897      * @return {Number} The constrained value if outside the range, otherwise the current value
898      */
899     constrain : function(min, max){
900         return Math.min(Math.max(this, min), max);
901     }
902 });/*
903  * Based on:
904  * Ext JS Library 1.1.1
905  * Copyright(c) 2006-2007, Ext JS, LLC.
906  *
907  * Originally Released Under LGPL - original licence link has changed is not relivant.
908  *
909  * Fork - LGPL
910  * <script type="text/javascript">
911  */
912  /**
913  * @class Array
914  */
915 Roo.applyIf(Array.prototype, {
916     /**
917      * Checks whether or not the specified object exists in the array.
918      * @param {Object} o The object to check for
919      * @return {Number} The index of o in the array (or -1 if it is not found)
920      */
921     indexOf : function(o){
922        for (var i = 0, len = this.length; i < len; i++){
923               if(this[i] == o) return i;
924        }
925            return -1;
926     },
927
928     /**
929      * Removes the specified object from the array.  If the object is not found nothing happens.
930      * @param {Object} o The object to remove
931      */
932     remove : function(o){
933        var index = this.indexOf(o);
934        if(index != -1){
935            this.splice(index, 1);
936        }
937     },
938     /**
939      * Map (JS 1.6 compatibility)
940      * @param {Function} function  to call
941      */
942     map : function(fun )
943     {
944         var len = this.length >>> 0;
945         if (typeof fun != "function")
946             throw new TypeError();
947
948         var res = new Array(len);
949         var thisp = arguments[1];
950         for (var i = 0; i < len; i++)
951         {
952             if (i in this)
953                 res[i] = fun.call(thisp, this[i], i, this);
954         }
955
956         return res;
957     }
958     
959 });
960
961
962  /*
963  * Based on:
964  * Ext JS Library 1.1.1
965  * Copyright(c) 2006-2007, Ext JS, LLC.
966  *
967  * Originally Released Under LGPL - original licence link has changed is not relivant.
968  *
969  * Fork - LGPL
970  * <script type="text/javascript">
971  */
972
973 /**
974  * @class Date
975  *
976  * The date parsing and format syntax is a subset of
977  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978  * supported will provide results equivalent to their PHP versions.
979  *
980  * Following is the list of all currently supported formats:
981  *<pre>
982 Sample date:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
984
985 Format  Output      Description
986 ------  ----------  --------------------------------------------------------------
987   d      10         Day of the month, 2 digits with leading zeros
988   D      Wed        A textual representation of a day, three letters
989   j      10         Day of the month without leading zeros
990   l      Wednesday  A full textual representation of the day of the week
991   S      th         English ordinal day of month suffix, 2 chars (use with j)
992   w      3          Numeric representation of the day of the week
993   z      9          The julian date, or day of the year (0-365)
994   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995   F      January    A full textual representation of the month
996   m      01         Numeric representation of a month, with leading zeros
997   M      Jan        Month name abbreviation, three letters
998   n      1          Numeric representation of a month, without leading zeros
999   t      31         Number of days in the given month
1000   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1001   Y      2007       A full numeric representation of a year, 4 digits
1002   y      07         A two digit representation of a year
1003   a      pm         Lowercase Ante meridiem and Post meridiem
1004   A      PM         Uppercase Ante meridiem and Post meridiem
1005   g      3          12-hour format of an hour without leading zeros
1006   G      15         24-hour format of an hour without leading zeros
1007   h      03         12-hour format of an hour with leading zeros
1008   H      15         24-hour format of an hour with leading zeros
1009   i      05         Minutes with leading zeros
1010   s      01         Seconds, with leading zeros
1011   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1013   T      CST        Timezone setting of the machine running the code
1014   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1015 </pre>
1016  *
1017  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1018  * <pre><code>
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d'));                         //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1022 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
1023  </code></pre>
1024  *
1025  * Here are some standard date/time patterns that you might find helpful.  They
1026  * are not part of the source of Date.js, but to use them you can simply copy this
1027  * block of code into any script that is included after Date.js and they will also become
1028  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1029  * <pre><code>
1030 Date.patterns = {
1031     ISO8601Long:"Y-m-d H:i:s",
1032     ISO8601Short:"Y-m-d",
1033     ShortDate: "n/j/Y",
1034     LongDate: "l, F d, Y",
1035     FullDateTime: "l, F d, Y g:i:s A",
1036     MonthDay: "F d",
1037     ShortTime: "g:i A",
1038     LongTime: "g:i:s A",
1039     SortableDateTime: "Y-m-d\\TH:i:s",
1040     UniversalSortableDateTime: "Y-m-d H:i:sO",
1041     YearMonth: "F, Y"
1042 };
1043 </code></pre>
1044  *
1045  * Example usage:
1046  * <pre><code>
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1049  </code></pre>
1050  */
1051
1052 /*
1053  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054  * They generate precompiled functions from date formats instead of parsing and
1055  * processing the pattern every time you format a date.  These functions are available
1056  * on every Date object (any javascript function).
1057  *
1058  * The original article and download are here:
1059  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1060  *
1061  */
1062  
1063  
1064  // was in core
1065 /**
1066  Returns the number of milliseconds between this date and date
1067  @param {Date} date (optional) Defaults to now
1068  @return {Number} The diff in milliseconds
1069  @member Date getElapsed
1070  */
1071 Date.prototype.getElapsed = function(date) {
1072         return Math.abs((date || new Date()).getTime()-this.getTime());
1073 };
1074 // was in date file..
1075
1076
1077 // private
1078 Date.parseFunctions = {count:0};
1079 // private
1080 Date.parseRegexes = [];
1081 // private
1082 Date.formatFunctions = {count:0};
1083
1084 // private
1085 Date.prototype.dateFormat = function(format) {
1086     if (Date.formatFunctions[format] == null) {
1087         Date.createNewFormat(format);
1088     }
1089     var func = Date.formatFunctions[format];
1090     return this[func]();
1091 };
1092
1093
1094 /**
1095  * Formats a date given the supplied format string
1096  * @param {String} format The format string
1097  * @return {String} The formatted date
1098  * @method
1099  */
1100 Date.prototype.format = Date.prototype.dateFormat;
1101
1102 // private
1103 Date.createNewFormat = function(format) {
1104     var funcName = "format" + Date.formatFunctions.count++;
1105     Date.formatFunctions[format] = funcName;
1106     var code = "Date.prototype." + funcName + " = function(){return ";
1107     var special = false;
1108     var ch = '';
1109     for (var i = 0; i < format.length; ++i) {
1110         ch = format.charAt(i);
1111         if (!special && ch == "\\") {
1112             special = true;
1113         }
1114         else if (special) {
1115             special = false;
1116             code += "'" + String.escape(ch) + "' + ";
1117         }
1118         else {
1119             code += Date.getFormatCode(ch);
1120         }
1121     }
1122     /** eval:var:zzzzzzzzzzzzz */
1123     eval(code.substring(0, code.length - 3) + ";}");
1124 };
1125
1126 // private
1127 Date.getFormatCode = function(character) {
1128     switch (character) {
1129     case "d":
1130         return "String.leftPad(this.getDate(), 2, '0') + ";
1131     case "D":
1132         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1133     case "j":
1134         return "this.getDate() + ";
1135     case "l":
1136         return "Date.dayNames[this.getDay()] + ";
1137     case "S":
1138         return "this.getSuffix() + ";
1139     case "w":
1140         return "this.getDay() + ";
1141     case "z":
1142         return "this.getDayOfYear() + ";
1143     case "W":
1144         return "this.getWeekOfYear() + ";
1145     case "F":
1146         return "Date.monthNames[this.getMonth()] + ";
1147     case "m":
1148         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1149     case "M":
1150         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1151     case "n":
1152         return "(this.getMonth() + 1) + ";
1153     case "t":
1154         return "this.getDaysInMonth() + ";
1155     case "L":
1156         return "(this.isLeapYear() ? 1 : 0) + ";
1157     case "Y":
1158         return "this.getFullYear() + ";
1159     case "y":
1160         return "('' + this.getFullYear()).substring(2, 4) + ";
1161     case "a":
1162         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1163     case "A":
1164         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1165     case "g":
1166         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1167     case "G":
1168         return "this.getHours() + ";
1169     case "h":
1170         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1171     case "H":
1172         return "String.leftPad(this.getHours(), 2, '0') + ";
1173     case "i":
1174         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1175     case "s":
1176         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1177     case "O":
1178         return "this.getGMTOffset() + ";
1179     case "P":
1180         return "this.getGMTColonOffset() + ";
1181     case "T":
1182         return "this.getTimezone() + ";
1183     case "Z":
1184         return "(this.getTimezoneOffset() * -60) + ";
1185     default:
1186         return "'" + String.escape(character) + "' + ";
1187     }
1188 };
1189
1190 /**
1191  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1193  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1194  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1195  * string or the parse operation will fail.
1196  * Example Usage:
1197 <pre><code>
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1200
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1203
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1206
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1209 </code></pre>
1210  * @param {String} input The unparsed date as a string
1211  * @param {String} format The format the date is in
1212  * @return {Date} The parsed date
1213  * @static
1214  */
1215 Date.parseDate = function(input, format) {
1216     if (Date.parseFunctions[format] == null) {
1217         Date.createParser(format);
1218     }
1219     var func = Date.parseFunctions[format];
1220     return Date[func](input);
1221 };
1222 /**
1223  * @private
1224  */
1225 Date.createParser = function(format) {
1226     var funcName = "parse" + Date.parseFunctions.count++;
1227     var regexNum = Date.parseRegexes.length;
1228     var currentGroup = 1;
1229     Date.parseFunctions[format] = funcName;
1230
1231     var code = "Date." + funcName + " = function(input){\n"
1232         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233         + "var d = new Date();\n"
1234         + "y = d.getFullYear();\n"
1235         + "m = d.getMonth();\n"
1236         + "d = d.getDate();\n"
1237         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238         + "if (results && results.length > 0) {";
1239     var regex = "";
1240
1241     var special = false;
1242     var ch = '';
1243     for (var i = 0; i < format.length; ++i) {
1244         ch = format.charAt(i);
1245         if (!special && ch == "\\") {
1246             special = true;
1247         }
1248         else if (special) {
1249             special = false;
1250             regex += String.escape(ch);
1251         }
1252         else {
1253             var obj = Date.formatCodeToRegex(ch, currentGroup);
1254             currentGroup += obj.g;
1255             regex += obj.s;
1256             if (obj.g && obj.c) {
1257                 code += obj.c;
1258             }
1259         }
1260     }
1261
1262     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i, s);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265         + "{v = new Date(y, m, d, h, i);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267         + "{v = new Date(y, m, d, h);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269         + "{v = new Date(y, m, d);}\n"
1270         + "else if (y >= 0 && m >= 0)\n"
1271         + "{v = new Date(y, m);}\n"
1272         + "else if (y >= 0)\n"
1273         + "{v = new Date(y);}\n"
1274         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277         + ";}";
1278
1279     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280     /** eval:var:zzzzzzzzzzzzz */
1281     eval(code);
1282 };
1283
1284 // private
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286     switch (character) {
1287     case "D":
1288         return {g:0,
1289         c:null,
1290         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291     case "j":
1292         return {g:1,
1293             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294             s:"(\\d{1,2})"}; // day of month without leading zeroes
1295     case "d":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{2})"}; // day of month with leading zeroes
1299     case "l":
1300         return {g:0,
1301             c:null,
1302             s:"(?:" + Date.dayNames.join("|") + ")"};
1303     case "S":
1304         return {g:0,
1305             c:null,
1306             s:"(?:st|nd|rd|th)"};
1307     case "w":
1308         return {g:0,
1309             c:null,
1310             s:"\\d"};
1311     case "z":
1312         return {g:0,
1313             c:null,
1314             s:"(?:\\d{1,3})"};
1315     case "W":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{2})"};
1319     case "F":
1320         return {g:1,
1321             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322             s:"(" + Date.monthNames.join("|") + ")"};
1323     case "M":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327     case "n":
1328         return {g:1,
1329             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331     case "m":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1335     case "t":
1336         return {g:0,
1337             c:null,
1338             s:"\\d{1,2}"};
1339     case "L":
1340         return {g:0,
1341             c:null,
1342             s:"(?:1|0)"};
1343     case "Y":
1344         return {g:1,
1345             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1346             s:"(\\d{4})"};
1347     case "y":
1348         return {g:1,
1349             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1351             s:"(\\d{1,2})"};
1352     case "a":
1353         return {g:1,
1354             c:"if (results[" + currentGroup + "] == 'am') {\n"
1355                 + "if (h == 12) { h = 0; }\n"
1356                 + "} else { if (h < 12) { h += 12; }}",
1357             s:"(am|pm)"};
1358     case "A":
1359         return {g:1,
1360             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361                 + "if (h == 12) { h = 0; }\n"
1362                 + "} else { if (h < 12) { h += 12; }}",
1363             s:"(AM|PM)"};
1364     case "g":
1365     case "G":
1366         return {g:1,
1367             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1369     case "h":
1370     case "H":
1371         return {g:1,
1372             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1374     case "i":
1375         return {g:1,
1376             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"};
1378     case "s":
1379         return {g:1,
1380             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "O":
1383         return {g:1,
1384             c:[
1385                 "o = results[", currentGroup, "];\n",
1386                 "var sn = o.substring(0,1);\n", // get + / - sign
1387                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391             ].join(""),
1392             s:"([+\-]\\d{2,4})"};
1393     
1394     
1395     case "P":
1396         return {g:1,
1397                 c:[
1398                    "o = results[", currentGroup, "];\n",
1399                    "var sn = o.substring(0,1);\n",
1400                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401                    "var mn = o.substring(4,6) % 60;\n",
1402                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1404             ].join(""),
1405             s:"([+\-]\\d{4})"};
1406     case "T":
1407         return {g:0,
1408             c:null,
1409             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410     case "Z":
1411         return {g:1,
1412             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1415     default:
1416         return {g:0,
1417             c:null,
1418             s:String.escape(character)};
1419     }
1420 };
1421
1422 /**
1423  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424  * @return {String} The abbreviated timezone name (e.g. 'CST')
1425  */
1426 Date.prototype.getTimezone = function() {
1427     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1428 };
1429
1430 /**
1431  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1433  */
1434 Date.prototype.getGMTOffset = function() {
1435     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1438 };
1439
1440 /**
1441  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442  * @return {String} 2-characters representing hours and 2-characters representing minutes
1443  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1444  */
1445 Date.prototype.getGMTColonOffset = function() {
1446         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1448                 + ":"
1449                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1450 }
1451
1452 /**
1453  * Get the numeric day number of the year, adjusted for leap year.
1454  * @return {Number} 0 through 364 (365 in leap years)
1455  */
1456 Date.prototype.getDayOfYear = function() {
1457     var num = 0;
1458     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459     for (var i = 0; i < this.getMonth(); ++i) {
1460         num += Date.daysInMonth[i];
1461     }
1462     return num + this.getDate() - 1;
1463 };
1464
1465 /**
1466  * Get the string representation of the numeric week number of the year
1467  * (equivalent to the format specifier 'W').
1468  * @return {String} '00' through '52'
1469  */
1470 Date.prototype.getWeekOfYear = function() {
1471     // Skip to Thursday of this week
1472     var now = this.getDayOfYear() + (4 - this.getDay());
1473     // Find the first Thursday of the year
1474     var jan1 = new Date(this.getFullYear(), 0, 1);
1475     var then = (7 - jan1.getDay() + 4);
1476     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1477 };
1478
1479 /**
1480  * Whether or not the current date is in a leap year.
1481  * @return {Boolean} True if the current date is in a leap year, else false
1482  */
1483 Date.prototype.isLeapYear = function() {
1484     var year = this.getFullYear();
1485     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1486 };
1487
1488 /**
1489  * Get the first day of the current month, adjusted for leap year.  The returned value
1490  * is the numeric day index within the week (0-6) which can be used in conjunction with
1491  * the {@link #monthNames} array to retrieve the textual day name.
1492  * Example:
1493  *<pre><code>
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1496 </code></pre>
1497  * @return {Number} The day number (0-6)
1498  */
1499 Date.prototype.getFirstDayOfMonth = function() {
1500     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501     return (day < 0) ? (day + 7) : day;
1502 };
1503
1504 /**
1505  * Get the last day of the current month, adjusted for leap year.  The returned value
1506  * is the numeric day index within the week (0-6) which can be used in conjunction with
1507  * the {@link #monthNames} array to retrieve the textual day name.
1508  * Example:
1509  *<pre><code>
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1512 </code></pre>
1513  * @return {Number} The day number (0-6)
1514  */
1515 Date.prototype.getLastDayOfMonth = function() {
1516     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517     return (day < 0) ? (day + 7) : day;
1518 };
1519
1520
1521 /**
1522  * Get the first date of this date's month
1523  * @return {Date}
1524  */
1525 Date.prototype.getFirstDateOfMonth = function() {
1526     return new Date(this.getFullYear(), this.getMonth(), 1);
1527 };
1528
1529 /**
1530  * Get the last date of this date's month
1531  * @return {Date}
1532  */
1533 Date.prototype.getLastDateOfMonth = function() {
1534     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 };
1536 /**
1537  * Get the number of days in the current month, adjusted for leap year.
1538  * @return {Number} The number of days in the month
1539  */
1540 Date.prototype.getDaysInMonth = function() {
1541     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542     return Date.daysInMonth[this.getMonth()];
1543 };
1544
1545 /**
1546  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547  * @return {String} 'st, 'nd', 'rd' or 'th'
1548  */
1549 Date.prototype.getSuffix = function() {
1550     switch (this.getDate()) {
1551         case 1:
1552         case 21:
1553         case 31:
1554             return "st";
1555         case 2:
1556         case 22:
1557             return "nd";
1558         case 3:
1559         case 23:
1560             return "rd";
1561         default:
1562             return "th";
1563     }
1564 };
1565
1566 // private
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568
1569 /**
1570  * An array of textual month names.
1571  * Override these values for international dates, for example...
1572  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1573  * @type Array
1574  * @static
1575  */
1576 Date.monthNames =
1577    ["January",
1578     "February",
1579     "March",
1580     "April",
1581     "May",
1582     "June",
1583     "July",
1584     "August",
1585     "September",
1586     "October",
1587     "November",
1588     "December"];
1589
1590 /**
1591  * An array of textual day names.
1592  * Override these values for international dates, for example...
1593  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1594  * @type Array
1595  * @static
1596  */
1597 Date.dayNames =
1598    ["Sunday",
1599     "Monday",
1600     "Tuesday",
1601     "Wednesday",
1602     "Thursday",
1603     "Friday",
1604     "Saturday"];
1605
1606 // private
1607 Date.y2kYear = 50;
1608 // private
1609 Date.monthNumbers = {
1610     Jan:0,
1611     Feb:1,
1612     Mar:2,
1613     Apr:3,
1614     May:4,
1615     Jun:5,
1616     Jul:6,
1617     Aug:7,
1618     Sep:8,
1619     Oct:9,
1620     Nov:10,
1621     Dec:11};
1622
1623 /**
1624  * Creates and returns a new Date instance with the exact same date value as the called instance.
1625  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626  * variable will also be changed.  When the intention is to create a new variable that will not
1627  * modify the original instance, you should create a clone.
1628  *
1629  * Example of correctly cloning a date:
1630  * <pre><code>
1631 //wrong way:
1632 var orig = new Date('10/1/2006');
1633 var copy = orig;
1634 copy.setDate(5);
1635 document.write(orig);  //returns 'Thu Oct 05 2006'!
1636
1637 //correct way:
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1640 copy.setDate(5);
1641 document.write(orig);  //returns 'Thu Oct 01 2006'
1642 </code></pre>
1643  * @return {Date} The new Date instance
1644  */
1645 Date.prototype.clone = function() {
1646         return new Date(this.getTime());
1647 };
1648
1649 /**
1650  * Clears any time information from this date
1651  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652  @return {Date} this or the clone
1653  */
1654 Date.prototype.clearTime = function(clone){
1655     if(clone){
1656         return this.clone().clearTime();
1657     }
1658     this.setHours(0);
1659     this.setMinutes(0);
1660     this.setSeconds(0);
1661     this.setMilliseconds(0);
1662     return this;
1663 };
1664
1665 // private
1666 // safari setMonth is broken
1667 if(Roo.isSafari){
1668     Date.brokenSetMonth = Date.prototype.setMonth;
1669         Date.prototype.setMonth = function(num){
1670                 if(num <= -1){
1671                         var n = Math.ceil(-num);
1672                         var back_year = Math.ceil(n/12);
1673                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1674                         this.setFullYear(this.getFullYear() - back_year);
1675                         return Date.brokenSetMonth.call(this, month);
1676                 } else {
1677                         return Date.brokenSetMonth.apply(this, arguments);
1678                 }
1679         };
1680 }
1681
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.MILLI = "ms";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.SECOND = "s";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.MINUTE = "mi";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.HOUR = "h";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.DAY = "d";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MONTH = "mo";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.YEAR = "y";
1710
1711 /**
1712  * Provides a convenient method of performing basic date arithmetic.  This method
1713  * does not modify the Date instance being called - it creates and returns
1714  * a new Date instance containing the resulting date value.
1715  *
1716  * Examples:
1717  * <pre><code>
1718 //Basic usage:
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1721
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1725
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729  </code></pre>
1730  *
1731  * @param {String} interval   A valid date interval enum value
1732  * @param {Number} value      The amount to add to the current date
1733  * @return {Date} The new Date instance
1734  */
1735 Date.prototype.add = function(interval, value){
1736   var d = this.clone();
1737   if (!interval || value === 0) return d;
1738   switch(interval.toLowerCase()){
1739     case Date.MILLI:
1740       d.setMilliseconds(this.getMilliseconds() + value);
1741       break;
1742     case Date.SECOND:
1743       d.setSeconds(this.getSeconds() + value);
1744       break;
1745     case Date.MINUTE:
1746       d.setMinutes(this.getMinutes() + value);
1747       break;
1748     case Date.HOUR:
1749       d.setHours(this.getHours() + value);
1750       break;
1751     case Date.DAY:
1752       d.setDate(this.getDate() + value);
1753       break;
1754     case Date.MONTH:
1755       var day = this.getDate();
1756       if(day > 28){
1757           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758       }
1759       d.setDate(day);
1760       d.setMonth(this.getMonth() + value);
1761       break;
1762     case Date.YEAR:
1763       d.setFullYear(this.getFullYear() + value);
1764       break;
1765   }
1766   return d;
1767 };
1768 /*
1769  * Based on:
1770  * Ext JS Library 1.1.1
1771  * Copyright(c) 2006-2007, Ext JS, LLC.
1772  *
1773  * Originally Released Under LGPL - original licence link has changed is not relivant.
1774  *
1775  * Fork - LGPL
1776  * <script type="text/javascript">
1777  */
1778
1779 /**
1780  * @class Roo.lib.Dom
1781  * @static
1782  * 
1783  * Dom utils (from YIU afaik)
1784  * 
1785  **/
1786 Roo.lib.Dom = {
1787     /**
1788      * Get the view width
1789      * @param {Boolean} full True will get the full document, otherwise it's the view width
1790      * @return {Number} The width
1791      */
1792      
1793     getViewWidth : function(full) {
1794         return full ? this.getDocumentWidth() : this.getViewportWidth();
1795     },
1796     /**
1797      * Get the view height
1798      * @param {Boolean} full True will get the full document, otherwise it's the view height
1799      * @return {Number} The height
1800      */
1801     getViewHeight : function(full) {
1802         return full ? this.getDocumentHeight() : this.getViewportHeight();
1803     },
1804
1805     getDocumentHeight: function() {
1806         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807         return Math.max(scrollHeight, this.getViewportHeight());
1808     },
1809
1810     getDocumentWidth: function() {
1811         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812         return Math.max(scrollWidth, this.getViewportWidth());
1813     },
1814
1815     getViewportHeight: function() {
1816         var height = self.innerHeight;
1817         var mode = document.compatMode;
1818
1819         if ((mode || Roo.isIE) && !Roo.isOpera) {
1820             height = (mode == "CSS1Compat") ?
1821                      document.documentElement.clientHeight :
1822                      document.body.clientHeight;
1823         }
1824
1825         return height;
1826     },
1827
1828     getViewportWidth: function() {
1829         var width = self.innerWidth;
1830         var mode = document.compatMode;
1831
1832         if (mode || Roo.isIE) {
1833             width = (mode == "CSS1Compat") ?
1834                     document.documentElement.clientWidth :
1835                     document.body.clientWidth;
1836         }
1837         return width;
1838     },
1839
1840     isAncestor : function(p, c) {
1841         p = Roo.getDom(p);
1842         c = Roo.getDom(c);
1843         if (!p || !c) {
1844             return false;
1845         }
1846
1847         if (p.contains && !Roo.isSafari) {
1848             return p.contains(c);
1849         } else if (p.compareDocumentPosition) {
1850             return !!(p.compareDocumentPosition(c) & 16);
1851         } else {
1852             var parent = c.parentNode;
1853             while (parent) {
1854                 if (parent == p) {
1855                     return true;
1856                 }
1857                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858                     return false;
1859                 }
1860                 parent = parent.parentNode;
1861             }
1862             return false;
1863         }
1864     },
1865
1866     getRegion : function(el) {
1867         return Roo.lib.Region.getRegion(el);
1868     },
1869
1870     getY : function(el) {
1871         return this.getXY(el)[1];
1872     },
1873
1874     getX : function(el) {
1875         return this.getXY(el)[0];
1876     },
1877
1878     getXY : function(el) {
1879         var p, pe, b, scroll, bd = document.body;
1880         el = Roo.getDom(el);
1881         var fly = Roo.lib.AnimBase.fly;
1882         if (el.getBoundingClientRect) {
1883             b = el.getBoundingClientRect();
1884             scroll = fly(document).getScroll();
1885             return [b.left + scroll.left, b.top + scroll.top];
1886         }
1887         var x = 0, y = 0;
1888
1889         p = el;
1890
1891         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1892
1893         while (p) {
1894
1895             x += p.offsetLeft;
1896             y += p.offsetTop;
1897
1898             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1899                 hasAbsolute = true;
1900             }
1901
1902             if (Roo.isGecko) {
1903                 pe = fly(p);
1904
1905                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1907
1908
1909                 x += bl;
1910                 y += bt;
1911
1912
1913                 if (p != el && pe.getStyle('overflow') != 'visible') {
1914                     x += bl;
1915                     y += bt;
1916                 }
1917             }
1918             p = p.offsetParent;
1919         }
1920
1921         if (Roo.isSafari && hasAbsolute) {
1922             x -= bd.offsetLeft;
1923             y -= bd.offsetTop;
1924         }
1925
1926         if (Roo.isGecko && !hasAbsolute) {
1927             var dbd = fly(bd);
1928             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1930         }
1931
1932         p = el.parentNode;
1933         while (p && p != bd) {
1934             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1935                 x -= p.scrollLeft;
1936                 y -= p.scrollTop;
1937             }
1938             p = p.parentNode;
1939         }
1940         return [x, y];
1941     },
1942  
1943   
1944
1945
1946     setXY : function(el, xy) {
1947         el = Roo.fly(el, '_setXY');
1948         el.position();
1949         var pts = el.translatePoints(xy);
1950         if (xy[0] !== false) {
1951             el.dom.style.left = pts.left + "px";
1952         }
1953         if (xy[1] !== false) {
1954             el.dom.style.top = pts.top + "px";
1955         }
1956     },
1957
1958     setX : function(el, x) {
1959         this.setXY(el, [x, false]);
1960     },
1961
1962     setY : function(el, y) {
1963         this.setXY(el, [false, y]);
1964     }
1965 };
1966 /*
1967  * Portions of this file are based on pieces of Yahoo User Interface Library
1968  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969  * YUI licensed under the BSD License:
1970  * http://developer.yahoo.net/yui/license.txt
1971  * <script type="text/javascript">
1972  *
1973  */
1974
1975 Roo.lib.Event = function() {
1976     var loadComplete = false;
1977     var listeners = [];
1978     var unloadListeners = [];
1979     var retryCount = 0;
1980     var onAvailStack = [];
1981     var counter = 0;
1982     var lastError = null;
1983
1984     return {
1985         POLL_RETRYS: 200,
1986         POLL_INTERVAL: 20,
1987         EL: 0,
1988         TYPE: 1,
1989         FN: 2,
1990         WFN: 3,
1991         OBJ: 3,
1992         ADJ_SCOPE: 4,
1993         _interval: null,
1994
1995         startInterval: function() {
1996             if (!this._interval) {
1997                 var self = this;
1998                 var callback = function() {
1999                     self._tryPreloadAttach();
2000                 };
2001                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2002
2003             }
2004         },
2005
2006         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007             onAvailStack.push({ id:         p_id,
2008                 fn:         p_fn,
2009                 obj:        p_obj,
2010                 override:   p_override,
2011                 checkReady: false    });
2012
2013             retryCount = this.POLL_RETRYS;
2014             this.startInterval();
2015         },
2016
2017
2018         addListener: function(el, eventName, fn) {
2019             el = Roo.getDom(el);
2020             if (!el || !fn) {
2021                 return false;
2022             }
2023
2024             if ("unload" == eventName) {
2025                 unloadListeners[unloadListeners.length] =
2026                 [el, eventName, fn];
2027                 return true;
2028             }
2029
2030             var wrappedFn = function(e) {
2031                 return fn(Roo.lib.Event.getEvent(e));
2032             };
2033
2034             var li = [el, eventName, fn, wrappedFn];
2035
2036             var index = listeners.length;
2037             listeners[index] = li;
2038
2039             this.doAdd(el, eventName, wrappedFn, false);
2040             return true;
2041
2042         },
2043
2044
2045         removeListener: function(el, eventName, fn) {
2046             var i, len;
2047
2048             el = Roo.getDom(el);
2049
2050             if(!fn) {
2051                 return this.purgeElement(el, false, eventName);
2052             }
2053
2054
2055             if ("unload" == eventName) {
2056
2057                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058                     var li = unloadListeners[i];
2059                     if (li &&
2060                         li[0] == el &&
2061                         li[1] == eventName &&
2062                         li[2] == fn) {
2063                         unloadListeners.splice(i, 1);
2064                         return true;
2065                     }
2066                 }
2067
2068                 return false;
2069             }
2070
2071             var cacheItem = null;
2072
2073
2074             var index = arguments[3];
2075
2076             if ("undefined" == typeof index) {
2077                 index = this._getCacheIndex(el, eventName, fn);
2078             }
2079
2080             if (index >= 0) {
2081                 cacheItem = listeners[index];
2082             }
2083
2084             if (!el || !cacheItem) {
2085                 return false;
2086             }
2087
2088             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2089
2090             delete listeners[index][this.WFN];
2091             delete listeners[index][this.FN];
2092             listeners.splice(index, 1);
2093
2094             return true;
2095
2096         },
2097
2098
2099         getTarget: function(ev, resolveTextNode) {
2100             ev = ev.browserEvent || ev;
2101             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2102             var t = ev.target || ev.srcElement;
2103             return this.resolveTextNode(t);
2104         },
2105
2106
2107         resolveTextNode: function(node) {
2108             if (Roo.isSafari && node && 3 == node.nodeType) {
2109                 return node.parentNode;
2110             } else {
2111                 return node;
2112             }
2113         },
2114
2115
2116         getPageX: function(ev) {
2117             ev = ev.browserEvent || ev;
2118             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2119             var x = ev.pageX;
2120             if (!x && 0 !== x) {
2121                 x = ev.clientX || 0;
2122
2123                 if (Roo.isIE) {
2124                     x += this.getScroll()[1];
2125                 }
2126             }
2127
2128             return x;
2129         },
2130
2131
2132         getPageY: function(ev) {
2133             ev = ev.browserEvent || ev;
2134             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2135             var y = ev.pageY;
2136             if (!y && 0 !== y) {
2137                 y = ev.clientY || 0;
2138
2139                 if (Roo.isIE) {
2140                     y += this.getScroll()[0];
2141                 }
2142             }
2143
2144
2145             return y;
2146         },
2147
2148
2149         getXY: function(ev) {
2150             ev = ev.browserEvent || ev;
2151             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2152             return [this.getPageX(ev), this.getPageY(ev)];
2153         },
2154
2155
2156         getRelatedTarget: function(ev) {
2157             ev = ev.browserEvent || ev;
2158             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2159             var t = ev.relatedTarget;
2160             if (!t) {
2161                 if (ev.type == "mouseout") {
2162                     t = ev.toElement;
2163                 } else if (ev.type == "mouseover") {
2164                     t = ev.fromElement;
2165                 }
2166             }
2167
2168             return this.resolveTextNode(t);
2169         },
2170
2171
2172         getTime: function(ev) {
2173             ev = ev.browserEvent || ev;
2174             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2175             if (!ev.time) {
2176                 var t = new Date().getTime();
2177                 try {
2178                     ev.time = t;
2179                 } catch(ex) {
2180                     this.lastError = ex;
2181                     return t;
2182                 }
2183             }
2184
2185             return ev.time;
2186         },
2187
2188
2189         stopEvent: function(ev) {
2190             this.stopPropagation(ev);
2191             this.preventDefault(ev);
2192         },
2193
2194
2195         stopPropagation: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             if (ev.stopPropagation) {
2198                 ev.stopPropagation();
2199             } else {
2200                 ev.cancelBubble = true;
2201             }
2202         },
2203
2204
2205         preventDefault: function(ev) {
2206             ev = ev.browserEvent || ev;
2207             if(ev.preventDefault) {
2208                 ev.preventDefault();
2209             } else {
2210                 ev.returnValue = false;
2211             }
2212         },
2213
2214
2215         getEvent: function(e) {
2216             var ev = e || window.event;
2217             if (!ev) {
2218                 var c = this.getEvent.caller;
2219                 while (c) {
2220                     ev = c.arguments[0];
2221                     if (ev && Event == ev.constructor) {
2222                         break;
2223                     }
2224                     c = c.caller;
2225                 }
2226             }
2227             return ev;
2228         },
2229
2230
2231         getCharCode: function(ev) {
2232             ev = ev.browserEvent || ev;
2233             return ev.charCode || ev.keyCode || 0;
2234         },
2235
2236
2237         _getCacheIndex: function(el, eventName, fn) {
2238             for (var i = 0,len = listeners.length; i < len; ++i) {
2239                 var li = listeners[i];
2240                 if (li &&
2241                     li[this.FN] == fn &&
2242                     li[this.EL] == el &&
2243                     li[this.TYPE] == eventName) {
2244                     return i;
2245                 }
2246             }
2247
2248             return -1;
2249         },
2250
2251
2252         elCache: {},
2253
2254
2255         getEl: function(id) {
2256             return document.getElementById(id);
2257         },
2258
2259
2260         clearCache: function() {
2261         },
2262
2263
2264         _load: function(e) {
2265             loadComplete = true;
2266             var EU = Roo.lib.Event;
2267
2268
2269             if (Roo.isIE) {
2270                 EU.doRemove(window, "load", EU._load);
2271             }
2272         },
2273
2274
2275         _tryPreloadAttach: function() {
2276
2277             if (this.locked) {
2278                 return false;
2279             }
2280
2281             this.locked = true;
2282
2283
2284             var tryAgain = !loadComplete;
2285             if (!tryAgain) {
2286                 tryAgain = (retryCount > 0);
2287             }
2288
2289
2290             var notAvail = [];
2291             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292                 var item = onAvailStack[i];
2293                 if (item) {
2294                     var el = this.getEl(item.id);
2295
2296                     if (el) {
2297                         if (!item.checkReady ||
2298                             loadComplete ||
2299                             el.nextSibling ||
2300                             (document && document.body)) {
2301
2302                             var scope = el;
2303                             if (item.override) {
2304                                 if (item.override === true) {
2305                                     scope = item.obj;
2306                                 } else {
2307                                     scope = item.override;
2308                                 }
2309                             }
2310                             item.fn.call(scope, item.obj);
2311                             onAvailStack[i] = null;
2312                         }
2313                     } else {
2314                         notAvail.push(item);
2315                     }
2316                 }
2317             }
2318
2319             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2320
2321             if (tryAgain) {
2322
2323                 this.startInterval();
2324             } else {
2325                 clearInterval(this._interval);
2326                 this._interval = null;
2327             }
2328
2329             this.locked = false;
2330
2331             return true;
2332
2333         },
2334
2335
2336         purgeElement: function(el, recurse, eventName) {
2337             var elListeners = this.getListeners(el, eventName);
2338             if (elListeners) {
2339                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340                     var l = elListeners[i];
2341                     this.removeListener(el, l.type, l.fn);
2342                 }
2343             }
2344
2345             if (recurse && el && el.childNodes) {
2346                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347                     this.purgeElement(el.childNodes[i], recurse, eventName);
2348                 }
2349             }
2350         },
2351
2352
2353         getListeners: function(el, eventName) {
2354             var results = [], searchLists;
2355             if (!eventName) {
2356                 searchLists = [listeners, unloadListeners];
2357             } else if (eventName == "unload") {
2358                 searchLists = [unloadListeners];
2359             } else {
2360                 searchLists = [listeners];
2361             }
2362
2363             for (var j = 0; j < searchLists.length; ++j) {
2364                 var searchList = searchLists[j];
2365                 if (searchList && searchList.length > 0) {
2366                     for (var i = 0,len = searchList.length; i < len; ++i) {
2367                         var l = searchList[i];
2368                         if (l && l[this.EL] === el &&
2369                             (!eventName || eventName === l[this.TYPE])) {
2370                             results.push({
2371                                 type:   l[this.TYPE],
2372                                 fn:     l[this.FN],
2373                                 obj:    l[this.OBJ],
2374                                 adjust: l[this.ADJ_SCOPE],
2375                                 index:  i
2376                             });
2377                         }
2378                     }
2379                 }
2380             }
2381
2382             return (results.length) ? results : null;
2383         },
2384
2385
2386         _unload: function(e) {
2387
2388             var EU = Roo.lib.Event, i, j, l, len, index;
2389
2390             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391                 l = unloadListeners[i];
2392                 if (l) {
2393                     var scope = window;
2394                     if (l[EU.ADJ_SCOPE]) {
2395                         if (l[EU.ADJ_SCOPE] === true) {
2396                             scope = l[EU.OBJ];
2397                         } else {
2398                             scope = l[EU.ADJ_SCOPE];
2399                         }
2400                     }
2401                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402                     unloadListeners[i] = null;
2403                     l = null;
2404                     scope = null;
2405                 }
2406             }
2407
2408             unloadListeners = null;
2409
2410             if (listeners && listeners.length > 0) {
2411                 j = listeners.length;
2412                 while (j) {
2413                     index = j - 1;
2414                     l = listeners[index];
2415                     if (l) {
2416                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2417                                 l[EU.FN], index);
2418                     }
2419                     j = j - 1;
2420                 }
2421                 l = null;
2422
2423                 EU.clearCache();
2424             }
2425
2426             EU.doRemove(window, "unload", EU._unload);
2427
2428         },
2429
2430
2431         getScroll: function() {
2432             var dd = document.documentElement, db = document.body;
2433             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434                 return [dd.scrollTop, dd.scrollLeft];
2435             } else if (db) {
2436                 return [db.scrollTop, db.scrollLeft];
2437             } else {
2438                 return [0, 0];
2439             }
2440         },
2441
2442
2443         doAdd: function () {
2444             if (window.addEventListener) {
2445                 return function(el, eventName, fn, capture) {
2446                     el.addEventListener(eventName, fn, (capture));
2447                 };
2448             } else if (window.attachEvent) {
2449                 return function(el, eventName, fn, capture) {
2450                     el.attachEvent("on" + eventName, fn);
2451                 };
2452             } else {
2453                 return function() {
2454                 };
2455             }
2456         }(),
2457
2458
2459         doRemove: function() {
2460             if (window.removeEventListener) {
2461                 return function (el, eventName, fn, capture) {
2462                     el.removeEventListener(eventName, fn, (capture));
2463                 };
2464             } else if (window.detachEvent) {
2465                 return function (el, eventName, fn) {
2466                     el.detachEvent("on" + eventName, fn);
2467                 };
2468             } else {
2469                 return function() {
2470                 };
2471             }
2472         }()
2473     };
2474     
2475 }();
2476 (function() {     
2477    
2478     var E = Roo.lib.Event;
2479     E.on = E.addListener;
2480     E.un = E.removeListener;
2481
2482     if (document && document.body) {
2483         E._load();
2484     } else {
2485         E.doAdd(window, "load", E._load);
2486     }
2487     E.doAdd(window, "unload", E._unload);
2488     E._tryPreloadAttach();
2489 })();
2490
2491 /*
2492  * Portions of this file are based on pieces of Yahoo User Interface Library
2493  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494  * YUI licensed under the BSD License:
2495  * http://developer.yahoo.net/yui/license.txt
2496  * <script type="text/javascript">
2497  *
2498  */
2499
2500 (function() {
2501     /**
2502      * @class Roo.lib.Ajax
2503      *
2504      */
2505     Roo.lib.Ajax = {
2506         /**
2507          * @static 
2508          */
2509         request : function(method, uri, cb, data, options) {
2510             if(options){
2511                 var hs = options.headers;
2512                 if(hs){
2513                     for(var h in hs){
2514                         if(hs.hasOwnProperty(h)){
2515                             this.initHeader(h, hs[h], false);
2516                         }
2517                     }
2518                 }
2519                 if(options.xmlData){
2520                     this.initHeader('Content-Type', 'text/xml', false);
2521                     method = 'POST';
2522                     data = options.xmlData;
2523                 }
2524             }
2525
2526             return this.asyncRequest(method, uri, cb, data);
2527         },
2528
2529         serializeForm : function(form) {
2530             if(typeof form == 'string') {
2531                 form = (document.getElementById(form) || document.forms[form]);
2532             }
2533
2534             var el, name, val, disabled, data = '', hasSubmit = false;
2535             for (var i = 0; i < form.elements.length; i++) {
2536                 el = form.elements[i];
2537                 disabled = form.elements[i].disabled;
2538                 name = form.elements[i].name;
2539                 val = form.elements[i].value;
2540
2541                 if (!disabled && name){
2542                     switch (el.type)
2543                             {
2544                         case 'select-one':
2545                         case 'select-multiple':
2546                             for (var j = 0; j < el.options.length; j++) {
2547                                 if (el.options[j].selected) {
2548                                     if (Roo.isIE) {
2549                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2550                                     }
2551                                     else {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                 }
2555                             }
2556                             break;
2557                         case 'radio':
2558                         case 'checkbox':
2559                             if (el.checked) {
2560                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2561                             }
2562                             break;
2563                         case 'file':
2564
2565                         case undefined:
2566
2567                         case 'reset':
2568
2569                         case 'button':
2570
2571                             break;
2572                         case 'submit':
2573                             if(hasSubmit == false) {
2574                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2575                                 hasSubmit = true;
2576                             }
2577                             break;
2578                         default:
2579                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2580                             break;
2581                     }
2582                 }
2583             }
2584             data = data.substr(0, data.length - 1);
2585             return data;
2586         },
2587
2588         headers:{},
2589
2590         hasHeaders:false,
2591
2592         useDefaultHeader:true,
2593
2594         defaultPostHeader:'application/x-www-form-urlencoded',
2595
2596         useDefaultXhrHeader:true,
2597
2598         defaultXhrHeader:'XMLHttpRequest',
2599
2600         hasDefaultHeaders:true,
2601
2602         defaultHeaders:{},
2603
2604         poll:{},
2605
2606         timeout:{},
2607
2608         pollInterval:50,
2609
2610         transactionId:0,
2611
2612         setProgId:function(id)
2613         {
2614             this.activeX.unshift(id);
2615         },
2616
2617         setDefaultPostHeader:function(b)
2618         {
2619             this.useDefaultHeader = b;
2620         },
2621
2622         setDefaultXhrHeader:function(b)
2623         {
2624             this.useDefaultXhrHeader = b;
2625         },
2626
2627         setPollingInterval:function(i)
2628         {
2629             if (typeof i == 'number' && isFinite(i)) {
2630                 this.pollInterval = i;
2631             }
2632         },
2633
2634         createXhrObject:function(transactionId)
2635         {
2636             var obj,http;
2637             try
2638             {
2639
2640                 http = new XMLHttpRequest();
2641
2642                 obj = { conn:http, tId:transactionId };
2643             }
2644             catch(e)
2645             {
2646                 for (var i = 0; i < this.activeX.length; ++i) {
2647                     try
2648                     {
2649
2650                         http = new ActiveXObject(this.activeX[i]);
2651
2652                         obj = { conn:http, tId:transactionId };
2653                         break;
2654                     }
2655                     catch(e) {
2656                     }
2657                 }
2658             }
2659             finally
2660             {
2661                 return obj;
2662             }
2663         },
2664
2665         getConnectionObject:function()
2666         {
2667             var o;
2668             var tId = this.transactionId;
2669
2670             try
2671             {
2672                 o = this.createXhrObject(tId);
2673                 if (o) {
2674                     this.transactionId++;
2675                 }
2676             }
2677             catch(e) {
2678             }
2679             finally
2680             {
2681                 return o;
2682             }
2683         },
2684
2685         asyncRequest:function(method, uri, callback, postData)
2686         {
2687             var o = this.getConnectionObject();
2688
2689             if (!o) {
2690                 return null;
2691             }
2692             else {
2693                 o.conn.open(method, uri, true);
2694
2695                 if (this.useDefaultXhrHeader) {
2696                     if (!this.defaultHeaders['X-Requested-With']) {
2697                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2698                     }
2699                 }
2700
2701                 if(postData && this.useDefaultHeader){
2702                     this.initHeader('Content-Type', this.defaultPostHeader);
2703                 }
2704
2705                  if (this.hasDefaultHeaders || this.hasHeaders) {
2706                     this.setHeader(o);
2707                 }
2708
2709                 this.handleReadyState(o, callback);
2710                 o.conn.send(postData || null);
2711
2712                 return o;
2713             }
2714         },
2715
2716         handleReadyState:function(o, callback)
2717         {
2718             var oConn = this;
2719
2720             if (callback && callback.timeout) {
2721                 
2722                 this.timeout[o.tId] = window.setTimeout(function() {
2723                     oConn.abort(o, callback, true);
2724                 }, callback.timeout);
2725             }
2726
2727             this.poll[o.tId] = window.setInterval(
2728                     function() {
2729                         if (o.conn && o.conn.readyState == 4) {
2730                             window.clearInterval(oConn.poll[o.tId]);
2731                             delete oConn.poll[o.tId];
2732
2733                             if(callback && callback.timeout) {
2734                                 window.clearTimeout(oConn.timeout[o.tId]);
2735                                 delete oConn.timeout[o.tId];
2736                             }
2737
2738                             oConn.handleTransactionResponse(o, callback);
2739                         }
2740                     }
2741                     , this.pollInterval);
2742         },
2743
2744         handleTransactionResponse:function(o, callback, isAbort)
2745         {
2746
2747             if (!callback) {
2748                 this.releaseObject(o);
2749                 return;
2750             }
2751
2752             var httpStatus, responseObject;
2753
2754             try
2755             {
2756                 if (o.conn.status !== undefined && o.conn.status != 0) {
2757                     httpStatus = o.conn.status;
2758                 }
2759                 else {
2760                     httpStatus = 13030;
2761                 }
2762             }
2763             catch(e) {
2764
2765
2766                 httpStatus = 13030;
2767             }
2768
2769             if (httpStatus >= 200 && httpStatus < 300) {
2770                 responseObject = this.createResponseObject(o, callback.argument);
2771                 if (callback.success) {
2772                     if (!callback.scope) {
2773                         callback.success(responseObject);
2774                     }
2775                     else {
2776
2777
2778                         callback.success.apply(callback.scope, [responseObject]);
2779                     }
2780                 }
2781             }
2782             else {
2783                 switch (httpStatus) {
2784
2785                     case 12002:
2786                     case 12029:
2787                     case 12030:
2788                     case 12031:
2789                     case 12152:
2790                     case 13030:
2791                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792                         if (callback.failure) {
2793                             if (!callback.scope) {
2794                                 callback.failure(responseObject);
2795                             }
2796                             else {
2797                                 callback.failure.apply(callback.scope, [responseObject]);
2798                             }
2799                         }
2800                         break;
2801                     default:
2802                         responseObject = this.createResponseObject(o, callback.argument);
2803                         if (callback.failure) {
2804                             if (!callback.scope) {
2805                                 callback.failure(responseObject);
2806                             }
2807                             else {
2808                                 callback.failure.apply(callback.scope, [responseObject]);
2809                             }
2810                         }
2811                 }
2812             }
2813
2814             this.releaseObject(o);
2815             responseObject = null;
2816         },
2817
2818         createResponseObject:function(o, callbackArg)
2819         {
2820             var obj = {};
2821             var headerObj = {};
2822
2823             try
2824             {
2825                 var headerStr = o.conn.getAllResponseHeaders();
2826                 var header = headerStr.split('\n');
2827                 for (var i = 0; i < header.length; i++) {
2828                     var delimitPos = header[i].indexOf(':');
2829                     if (delimitPos != -1) {
2830                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2831                     }
2832                 }
2833             }
2834             catch(e) {
2835             }
2836
2837             obj.tId = o.tId;
2838             obj.status = o.conn.status;
2839             obj.statusText = o.conn.statusText;
2840             obj.getResponseHeader = headerObj;
2841             obj.getAllResponseHeaders = headerStr;
2842             obj.responseText = o.conn.responseText;
2843             obj.responseXML = o.conn.responseXML;
2844
2845             if (typeof callbackArg !== undefined) {
2846                 obj.argument = callbackArg;
2847             }
2848
2849             return obj;
2850         },
2851
2852         createExceptionObject:function(tId, callbackArg, isAbort)
2853         {
2854             var COMM_CODE = 0;
2855             var COMM_ERROR = 'communication failure';
2856             var ABORT_CODE = -1;
2857             var ABORT_ERROR = 'transaction aborted';
2858
2859             var obj = {};
2860
2861             obj.tId = tId;
2862             if (isAbort) {
2863                 obj.status = ABORT_CODE;
2864                 obj.statusText = ABORT_ERROR;
2865             }
2866             else {
2867                 obj.status = COMM_CODE;
2868                 obj.statusText = COMM_ERROR;
2869             }
2870
2871             if (callbackArg) {
2872                 obj.argument = callbackArg;
2873             }
2874
2875             return obj;
2876         },
2877
2878         initHeader:function(label, value, isDefault)
2879         {
2880             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2881
2882             if (headerObj[label] === undefined) {
2883                 headerObj[label] = value;
2884             }
2885             else {
2886
2887
2888                 headerObj[label] = value + "," + headerObj[label];
2889             }
2890
2891             if (isDefault) {
2892                 this.hasDefaultHeaders = true;
2893             }
2894             else {
2895                 this.hasHeaders = true;
2896             }
2897         },
2898
2899
2900         setHeader:function(o)
2901         {
2902             if (this.hasDefaultHeaders) {
2903                 for (var prop in this.defaultHeaders) {
2904                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2905                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2906                     }
2907                 }
2908             }
2909
2910             if (this.hasHeaders) {
2911                 for (var prop in this.headers) {
2912                     if (this.headers.hasOwnProperty(prop)) {
2913                         o.conn.setRequestHeader(prop, this.headers[prop]);
2914                     }
2915                 }
2916                 this.headers = {};
2917                 this.hasHeaders = false;
2918             }
2919         },
2920
2921         resetDefaultHeaders:function() {
2922             delete this.defaultHeaders;
2923             this.defaultHeaders = {};
2924             this.hasDefaultHeaders = false;
2925         },
2926
2927         abort:function(o, callback, isTimeout)
2928         {
2929             if(this.isCallInProgress(o)) {
2930                 o.conn.abort();
2931                 window.clearInterval(this.poll[o.tId]);
2932                 delete this.poll[o.tId];
2933                 if (isTimeout) {
2934                     delete this.timeout[o.tId];
2935                 }
2936
2937                 this.handleTransactionResponse(o, callback, true);
2938
2939                 return true;
2940             }
2941             else {
2942                 return false;
2943             }
2944         },
2945
2946
2947         isCallInProgress:function(o)
2948         {
2949             if (o && o.conn) {
2950                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2951             }
2952             else {
2953
2954                 return false;
2955             }
2956         },
2957
2958
2959         releaseObject:function(o)
2960         {
2961
2962             o.conn = null;
2963
2964             o = null;
2965         },
2966
2967         activeX:[
2968         'MSXML2.XMLHTTP.3.0',
2969         'MSXML2.XMLHTTP',
2970         'Microsoft.XMLHTTP'
2971         ]
2972
2973
2974     };
2975 })();/*
2976  * Portions of this file are based on pieces of Yahoo User Interface Library
2977  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978  * YUI licensed under the BSD License:
2979  * http://developer.yahoo.net/yui/license.txt
2980  * <script type="text/javascript">
2981  *
2982  */
2983
2984 Roo.lib.Region = function(t, r, b, l) {
2985     this.top = t;
2986     this[1] = t;
2987     this.right = r;
2988     this.bottom = b;
2989     this.left = l;
2990     this[0] = l;
2991 };
2992
2993
2994 Roo.lib.Region.prototype = {
2995     contains : function(region) {
2996         return ( region.left >= this.left &&
2997                  region.right <= this.right &&
2998                  region.top >= this.top &&
2999                  region.bottom <= this.bottom    );
3000
3001     },
3002
3003     getArea : function() {
3004         return ( (this.bottom - this.top) * (this.right - this.left) );
3005     },
3006
3007     intersect : function(region) {
3008         var t = Math.max(this.top, region.top);
3009         var r = Math.min(this.right, region.right);
3010         var b = Math.min(this.bottom, region.bottom);
3011         var l = Math.max(this.left, region.left);
3012
3013         if (b >= t && r >= l) {
3014             return new Roo.lib.Region(t, r, b, l);
3015         } else {
3016             return null;
3017         }
3018     },
3019     union : function(region) {
3020         var t = Math.min(this.top, region.top);
3021         var r = Math.max(this.right, region.right);
3022         var b = Math.max(this.bottom, region.bottom);
3023         var l = Math.min(this.left, region.left);
3024
3025         return new Roo.lib.Region(t, r, b, l);
3026     },
3027
3028     adjust : function(t, l, b, r) {
3029         this.top += t;
3030         this.left += l;
3031         this.right += r;
3032         this.bottom += b;
3033         return this;
3034     }
3035 };
3036
3037 Roo.lib.Region.getRegion = function(el) {
3038     var p = Roo.lib.Dom.getXY(el);
3039
3040     var t = p[1];
3041     var r = p[0] + el.offsetWidth;
3042     var b = p[1] + el.offsetHeight;
3043     var l = p[0];
3044
3045     return new Roo.lib.Region(t, r, b, l);
3046 };
3047 /*
3048  * Portions of this file are based on pieces of Yahoo User Interface Library
3049  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050  * YUI licensed under the BSD License:
3051  * http://developer.yahoo.net/yui/license.txt
3052  * <script type="text/javascript">
3053  *
3054  */
3055 //@@dep Roo.lib.Region
3056
3057
3058 Roo.lib.Point = function(x, y) {
3059     if (x instanceof Array) {
3060         y = x[1];
3061         x = x[0];
3062     }
3063     this.x = this.right = this.left = this[0] = x;
3064     this.y = this.top = this.bottom = this[1] = y;
3065 };
3066
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3068 /*
3069  * Portions of this file are based on pieces of Yahoo User Interface Library
3070  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071  * YUI licensed under the BSD License:
3072  * http://developer.yahoo.net/yui/license.txt
3073  * <script type="text/javascript">
3074  *
3075  */
3076  
3077 (function() {   
3078
3079     Roo.lib.Anim = {
3080         scroll : function(el, args, duration, easing, cb, scope) {
3081             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3082         },
3083
3084         motion : function(el, args, duration, easing, cb, scope) {
3085             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3086         },
3087
3088         color : function(el, args, duration, easing, cb, scope) {
3089             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3090         },
3091
3092         run : function(el, args, duration, easing, cb, scope, type) {
3093             type = type || Roo.lib.AnimBase;
3094             if (typeof easing == "string") {
3095                 easing = Roo.lib.Easing[easing];
3096             }
3097             var anim = new type(el, args, duration, easing);
3098             anim.animateX(function() {
3099                 Roo.callback(cb, scope);
3100             });
3101             return anim;
3102         }
3103     };
3104 })();/*
3105  * Portions of this file are based on pieces of Yahoo User Interface Library
3106  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107  * YUI licensed under the BSD License:
3108  * http://developer.yahoo.net/yui/license.txt
3109  * <script type="text/javascript">
3110  *
3111  */
3112
3113 (function() {    
3114     var libFlyweight;
3115     
3116     function fly(el) {
3117         if (!libFlyweight) {
3118             libFlyweight = new Roo.Element.Flyweight();
3119         }
3120         libFlyweight.dom = el;
3121         return libFlyweight;
3122     }
3123
3124     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3125     
3126    
3127     
3128     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3129         if (el) {
3130             this.init(el, attributes, duration, method);
3131         }
3132     };
3133
3134     Roo.lib.AnimBase.fly = fly;
3135     
3136     
3137     
3138     Roo.lib.AnimBase.prototype = {
3139
3140         toString: function() {
3141             var el = this.getEl();
3142             var id = el.id || el.tagName;
3143             return ("Anim " + id);
3144         },
3145
3146         patterns: {
3147             noNegatives:        /width|height|opacity|padding/i,
3148             offsetAttribute:  /^((width|height)|(top|left))$/,
3149             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3150             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3151         },
3152
3153
3154         doMethod: function(attr, start, end) {
3155             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3156         },
3157
3158
3159         setAttribute: function(attr, val, unit) {
3160             if (this.patterns.noNegatives.test(attr)) {
3161                 val = (val > 0) ? val : 0;
3162             }
3163
3164             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3165         },
3166
3167
3168         getAttribute: function(attr) {
3169             var el = this.getEl();
3170             var val = fly(el).getStyle(attr);
3171
3172             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173                 return parseFloat(val);
3174             }
3175
3176             var a = this.patterns.offsetAttribute.exec(attr) || [];
3177             var pos = !!( a[3] );
3178             var box = !!( a[2] );
3179
3180
3181             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3183             } else {
3184                 val = 0;
3185             }
3186
3187             return val;
3188         },
3189
3190
3191         getDefaultUnit: function(attr) {
3192             if (this.patterns.defaultUnit.test(attr)) {
3193                 return 'px';
3194             }
3195
3196             return '';
3197         },
3198
3199         animateX : function(callback, scope) {
3200             var f = function() {
3201                 this.onComplete.removeListener(f);
3202                 if (typeof callback == "function") {
3203                     callback.call(scope || this, this);
3204                 }
3205             };
3206             this.onComplete.addListener(f, this);
3207             this.animate();
3208         },
3209
3210
3211         setRuntimeAttribute: function(attr) {
3212             var start;
3213             var end;
3214             var attributes = this.attributes;
3215
3216             this.runtimeAttributes[attr] = {};
3217
3218             var isset = function(prop) {
3219                 return (typeof prop !== 'undefined');
3220             };
3221
3222             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3223                 return false;
3224             }
3225
3226             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3227
3228
3229             if (isset(attributes[attr]['to'])) {
3230                 end = attributes[attr]['to'];
3231             } else if (isset(attributes[attr]['by'])) {
3232                 if (start.constructor == Array) {
3233                     end = [];
3234                     for (var i = 0, len = start.length; i < len; ++i) {
3235                         end[i] = start[i] + attributes[attr]['by'][i];
3236                     }
3237                 } else {
3238                     end = start + attributes[attr]['by'];
3239                 }
3240             }
3241
3242             this.runtimeAttributes[attr].start = start;
3243             this.runtimeAttributes[attr].end = end;
3244
3245
3246             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3247         },
3248
3249
3250         init: function(el, attributes, duration, method) {
3251
3252             var isAnimated = false;
3253
3254
3255             var startTime = null;
3256
3257
3258             var actualFrames = 0;
3259
3260
3261             el = Roo.getDom(el);
3262
3263
3264             this.attributes = attributes || {};
3265
3266
3267             this.duration = duration || 1;
3268
3269
3270             this.method = method || Roo.lib.Easing.easeNone;
3271
3272
3273             this.useSeconds = true;
3274
3275
3276             this.currentFrame = 0;
3277
3278
3279             this.totalFrames = Roo.lib.AnimMgr.fps;
3280
3281
3282             this.getEl = function() {
3283                 return el;
3284             };
3285
3286
3287             this.isAnimated = function() {
3288                 return isAnimated;
3289             };
3290
3291
3292             this.getStartTime = function() {
3293                 return startTime;
3294             };
3295
3296             this.runtimeAttributes = {};
3297
3298
3299             this.animate = function() {
3300                 if (this.isAnimated()) {
3301                     return false;
3302                 }
3303
3304                 this.currentFrame = 0;
3305
3306                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3307
3308                 Roo.lib.AnimMgr.registerElement(this);
3309             };
3310
3311
3312             this.stop = function(finish) {
3313                 if (finish) {
3314                     this.currentFrame = this.totalFrames;
3315                     this._onTween.fire();
3316                 }
3317                 Roo.lib.AnimMgr.stop(this);
3318             };
3319
3320             var onStart = function() {
3321                 this.onStart.fire();
3322
3323                 this.runtimeAttributes = {};
3324                 for (var attr in this.attributes) {
3325                     this.setRuntimeAttribute(attr);
3326                 }
3327
3328                 isAnimated = true;
3329                 actualFrames = 0;
3330                 startTime = new Date();
3331             };
3332
3333
3334             var onTween = function() {
3335                 var data = {
3336                     duration: new Date() - this.getStartTime(),
3337                     currentFrame: this.currentFrame
3338                 };
3339
3340                 data.toString = function() {
3341                     return (
3342                             'duration: ' + data.duration +
3343                             ', currentFrame: ' + data.currentFrame
3344                             );
3345                 };
3346
3347                 this.onTween.fire(data);
3348
3349                 var runtimeAttributes = this.runtimeAttributes;
3350
3351                 for (var attr in runtimeAttributes) {
3352                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3353                 }
3354
3355                 actualFrames += 1;
3356             };
3357
3358             var onComplete = function() {
3359                 var actual_duration = (new Date() - startTime) / 1000 ;
3360
3361                 var data = {
3362                     duration: actual_duration,
3363                     frames: actualFrames,
3364                     fps: actualFrames / actual_duration
3365                 };
3366
3367                 data.toString = function() {
3368                     return (
3369                             'duration: ' + data.duration +
3370                             ', frames: ' + data.frames +
3371                             ', fps: ' + data.fps
3372                             );
3373                 };
3374
3375                 isAnimated = false;
3376                 actualFrames = 0;
3377                 this.onComplete.fire(data);
3378             };
3379
3380
3381             this._onStart = new Roo.util.Event(this);
3382             this.onStart = new Roo.util.Event(this);
3383             this.onTween = new Roo.util.Event(this);
3384             this._onTween = new Roo.util.Event(this);
3385             this.onComplete = new Roo.util.Event(this);
3386             this._onComplete = new Roo.util.Event(this);
3387             this._onStart.addListener(onStart);
3388             this._onTween.addListener(onTween);
3389             this._onComplete.addListener(onComplete);
3390         }
3391     };
3392 })();
3393 /*
3394  * Portions of this file are based on pieces of Yahoo User Interface Library
3395  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396  * YUI licensed under the BSD License:
3397  * http://developer.yahoo.net/yui/license.txt
3398  * <script type="text/javascript">
3399  *
3400  */
3401
3402 Roo.lib.AnimMgr = new function() {
3403
3404     var thread = null;
3405
3406
3407     var queue = [];
3408
3409
3410     var tweenCount = 0;
3411
3412
3413     this.fps = 1000;
3414
3415
3416     this.delay = 1;
3417
3418
3419     this.registerElement = function(tween) {
3420         queue[queue.length] = tween;
3421         tweenCount += 1;
3422         tween._onStart.fire();
3423         this.start();
3424     };
3425
3426
3427     this.unRegister = function(tween, index) {
3428         tween._onComplete.fire();
3429         index = index || getIndex(tween);
3430         if (index != -1) {
3431             queue.splice(index, 1);
3432         }
3433
3434         tweenCount -= 1;
3435         if (tweenCount <= 0) {
3436             this.stop();
3437         }
3438     };
3439
3440
3441     this.start = function() {
3442         if (thread === null) {
3443             thread = setInterval(this.run, this.delay);
3444         }
3445     };
3446
3447
3448     this.stop = function(tween) {
3449         if (!tween) {
3450             clearInterval(thread);
3451
3452             for (var i = 0, len = queue.length; i < len; ++i) {
3453                 if (queue[0].isAnimated()) {
3454                     this.unRegister(queue[0], 0);
3455                 }
3456             }
3457
3458             queue = [];
3459             thread = null;
3460             tweenCount = 0;
3461         }
3462         else {
3463             this.unRegister(tween);
3464         }
3465     };
3466
3467
3468     this.run = function() {
3469         for (var i = 0, len = queue.length; i < len; ++i) {
3470             var tween = queue[i];
3471             if (!tween || !tween.isAnimated()) {
3472                 continue;
3473             }
3474
3475             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3476             {
3477                 tween.currentFrame += 1;
3478
3479                 if (tween.useSeconds) {
3480                     correctFrame(tween);
3481                 }
3482                 tween._onTween.fire();
3483             }
3484             else {
3485                 Roo.lib.AnimMgr.stop(tween, i);
3486             }
3487         }
3488     };
3489
3490     var getIndex = function(anim) {
3491         for (var i = 0, len = queue.length; i < len; ++i) {
3492             if (queue[i] == anim) {
3493                 return i;
3494             }
3495         }
3496         return -1;
3497     };
3498
3499
3500     var correctFrame = function(tween) {
3501         var frames = tween.totalFrames;
3502         var frame = tween.currentFrame;
3503         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504         var elapsed = (new Date() - tween.getStartTime());
3505         var tweak = 0;
3506
3507         if (elapsed < tween.duration * 1000) {
3508             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3509         } else {
3510             tweak = frames - (frame + 1);
3511         }
3512         if (tweak > 0 && isFinite(tweak)) {
3513             if (tween.currentFrame + tweak >= frames) {
3514                 tweak = frames - (frame + 1);
3515             }
3516
3517             tween.currentFrame += tweak;
3518         }
3519     };
3520 };
3521
3522     /*
3523  * Portions of this file are based on pieces of Yahoo User Interface Library
3524  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525  * YUI licensed under the BSD License:
3526  * http://developer.yahoo.net/yui/license.txt
3527  * <script type="text/javascript">
3528  *
3529  */
3530 Roo.lib.Bezier = new function() {
3531
3532         this.getPosition = function(points, t) {
3533             var n = points.length;
3534             var tmp = [];
3535
3536             for (var i = 0; i < n; ++i) {
3537                 tmp[i] = [points[i][0], points[i][1]];
3538             }
3539
3540             for (var j = 1; j < n; ++j) {
3541                 for (i = 0; i < n - j; ++i) {
3542                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3544                 }
3545             }
3546
3547             return [ tmp[0][0], tmp[0][1] ];
3548
3549         };
3550     };/*
3551  * Portions of this file are based on pieces of Yahoo User Interface Library
3552  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553  * YUI licensed under the BSD License:
3554  * http://developer.yahoo.net/yui/license.txt
3555  * <script type="text/javascript">
3556  *
3557  */
3558 (function() {
3559
3560     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3562     };
3563
3564     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3565
3566     var fly = Roo.lib.AnimBase.fly;
3567     var Y = Roo.lib;
3568     var superclass = Y.ColorAnim.superclass;
3569     var proto = Y.ColorAnim.prototype;
3570
3571     proto.toString = function() {
3572         var el = this.getEl();
3573         var id = el.id || el.tagName;
3574         return ("ColorAnim " + id);
3575     };
3576
3577     proto.patterns.color = /color$/i;
3578     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3582
3583
3584     proto.parseColor = function(s) {
3585         if (s.length == 3) {
3586             return s;
3587         }
3588
3589         var c = this.patterns.hex.exec(s);
3590         if (c && c.length == 4) {
3591             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3592         }
3593
3594         c = this.patterns.rgb.exec(s);
3595         if (c && c.length == 4) {
3596             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3597         }
3598
3599         c = this.patterns.hex3.exec(s);
3600         if (c && c.length == 4) {
3601             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3602         }
3603
3604         return null;
3605     };
3606     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607     proto.getAttribute = function(attr) {
3608         var el = this.getEl();
3609         if (this.patterns.color.test(attr)) {
3610             var val = fly(el).getStyle(attr);
3611
3612             if (this.patterns.transparent.test(val)) {
3613                 var parent = el.parentNode;
3614                 val = fly(parent).getStyle(attr);
3615
3616                 while (parent && this.patterns.transparent.test(val)) {
3617                     parent = parent.parentNode;
3618                     val = fly(parent).getStyle(attr);
3619                     if (parent.tagName.toUpperCase() == 'HTML') {
3620                         val = '#fff';
3621                     }
3622                 }
3623             }
3624         } else {
3625             val = superclass.getAttribute.call(this, attr);
3626         }
3627
3628         return val;
3629     };
3630     proto.getAttribute = function(attr) {
3631         var el = this.getEl();
3632         if (this.patterns.color.test(attr)) {
3633             var val = fly(el).getStyle(attr);
3634
3635             if (this.patterns.transparent.test(val)) {
3636                 var parent = el.parentNode;
3637                 val = fly(parent).getStyle(attr);
3638
3639                 while (parent && this.patterns.transparent.test(val)) {
3640                     parent = parent.parentNode;
3641                     val = fly(parent).getStyle(attr);
3642                     if (parent.tagName.toUpperCase() == 'HTML') {
3643                         val = '#fff';
3644                     }
3645                 }
3646             }
3647         } else {
3648             val = superclass.getAttribute.call(this, attr);
3649         }
3650
3651         return val;
3652     };
3653
3654     proto.doMethod = function(attr, start, end) {
3655         var val;
3656
3657         if (this.patterns.color.test(attr)) {
3658             val = [];
3659             for (var i = 0, len = start.length; i < len; ++i) {
3660                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3661             }
3662
3663             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3664         }
3665         else {
3666             val = superclass.doMethod.call(this, attr, start, end);
3667         }
3668
3669         return val;
3670     };
3671
3672     proto.setRuntimeAttribute = function(attr) {
3673         superclass.setRuntimeAttribute.call(this, attr);
3674
3675         if (this.patterns.color.test(attr)) {
3676             var attributes = this.attributes;
3677             var start = this.parseColor(this.runtimeAttributes[attr].start);
3678             var end = this.parseColor(this.runtimeAttributes[attr].end);
3679
3680             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681                 end = this.parseColor(attributes[attr].by);
3682
3683                 for (var i = 0, len = start.length; i < len; ++i) {
3684                     end[i] = start[i] + end[i];
3685                 }
3686             }
3687
3688             this.runtimeAttributes[attr].start = start;
3689             this.runtimeAttributes[attr].end = end;
3690         }
3691     };
3692 })();
3693
3694 /*
3695  * Portions of this file are based on pieces of Yahoo User Interface Library
3696  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697  * YUI licensed under the BSD License:
3698  * http://developer.yahoo.net/yui/license.txt
3699  * <script type="text/javascript">
3700  *
3701  */
3702 Roo.lib.Easing = {
3703
3704
3705     easeNone: function (t, b, c, d) {
3706         return c * t / d + b;
3707     },
3708
3709
3710     easeIn: function (t, b, c, d) {
3711         return c * (t /= d) * t + b;
3712     },
3713
3714
3715     easeOut: function (t, b, c, d) {
3716         return -c * (t /= d) * (t - 2) + b;
3717     },
3718
3719
3720     easeBoth: function (t, b, c, d) {
3721         if ((t /= d / 2) < 1) {
3722             return c / 2 * t * t + b;
3723         }
3724
3725         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3726     },
3727
3728
3729     easeInStrong: function (t, b, c, d) {
3730         return c * (t /= d) * t * t * t + b;
3731     },
3732
3733
3734     easeOutStrong: function (t, b, c, d) {
3735         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3736     },
3737
3738
3739     easeBothStrong: function (t, b, c, d) {
3740         if ((t /= d / 2) < 1) {
3741             return c / 2 * t * t * t * t + b;
3742         }
3743
3744         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3745     },
3746
3747
3748
3749     elasticIn: function (t, b, c, d, a, p) {
3750         if (t == 0) {
3751             return b;
3752         }
3753         if ((t /= d) == 1) {
3754             return b + c;
3755         }
3756         if (!p) {
3757             p = d * .3;
3758         }
3759
3760         if (!a || a < Math.abs(c)) {
3761             a = c;
3762             var s = p / 4;
3763         }
3764         else {
3765             var s = p / (2 * Math.PI) * Math.asin(c / a);
3766         }
3767
3768         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3769     },
3770
3771
3772     elasticOut: function (t, b, c, d, a, p) {
3773         if (t == 0) {
3774             return b;
3775         }
3776         if ((t /= d) == 1) {
3777             return b + c;
3778         }
3779         if (!p) {
3780             p = d * .3;
3781         }
3782
3783         if (!a || a < Math.abs(c)) {
3784             a = c;
3785             var s = p / 4;
3786         }
3787         else {
3788             var s = p / (2 * Math.PI) * Math.asin(c / a);
3789         }
3790
3791         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3792     },
3793
3794
3795     elasticBoth: function (t, b, c, d, a, p) {
3796         if (t == 0) {
3797             return b;
3798         }
3799
3800         if ((t /= d / 2) == 2) {
3801             return b + c;
3802         }
3803
3804         if (!p) {
3805             p = d * (.3 * 1.5);
3806         }
3807
3808         if (!a || a < Math.abs(c)) {
3809             a = c;
3810             var s = p / 4;
3811         }
3812         else {
3813             var s = p / (2 * Math.PI) * Math.asin(c / a);
3814         }
3815
3816         if (t < 1) {
3817             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3819         }
3820         return a * Math.pow(2, -10 * (t -= 1)) *
3821                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3822     },
3823
3824
3825
3826     backIn: function (t, b, c, d, s) {
3827         if (typeof s == 'undefined') {
3828             s = 1.70158;
3829         }
3830         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3831     },
3832
3833
3834     backOut: function (t, b, c, d, s) {
3835         if (typeof s == 'undefined') {
3836             s = 1.70158;
3837         }
3838         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3839     },
3840
3841
3842     backBoth: function (t, b, c, d, s) {
3843         if (typeof s == 'undefined') {
3844             s = 1.70158;
3845         }
3846
3847         if ((t /= d / 2 ) < 1) {
3848             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3849         }
3850         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3851     },
3852
3853
3854     bounceIn: function (t, b, c, d) {
3855         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3856     },
3857
3858
3859     bounceOut: function (t, b, c, d) {
3860         if ((t /= d) < (1 / 2.75)) {
3861             return c * (7.5625 * t * t) + b;
3862         } else if (t < (2 / 2.75)) {
3863             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864         } else if (t < (2.5 / 2.75)) {
3865             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3866         }
3867         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3868     },
3869
3870
3871     bounceBoth: function (t, b, c, d) {
3872         if (t < d / 2) {
3873             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3874         }
3875         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3876     }
3877 };/*
3878  * Portions of this file are based on pieces of Yahoo User Interface Library
3879  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880  * YUI licensed under the BSD License:
3881  * http://developer.yahoo.net/yui/license.txt
3882  * <script type="text/javascript">
3883  *
3884  */
3885     (function() {
3886         Roo.lib.Motion = function(el, attributes, duration, method) {
3887             if (el) {
3888                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3889             }
3890         };
3891
3892         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3893
3894
3895         var Y = Roo.lib;
3896         var superclass = Y.Motion.superclass;
3897         var proto = Y.Motion.prototype;
3898
3899         proto.toString = function() {
3900             var el = this.getEl();
3901             var id = el.id || el.tagName;
3902             return ("Motion " + id);
3903         };
3904
3905         proto.patterns.points = /^points$/i;
3906
3907         proto.setAttribute = function(attr, val, unit) {
3908             if (this.patterns.points.test(attr)) {
3909                 unit = unit || 'px';
3910                 superclass.setAttribute.call(this, 'left', val[0], unit);
3911                 superclass.setAttribute.call(this, 'top', val[1], unit);
3912             } else {
3913                 superclass.setAttribute.call(this, attr, val, unit);
3914             }
3915         };
3916
3917         proto.getAttribute = function(attr) {
3918             if (this.patterns.points.test(attr)) {
3919                 var val = [
3920                         superclass.getAttribute.call(this, 'left'),
3921                         superclass.getAttribute.call(this, 'top')
3922                         ];
3923             } else {
3924                 val = superclass.getAttribute.call(this, attr);
3925             }
3926
3927             return val;
3928         };
3929
3930         proto.doMethod = function(attr, start, end) {
3931             var val = null;
3932
3933             if (this.patterns.points.test(attr)) {
3934                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3936             } else {
3937                 val = superclass.doMethod.call(this, attr, start, end);
3938             }
3939             return val;
3940         };
3941
3942         proto.setRuntimeAttribute = function(attr) {
3943             if (this.patterns.points.test(attr)) {
3944                 var el = this.getEl();
3945                 var attributes = this.attributes;
3946                 var start;
3947                 var control = attributes['points']['control'] || [];
3948                 var end;
3949                 var i, len;
3950
3951                 if (control.length > 0 && !(control[0] instanceof Array)) {
3952                     control = [control];
3953                 } else {
3954                     var tmp = [];
3955                     for (i = 0,len = control.length; i < len; ++i) {
3956                         tmp[i] = control[i];
3957                     }
3958                     control = tmp;
3959                 }
3960
3961                 Roo.fly(el).position();
3962
3963                 if (isset(attributes['points']['from'])) {
3964                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3965                 }
3966                 else {
3967                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3968                 }
3969
3970                 start = this.getAttribute('points');
3971
3972
3973                 if (isset(attributes['points']['to'])) {
3974                     end = translateValues.call(this, attributes['points']['to'], start);
3975
3976                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977                     for (i = 0,len = control.length; i < len; ++i) {
3978                         control[i] = translateValues.call(this, control[i], start);
3979                     }
3980
3981
3982                 } else if (isset(attributes['points']['by'])) {
3983                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3984
3985                     for (i = 0,len = control.length; i < len; ++i) {
3986                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3987                     }
3988                 }
3989
3990                 this.runtimeAttributes[attr] = [start];
3991
3992                 if (control.length > 0) {
3993                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3994                 }
3995
3996                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3997             }
3998             else {
3999                 superclass.setRuntimeAttribute.call(this, attr);
4000             }
4001         };
4002
4003         var translateValues = function(val, start) {
4004             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4006
4007             return val;
4008         };
4009
4010         var isset = function(prop) {
4011             return (typeof prop !== 'undefined');
4012         };
4013     })();
4014 /*
4015  * Portions of this file are based on pieces of Yahoo User Interface Library
4016  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017  * YUI licensed under the BSD License:
4018  * http://developer.yahoo.net/yui/license.txt
4019  * <script type="text/javascript">
4020  *
4021  */
4022     (function() {
4023         Roo.lib.Scroll = function(el, attributes, duration, method) {
4024             if (el) {
4025                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4026             }
4027         };
4028
4029         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4030
4031
4032         var Y = Roo.lib;
4033         var superclass = Y.Scroll.superclass;
4034         var proto = Y.Scroll.prototype;
4035
4036         proto.toString = function() {
4037             var el = this.getEl();
4038             var id = el.id || el.tagName;
4039             return ("Scroll " + id);
4040         };
4041
4042         proto.doMethod = function(attr, start, end) {
4043             var val = null;
4044
4045             if (attr == 'scroll') {
4046                 val = [
4047                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4049                         ];
4050
4051             } else {
4052                 val = superclass.doMethod.call(this, attr, start, end);
4053             }
4054             return val;
4055         };
4056
4057         proto.getAttribute = function(attr) {
4058             var val = null;
4059             var el = this.getEl();
4060
4061             if (attr == 'scroll') {
4062                 val = [ el.scrollLeft, el.scrollTop ];
4063             } else {
4064                 val = superclass.getAttribute.call(this, attr);
4065             }
4066
4067             return val;
4068         };
4069
4070         proto.setAttribute = function(attr, val, unit) {
4071             var el = this.getEl();
4072
4073             if (attr == 'scroll') {
4074                 el.scrollLeft = val[0];
4075                 el.scrollTop = val[1];
4076             } else {
4077                 superclass.setAttribute.call(this, attr, val, unit);
4078             }
4079         };
4080     })();
4081 /*
4082  * Based on:
4083  * Ext JS Library 1.1.1
4084  * Copyright(c) 2006-2007, Ext JS, LLC.
4085  *
4086  * Originally Released Under LGPL - original licence link has changed is not relivant.
4087  *
4088  * Fork - LGPL
4089  * <script type="text/javascript">
4090  */
4091
4092
4093 // nasty IE9 hack - what a pile of crap that is..
4094
4095  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096     Range.prototype.createContextualFragment = function (html) {
4097         var doc = window.document;
4098         var container = doc.createElement("div");
4099         container.innerHTML = html;
4100         var frag = doc.createDocumentFragment(), n;
4101         while ((n = container.firstChild)) {
4102             frag.appendChild(n);
4103         }
4104         return frag;
4105     };
4106 }
4107
4108 /**
4109  * @class Roo.DomHelper
4110  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111  * 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>.
4112  * @singleton
4113  */
4114 Roo.DomHelper = function(){
4115     var tempTableEl = null;
4116     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117     var tableRe = /^table|tbody|tr|td$/i;
4118     var xmlns = {};
4119     // build as innerHTML where available
4120     /** @ignore */
4121     var createHtml = function(o){
4122         if(typeof o == 'string'){
4123             return o;
4124         }
4125         var b = "";
4126         if(!o.tag){
4127             o.tag = "div";
4128         }
4129         b += "<" + o.tag;
4130         for(var attr in o){
4131             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132             if(attr == "style"){
4133                 var s = o["style"];
4134                 if(typeof s == "function"){
4135                     s = s.call();
4136                 }
4137                 if(typeof s == "string"){
4138                     b += ' style="' + s + '"';
4139                 }else if(typeof s == "object"){
4140                     b += ' style="';
4141                     for(var key in s){
4142                         if(typeof s[key] != "function"){
4143                             b += key + ":" + s[key] + ";";
4144                         }
4145                     }
4146                     b += '"';
4147                 }
4148             }else{
4149                 if(attr == "cls"){
4150                     b += ' class="' + o["cls"] + '"';
4151                 }else if(attr == "htmlFor"){
4152                     b += ' for="' + o["htmlFor"] + '"';
4153                 }else{
4154                     b += " " + attr + '="' + o[attr] + '"';
4155                 }
4156             }
4157         }
4158         if(emptyTags.test(o.tag)){
4159             b += "/>";
4160         }else{
4161             b += ">";
4162             var cn = o.children || o.cn;
4163             if(cn){
4164                 //http://bugs.kde.org/show_bug.cgi?id=71506
4165                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166                     for(var i = 0, len = cn.length; i < len; i++) {
4167                         b += createHtml(cn[i], b);
4168                     }
4169                 }else{
4170                     b += createHtml(cn, b);
4171                 }
4172             }
4173             if(o.html){
4174                 b += o.html;
4175             }
4176             b += "</" + o.tag + ">";
4177         }
4178         return b;
4179     };
4180
4181     // build as dom
4182     /** @ignore */
4183     var createDom = function(o, parentNode){
4184          
4185         // defininition craeted..
4186         var ns = false;
4187         if (o.ns && o.ns != 'html') {
4188                
4189             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190                 xmlns[o.ns] = o.xmlns;
4191                 ns = o.xmlns;
4192             }
4193             if (typeof(xmlns[o.ns]) == 'undefined') {
4194                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4195             }
4196             ns = xmlns[o.ns];
4197         }
4198         
4199         
4200         if (typeof(o) == 'string') {
4201             return parentNode.appendChild(document.createTextNode(o));
4202         }
4203         o.tag = o.tag || div;
4204         if (o.ns && Roo.isIE) {
4205             ns = false;
4206             o.tag = o.ns + ':' + o.tag;
4207             
4208         }
4209         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4210         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4211         for(var attr in o){
4212             
4213             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4214                     attr == "style" || typeof o[attr] == "function") continue;
4215                     
4216             if(attr=="cls" && Roo.isIE){
4217                 el.className = o["cls"];
4218             }else{
4219                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220                 else el[attr] = o[attr];
4221             }
4222         }
4223         Roo.DomHelper.applyStyles(el, o.style);
4224         var cn = o.children || o.cn;
4225         if(cn){
4226             //http://bugs.kde.org/show_bug.cgi?id=71506
4227              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228                 for(var i = 0, len = cn.length; i < len; i++) {
4229                     createDom(cn[i], el);
4230                 }
4231             }else{
4232                 createDom(cn, el);
4233             }
4234         }
4235         if(o.html){
4236             el.innerHTML = o.html;
4237         }
4238         if(parentNode){
4239            parentNode.appendChild(el);
4240         }
4241         return el;
4242     };
4243
4244     var ieTable = function(depth, s, h, e){
4245         tempTableEl.innerHTML = [s, h, e].join('');
4246         var i = -1, el = tempTableEl;
4247         while(++i < depth){
4248             el = el.firstChild;
4249         }
4250         return el;
4251     };
4252
4253     // kill repeat to save bytes
4254     var ts = '<table>',
4255         te = '</table>',
4256         tbs = ts+'<tbody>',
4257         tbe = '</tbody>'+te,
4258         trs = tbs + '<tr>',
4259         tre = '</tr>'+tbe;
4260
4261     /**
4262      * @ignore
4263      * Nasty code for IE's broken table implementation
4264      */
4265     var insertIntoTable = function(tag, where, el, html){
4266         if(!tempTableEl){
4267             tempTableEl = document.createElement('div');
4268         }
4269         var node;
4270         var before = null;
4271         if(tag == 'td'){
4272             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4273                 return;
4274             }
4275             if(where == 'beforebegin'){
4276                 before = el;
4277                 el = el.parentNode;
4278             } else{
4279                 before = el.nextSibling;
4280                 el = el.parentNode;
4281             }
4282             node = ieTable(4, trs, html, tre);
4283         }
4284         else if(tag == 'tr'){
4285             if(where == 'beforebegin'){
4286                 before = el;
4287                 el = el.parentNode;
4288                 node = ieTable(3, tbs, html, tbe);
4289             } else if(where == 'afterend'){
4290                 before = el.nextSibling;
4291                 el = el.parentNode;
4292                 node = ieTable(3, tbs, html, tbe);
4293             } else{ // INTO a TR
4294                 if(where == 'afterbegin'){
4295                     before = el.firstChild;
4296                 }
4297                 node = ieTable(4, trs, html, tre);
4298             }
4299         } else if(tag == 'tbody'){
4300             if(where == 'beforebegin'){
4301                 before = el;
4302                 el = el.parentNode;
4303                 node = ieTable(2, ts, html, te);
4304             } else if(where == 'afterend'){
4305                 before = el.nextSibling;
4306                 el = el.parentNode;
4307                 node = ieTable(2, ts, html, te);
4308             } else{
4309                 if(where == 'afterbegin'){
4310                     before = el.firstChild;
4311                 }
4312                 node = ieTable(3, tbs, html, tbe);
4313             }
4314         } else{ // TABLE
4315             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4316                 return;
4317             }
4318             if(where == 'afterbegin'){
4319                 before = el.firstChild;
4320             }
4321             node = ieTable(2, ts, html, te);
4322         }
4323         el.insertBefore(node, before);
4324         return node;
4325     };
4326
4327     return {
4328     /** True to force the use of DOM instead of html fragments @type Boolean */
4329     useDom : false,
4330
4331     /**
4332      * Returns the markup for the passed Element(s) config
4333      * @param {Object} o The Dom object spec (and children)
4334      * @return {String}
4335      */
4336     markup : function(o){
4337         return createHtml(o);
4338     },
4339
4340     /**
4341      * Applies a style specification to an element
4342      * @param {String/HTMLElement} el The element to apply styles to
4343      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344      * a function which returns such a specification.
4345      */
4346     applyStyles : function(el, styles){
4347         if(styles){
4348            el = Roo.fly(el);
4349            if(typeof styles == "string"){
4350                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4351                var matches;
4352                while ((matches = re.exec(styles)) != null){
4353                    el.setStyle(matches[1], matches[2]);
4354                }
4355            }else if (typeof styles == "object"){
4356                for (var style in styles){
4357                   el.setStyle(style, styles[style]);
4358                }
4359            }else if (typeof styles == "function"){
4360                 Roo.DomHelper.applyStyles(el, styles.call());
4361            }
4362         }
4363     },
4364
4365     /**
4366      * Inserts an HTML fragment into the Dom
4367      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368      * @param {HTMLElement} el The context element
4369      * @param {String} html The HTML fragmenet
4370      * @return {HTMLElement} The new node
4371      */
4372     insertHtml : function(where, el, html){
4373         where = where.toLowerCase();
4374         if(el.insertAdjacentHTML){
4375             if(tableRe.test(el.tagName)){
4376                 var rs;
4377                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4378                     return rs;
4379                 }
4380             }
4381             switch(where){
4382                 case "beforebegin":
4383                     el.insertAdjacentHTML('BeforeBegin', html);
4384                     return el.previousSibling;
4385                 case "afterbegin":
4386                     el.insertAdjacentHTML('AfterBegin', html);
4387                     return el.firstChild;
4388                 case "beforeend":
4389                     el.insertAdjacentHTML('BeforeEnd', html);
4390                     return el.lastChild;
4391                 case "afterend":
4392                     el.insertAdjacentHTML('AfterEnd', html);
4393                     return el.nextSibling;
4394             }
4395             throw 'Illegal insertion point -> "' + where + '"';
4396         }
4397         var range = el.ownerDocument.createRange();
4398         var frag;
4399         switch(where){
4400              case "beforebegin":
4401                 range.setStartBefore(el);
4402                 frag = range.createContextualFragment(html);
4403                 el.parentNode.insertBefore(frag, el);
4404                 return el.previousSibling;
4405              case "afterbegin":
4406                 if(el.firstChild){
4407                     range.setStartBefore(el.firstChild);
4408                     frag = range.createContextualFragment(html);
4409                     el.insertBefore(frag, el.firstChild);
4410                     return el.firstChild;
4411                 }else{
4412                     el.innerHTML = html;
4413                     return el.firstChild;
4414                 }
4415             case "beforeend":
4416                 if(el.lastChild){
4417                     range.setStartAfter(el.lastChild);
4418                     frag = range.createContextualFragment(html);
4419                     el.appendChild(frag);
4420                     return el.lastChild;
4421                 }else{
4422                     el.innerHTML = html;
4423                     return el.lastChild;
4424                 }
4425             case "afterend":
4426                 range.setStartAfter(el);
4427                 frag = range.createContextualFragment(html);
4428                 el.parentNode.insertBefore(frag, el.nextSibling);
4429                 return el.nextSibling;
4430             }
4431             throw 'Illegal insertion point -> "' + where + '"';
4432     },
4433
4434     /**
4435      * Creates new Dom element(s) and inserts them before el
4436      * @param {String/HTMLElement/Element} el The context element
4437      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439      * @return {HTMLElement/Roo.Element} The new node
4440      */
4441     insertBefore : function(el, o, returnElement){
4442         return this.doInsert(el, o, returnElement, "beforeBegin");
4443     },
4444
4445     /**
4446      * Creates new Dom element(s) and inserts them after el
4447      * @param {String/HTMLElement/Element} el The context element
4448      * @param {Object} o The Dom object spec (and children)
4449      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450      * @return {HTMLElement/Roo.Element} The new node
4451      */
4452     insertAfter : function(el, o, returnElement){
4453         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4454     },
4455
4456     /**
4457      * Creates new Dom element(s) and inserts them as the first child of el
4458      * @param {String/HTMLElement/Element} el The context element
4459      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461      * @return {HTMLElement/Roo.Element} The new node
4462      */
4463     insertFirst : function(el, o, returnElement){
4464         return this.doInsert(el, o, returnElement, "afterBegin");
4465     },
4466
4467     // private
4468     doInsert : function(el, o, returnElement, pos, sibling){
4469         el = Roo.getDom(el);
4470         var newNode;
4471         if(this.useDom || o.ns){
4472             newNode = createDom(o, null);
4473             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4474         }else{
4475             var html = createHtml(o);
4476             newNode = this.insertHtml(pos, el, html);
4477         }
4478         return returnElement ? Roo.get(newNode, true) : newNode;
4479     },
4480
4481     /**
4482      * Creates new Dom element(s) and appends them to el
4483      * @param {String/HTMLElement/Element} el The context element
4484      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486      * @return {HTMLElement/Roo.Element} The new node
4487      */
4488     append : function(el, o, returnElement){
4489         el = Roo.getDom(el);
4490         var newNode;
4491         if(this.useDom || o.ns){
4492             newNode = createDom(o, null);
4493             el.appendChild(newNode);
4494         }else{
4495             var html = createHtml(o);
4496             newNode = this.insertHtml("beforeEnd", el, html);
4497         }
4498         return returnElement ? Roo.get(newNode, true) : newNode;
4499     },
4500
4501     /**
4502      * Creates new Dom element(s) and overwrites the contents of el with them
4503      * @param {String/HTMLElement/Element} el The context element
4504      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506      * @return {HTMLElement/Roo.Element} The new node
4507      */
4508     overwrite : function(el, o, returnElement){
4509         el = Roo.getDom(el);
4510         if (o.ns) {
4511           
4512             while (el.childNodes.length) {
4513                 el.removeChild(el.firstChild);
4514             }
4515             createDom(o, el);
4516         } else {
4517             el.innerHTML = createHtml(o);   
4518         }
4519         
4520         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4521     },
4522
4523     /**
4524      * Creates a new Roo.DomHelper.Template from the Dom object spec
4525      * @param {Object} o The Dom object spec (and children)
4526      * @return {Roo.DomHelper.Template} The new template
4527      */
4528     createTemplate : function(o){
4529         var html = createHtml(o);
4530         return new Roo.Template(html);
4531     }
4532     };
4533 }();
4534 /*
4535  * Based on:
4536  * Ext JS Library 1.1.1
4537  * Copyright(c) 2006-2007, Ext JS, LLC.
4538  *
4539  * Originally Released Under LGPL - original licence link has changed is not relivant.
4540  *
4541  * Fork - LGPL
4542  * <script type="text/javascript">
4543  */
4544  
4545 /**
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4549 * Usage:
4550 <pre><code>
4551 var t = new Roo.Template({
4552     html :  '&lt;div name="{id}"&gt;' + 
4553         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4554         '&lt;/div&gt;',
4555     myformat: function (value, allValues) {
4556         return 'XX' + value;
4557     }
4558 });
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4560 </code></pre>
4561 * For more information see this blog post with examples:
4562 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563      - Create Elements using DOM, HTML fragments and Templates</a>. 
4564 * @constructor
4565 * @param {Object} cfg - Configuration object.
4566 */
4567 Roo.Template = function(cfg){
4568     // BC!
4569     if(cfg instanceof Array){
4570         cfg = cfg.join("");
4571     }else if(arguments.length > 1){
4572         cfg = Array.prototype.join.call(arguments, "");
4573     }
4574     
4575     
4576     if (typeof(cfg) == 'object') {
4577         Roo.apply(this,cfg)
4578     } else {
4579         // bc
4580         this.html = cfg;
4581     }
4582     if (this.url) {
4583         this.load();
4584     }
4585     
4586 };
4587 Roo.Template.prototype = {
4588     
4589     /**
4590      * @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..
4591      *                    it should be fixed so that template is observable...
4592      */
4593     url : false,
4594     /**
4595      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4596      */
4597     html : '',
4598     /**
4599      * Returns an HTML fragment of this template with the specified values applied.
4600      * @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'})
4601      * @return {String} The HTML fragment
4602      */
4603     applyTemplate : function(values){
4604         try {
4605            
4606             if(this.compiled){
4607                 return this.compiled(values);
4608             }
4609             var useF = this.disableFormats !== true;
4610             var fm = Roo.util.Format, tpl = this;
4611             var fn = function(m, name, format, args){
4612                 if(format && useF){
4613                     if(format.substr(0, 5) == "this."){
4614                         return tpl.call(format.substr(5), values[name], values);
4615                     }else{
4616                         if(args){
4617                             // quoted values are required for strings in compiled templates, 
4618                             // but for non compiled we need to strip them
4619                             // quoted reversed for jsmin
4620                             var re = /^\s*['"](.*)["']\s*$/;
4621                             args = args.split(',');
4622                             for(var i = 0, len = args.length; i < len; i++){
4623                                 args[i] = args[i].replace(re, "$1");
4624                             }
4625                             args = [values[name]].concat(args);
4626                         }else{
4627                             args = [values[name]];
4628                         }
4629                         return fm[format].apply(fm, args);
4630                     }
4631                 }else{
4632                     return values[name] !== undefined ? values[name] : "";
4633                 }
4634             };
4635             return this.html.replace(this.re, fn);
4636         } catch (e) {
4637             Roo.log(e);
4638             throw e;
4639         }
4640          
4641     },
4642     
4643     loading : false,
4644       
4645     load : function ()
4646     {
4647          
4648         if (this.loading) {
4649             return;
4650         }
4651         var _t = this;
4652         
4653         this.loading = true;
4654         this.compiled = false;
4655         
4656         var cx = new Roo.data.Connection();
4657         cx.request({
4658             url : this.url,
4659             method : 'GET',
4660             success : function (response) {
4661                 _t.loading = false;
4662                 _t.html = response.responseText;
4663                 _t.url = false;
4664                 _t.compile();
4665              },
4666             failure : function(response) {
4667                 Roo.log("Template failed to load from " + _t.url);
4668                 _t.loading = false;
4669             }
4670         });
4671     },
4672
4673     /**
4674      * Sets the HTML used as the template and optionally compiles it.
4675      * @param {String} html
4676      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677      * @return {Roo.Template} this
4678      */
4679     set : function(html, compile){
4680         this.html = html;
4681         this.compiled = null;
4682         if(compile){
4683             this.compile();
4684         }
4685         return this;
4686     },
4687     
4688     /**
4689      * True to disable format functions (defaults to false)
4690      * @type Boolean
4691      */
4692     disableFormats : false,
4693     
4694     /**
4695     * The regular expression used to match template variables 
4696     * @type RegExp
4697     * @property 
4698     */
4699     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4700     
4701     /**
4702      * Compiles the template into an internal function, eliminating the RegEx overhead.
4703      * @return {Roo.Template} this
4704      */
4705     compile : function(){
4706         var fm = Roo.util.Format;
4707         var useF = this.disableFormats !== true;
4708         var sep = Roo.isGecko ? "+" : ",";
4709         var fn = function(m, name, format, args){
4710             if(format && useF){
4711                 args = args ? ',' + args : "";
4712                 if(format.substr(0, 5) != "this."){
4713                     format = "fm." + format + '(';
4714                 }else{
4715                     format = 'this.call("'+ format.substr(5) + '", ';
4716                     args = ", values";
4717                 }
4718             }else{
4719                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4720             }
4721             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4722         };
4723         var body;
4724         // branched to use + in gecko and [].join() in others
4725         if(Roo.isGecko){
4726             body = "this.compiled = function(values){ return '" +
4727                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4728                     "';};";
4729         }else{
4730             body = ["this.compiled = function(values){ return ['"];
4731             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732             body.push("'].join('');};");
4733             body = body.join('');
4734         }
4735         /**
4736          * eval:var:values
4737          * eval:var:fm
4738          */
4739         eval(body);
4740         return this;
4741     },
4742     
4743     // private function used to call members
4744     call : function(fnName, value, allValues){
4745         return this[fnName](value, allValues);
4746     },
4747     
4748     /**
4749      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750      * @param {String/HTMLElement/Roo.Element} el The context element
4751      * @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'})
4752      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753      * @return {HTMLElement/Roo.Element} The new node or Element
4754      */
4755     insertFirst: function(el, values, returnElement){
4756         return this.doInsert('afterBegin', el, values, returnElement);
4757     },
4758
4759     /**
4760      * Applies the supplied values to the template and inserts the new node(s) before el.
4761      * @param {String/HTMLElement/Roo.Element} el The context element
4762      * @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'})
4763      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764      * @return {HTMLElement/Roo.Element} The new node or Element
4765      */
4766     insertBefore: function(el, values, returnElement){
4767         return this.doInsert('beforeBegin', el, values, returnElement);
4768     },
4769
4770     /**
4771      * Applies the supplied values to the template and inserts the new node(s) after el.
4772      * @param {String/HTMLElement/Roo.Element} el The context element
4773      * @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'})
4774      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775      * @return {HTMLElement/Roo.Element} The new node or Element
4776      */
4777     insertAfter : function(el, values, returnElement){
4778         return this.doInsert('afterEnd', el, values, returnElement);
4779     },
4780     
4781     /**
4782      * Applies the supplied values to the template and appends the new node(s) to el.
4783      * @param {String/HTMLElement/Roo.Element} el The context element
4784      * @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'})
4785      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786      * @return {HTMLElement/Roo.Element} The new node or Element
4787      */
4788     append : function(el, values, returnElement){
4789         return this.doInsert('beforeEnd', el, values, returnElement);
4790     },
4791
4792     doInsert : function(where, el, values, returnEl){
4793         el = Roo.getDom(el);
4794         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795         return returnEl ? Roo.get(newNode, true) : newNode;
4796     },
4797
4798     /**
4799      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800      * @param {String/HTMLElement/Roo.Element} el The context element
4801      * @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'})
4802      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803      * @return {HTMLElement/Roo.Element} The new node or Element
4804      */
4805     overwrite : function(el, values, returnElement){
4806         el = Roo.getDom(el);
4807         el.innerHTML = this.applyTemplate(values);
4808         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4809     }
4810 };
4811 /**
4812  * Alias for {@link #applyTemplate}
4813  * @method
4814  */
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4816
4817 // backwards compat
4818 Roo.DomHelper.Template = Roo.Template;
4819
4820 /**
4821  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822  * @param {String/HTMLElement} el A DOM element or its id
4823  * @returns {Roo.Template} The created template
4824  * @static
4825  */
4826 Roo.Template.from = function(el){
4827     el = Roo.getDom(el);
4828     return new Roo.Template(el.value || el.innerHTML);
4829 };/*
4830  * Based on:
4831  * Ext JS Library 1.1.1
4832  * Copyright(c) 2006-2007, Ext JS, LLC.
4833  *
4834  * Originally Released Under LGPL - original licence link has changed is not relivant.
4835  *
4836  * Fork - LGPL
4837  * <script type="text/javascript">
4838  */
4839  
4840
4841 /*
4842  * This is code is also distributed under MIT license for use
4843  * with jQuery and prototype JavaScript libraries.
4844  */
4845 /**
4846  * @class Roo.DomQuery
4847 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).
4848 <p>
4849 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>
4850
4851 <p>
4852 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.
4853 </p>
4854 <h4>Element Selectors:</h4>
4855 <ul class="list">
4856     <li> <b>*</b> any element</li>
4857     <li> <b>E</b> an element with the tag E</li>
4858     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4862 </ul>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4865 <ul class="list">
4866     <li> <b>E[foo]</b> has an attribute "foo"</li>
4867     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4873 </ul>
4874 <h4>Pseudo Classes:</h4>
4875 <ul class="list">
4876     <li> <b>E:first-child</b> E is the first child of its parent</li>
4877     <li> <b>E:last-child</b> E is the last child of its parent</li>
4878     <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>
4879     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881     <li> <b>E:only-child</b> E is the only child of its parent</li>
4882     <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>
4883     <li> <b>E:first</b> the first E in the resultset</li>
4884     <li> <b>E:last</b> the last E in the resultset</li>
4885     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4894 </ul>
4895 <h4>CSS Value Selectors:</h4>
4896 <ul class="list">
4897     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4903 </ul>
4904  * @singleton
4905  */
4906 Roo.DomQuery = function(){
4907     var cache = {}, simpleCache = {}, valueCache = {};
4908     var nonSpace = /\S/;
4909     var trimRe = /^\s+|\s+$/g;
4910     var tplRe = /\{(\d+)\}/g;
4911     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912     var tagTokenRe = /^(#)?([\w-\*]+)/;
4913     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4914
4915     function child(p, index){
4916         var i = 0;
4917         var n = p.firstChild;
4918         while(n){
4919             if(n.nodeType == 1){
4920                if(++i == index){
4921                    return n;
4922                }
4923             }
4924             n = n.nextSibling;
4925         }
4926         return null;
4927     };
4928
4929     function next(n){
4930         while((n = n.nextSibling) && n.nodeType != 1);
4931         return n;
4932     };
4933
4934     function prev(n){
4935         while((n = n.previousSibling) && n.nodeType != 1);
4936         return n;
4937     };
4938
4939     function children(d){
4940         var n = d.firstChild, ni = -1;
4941             while(n){
4942                 var nx = n.nextSibling;
4943                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4944                     d.removeChild(n);
4945                 }else{
4946                     n.nodeIndex = ++ni;
4947                 }
4948                 n = nx;
4949             }
4950             return this;
4951         };
4952
4953     function byClassName(c, a, v){
4954         if(!v){
4955             return c;
4956         }
4957         var r = [], ri = -1, cn;
4958         for(var i = 0, ci; ci = c[i]; i++){
4959             if((' '+ci.className+' ').indexOf(v) != -1){
4960                 r[++ri] = ci;
4961             }
4962         }
4963         return r;
4964     };
4965
4966     function attrValue(n, attr){
4967         if(!n.tagName && typeof n.length != "undefined"){
4968             n = n[0];
4969         }
4970         if(!n){
4971             return null;
4972         }
4973         if(attr == "for"){
4974             return n.htmlFor;
4975         }
4976         if(attr == "class" || attr == "className"){
4977             return n.className;
4978         }
4979         return n.getAttribute(attr) || n[attr];
4980
4981     };
4982
4983     function getNodes(ns, mode, tagName){
4984         var result = [], ri = -1, cs;
4985         if(!ns){
4986             return result;
4987         }
4988         tagName = tagName || "*";
4989         if(typeof ns.getElementsByTagName != "undefined"){
4990             ns = [ns];
4991         }
4992         if(!mode){
4993             for(var i = 0, ni; ni = ns[i]; i++){
4994                 cs = ni.getElementsByTagName(tagName);
4995                 for(var j = 0, ci; ci = cs[j]; j++){
4996                     result[++ri] = ci;
4997                 }
4998             }
4999         }else if(mode == "/" || mode == ">"){
5000             var utag = tagName.toUpperCase();
5001             for(var i = 0, ni, cn; ni = ns[i]; i++){
5002                 cn = ni.children || ni.childNodes;
5003                 for(var j = 0, cj; cj = cn[j]; j++){
5004                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5005                         result[++ri] = cj;
5006                     }
5007                 }
5008             }
5009         }else if(mode == "+"){
5010             var utag = tagName.toUpperCase();
5011             for(var i = 0, n; n = ns[i]; i++){
5012                 while((n = n.nextSibling) && n.nodeType != 1);
5013                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5014                     result[++ri] = n;
5015                 }
5016             }
5017         }else if(mode == "~"){
5018             for(var i = 0, n; n = ns[i]; i++){
5019                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5020                 if(n){
5021                     result[++ri] = n;
5022                 }
5023             }
5024         }
5025         return result;
5026     };
5027
5028     function concat(a, b){
5029         if(b.slice){
5030             return a.concat(b);
5031         }
5032         for(var i = 0, l = b.length; i < l; i++){
5033             a[a.length] = b[i];
5034         }
5035         return a;
5036     }
5037
5038     function byTag(cs, tagName){
5039         if(cs.tagName || cs == document){
5040             cs = [cs];
5041         }
5042         if(!tagName){
5043             return cs;
5044         }
5045         var r = [], ri = -1;
5046         tagName = tagName.toLowerCase();
5047         for(var i = 0, ci; ci = cs[i]; i++){
5048             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5049                 r[++ri] = ci;
5050             }
5051         }
5052         return r;
5053     };
5054
5055     function byId(cs, attr, id){
5056         if(cs.tagName || cs == document){
5057             cs = [cs];
5058         }
5059         if(!id){
5060             return cs;
5061         }
5062         var r = [], ri = -1;
5063         for(var i = 0,ci; ci = cs[i]; i++){
5064             if(ci && ci.id == id){
5065                 r[++ri] = ci;
5066                 return r;
5067             }
5068         }
5069         return r;
5070     };
5071
5072     function byAttribute(cs, attr, value, op, custom){
5073         var r = [], ri = -1, st = custom=="{";
5074         var f = Roo.DomQuery.operators[op];
5075         for(var i = 0, ci; ci = cs[i]; i++){
5076             var a;
5077             if(st){
5078                 a = Roo.DomQuery.getStyle(ci, attr);
5079             }
5080             else if(attr == "class" || attr == "className"){
5081                 a = ci.className;
5082             }else if(attr == "for"){
5083                 a = ci.htmlFor;
5084             }else if(attr == "href"){
5085                 a = ci.getAttribute("href", 2);
5086             }else{
5087                 a = ci.getAttribute(attr);
5088             }
5089             if((f && f(a, value)) || (!f && a)){
5090                 r[++ri] = ci;
5091             }
5092         }
5093         return r;
5094     };
5095
5096     function byPseudo(cs, name, value){
5097         return Roo.DomQuery.pseudos[name](cs, value);
5098     };
5099
5100     // This is for IE MSXML which does not support expandos.
5101     // IE runs the same speed using setAttribute, however FF slows way down
5102     // and Safari completely fails so they need to continue to use expandos.
5103     var isIE = window.ActiveXObject ? true : false;
5104
5105     // this eval is stop the compressor from
5106     // renaming the variable to something shorter
5107     
5108     /** eval:var:batch */
5109     var batch = 30803; 
5110
5111     var key = 30803;
5112
5113     function nodupIEXml(cs){
5114         var d = ++key;
5115         cs[0].setAttribute("_nodup", d);
5116         var r = [cs[0]];
5117         for(var i = 1, len = cs.length; i < len; i++){
5118             var c = cs[i];
5119             if(!c.getAttribute("_nodup") != d){
5120                 c.setAttribute("_nodup", d);
5121                 r[r.length] = c;
5122             }
5123         }
5124         for(var i = 0, len = cs.length; i < len; i++){
5125             cs[i].removeAttribute("_nodup");
5126         }
5127         return r;
5128     }
5129
5130     function nodup(cs){
5131         if(!cs){
5132             return [];
5133         }
5134         var len = cs.length, c, i, r = cs, cj, ri = -1;
5135         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5136             return cs;
5137         }
5138         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139             return nodupIEXml(cs);
5140         }
5141         var d = ++key;
5142         cs[0]._nodup = d;
5143         for(i = 1; c = cs[i]; i++){
5144             if(c._nodup != d){
5145                 c._nodup = d;
5146             }else{
5147                 r = [];
5148                 for(var j = 0; j < i; j++){
5149                     r[++ri] = cs[j];
5150                 }
5151                 for(j = i+1; cj = cs[j]; j++){
5152                     if(cj._nodup != d){
5153                         cj._nodup = d;
5154                         r[++ri] = cj;
5155                     }
5156                 }
5157                 return r;
5158             }
5159         }
5160         return r;
5161     }
5162
5163     function quickDiffIEXml(c1, c2){
5164         var d = ++key;
5165         for(var i = 0, len = c1.length; i < len; i++){
5166             c1[i].setAttribute("_qdiff", d);
5167         }
5168         var r = [];
5169         for(var i = 0, len = c2.length; i < len; i++){
5170             if(c2[i].getAttribute("_qdiff") != d){
5171                 r[r.length] = c2[i];
5172             }
5173         }
5174         for(var i = 0, len = c1.length; i < len; i++){
5175            c1[i].removeAttribute("_qdiff");
5176         }
5177         return r;
5178     }
5179
5180     function quickDiff(c1, c2){
5181         var len1 = c1.length;
5182         if(!len1){
5183             return c2;
5184         }
5185         if(isIE && c1[0].selectSingleNode){
5186             return quickDiffIEXml(c1, c2);
5187         }
5188         var d = ++key;
5189         for(var i = 0; i < len1; i++){
5190             c1[i]._qdiff = d;
5191         }
5192         var r = [];
5193         for(var i = 0, len = c2.length; i < len; i++){
5194             if(c2[i]._qdiff != d){
5195                 r[r.length] = c2[i];
5196             }
5197         }
5198         return r;
5199     }
5200
5201     function quickId(ns, mode, root, id){
5202         if(ns == root){
5203            var d = root.ownerDocument || root;
5204            return d.getElementById(id);
5205         }
5206         ns = getNodes(ns, mode, "*");
5207         return byId(ns, null, id);
5208     }
5209
5210     return {
5211         getStyle : function(el, name){
5212             return Roo.fly(el).getStyle(name);
5213         },
5214         /**
5215          * Compiles a selector/xpath query into a reusable function. The returned function
5216          * takes one parameter "root" (optional), which is the context node from where the query should start.
5217          * @param {String} selector The selector/xpath query
5218          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219          * @return {Function}
5220          */
5221         compile : function(path, type){
5222             type = type || "select";
5223             
5224             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225             var q = path, mode, lq;
5226             var tk = Roo.DomQuery.matchers;
5227             var tklen = tk.length;
5228             var mm;
5229
5230             // accept leading mode switch
5231             var lmode = q.match(modeRe);
5232             if(lmode && lmode[1]){
5233                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234                 q = q.replace(lmode[1], "");
5235             }
5236             // strip leading slashes
5237             while(path.substr(0, 1)=="/"){
5238                 path = path.substr(1);
5239             }
5240
5241             while(q && lq != q){
5242                 lq = q;
5243                 var tm = q.match(tagTokenRe);
5244                 if(type == "select"){
5245                     if(tm){
5246                         if(tm[1] == "#"){
5247                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5248                         }else{
5249                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5250                         }
5251                         q = q.replace(tm[0], "");
5252                     }else if(q.substr(0, 1) != '@'){
5253                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5254                     }
5255                 }else{
5256                     if(tm){
5257                         if(tm[1] == "#"){
5258                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5259                         }else{
5260                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5261                         }
5262                         q = q.replace(tm[0], "");
5263                     }
5264                 }
5265                 while(!(mm = q.match(modeRe))){
5266                     var matched = false;
5267                     for(var j = 0; j < tklen; j++){
5268                         var t = tk[j];
5269                         var m = q.match(t.re);
5270                         if(m){
5271                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5272                                                     return m[i];
5273                                                 });
5274                             q = q.replace(m[0], "");
5275                             matched = true;
5276                             break;
5277                         }
5278                     }
5279                     // prevent infinite loop on bad selector
5280                     if(!matched){
5281                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5282                     }
5283                 }
5284                 if(mm[1]){
5285                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5286                     q = q.replace(mm[1], "");
5287                 }
5288             }
5289             fn[fn.length] = "return nodup(n);\n}";
5290             
5291              /** 
5292               * list of variables that need from compression as they are used by eval.
5293              *  eval:var:batch 
5294              *  eval:var:nodup
5295              *  eval:var:byTag
5296              *  eval:var:ById
5297              *  eval:var:getNodes
5298              *  eval:var:quickId
5299              *  eval:var:mode
5300              *  eval:var:root
5301              *  eval:var:n
5302              *  eval:var:byClassName
5303              *  eval:var:byPseudo
5304              *  eval:var:byAttribute
5305              *  eval:var:attrValue
5306              * 
5307              **/ 
5308             eval(fn.join(""));
5309             return f;
5310         },
5311
5312         /**
5313          * Selects a group of elements.
5314          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5315          * @param {Node} root (optional) The start of the query (defaults to document).
5316          * @return {Array}
5317          */
5318         select : function(path, root, type){
5319             if(!root || root == document){
5320                 root = document;
5321             }
5322             if(typeof root == "string"){
5323                 root = document.getElementById(root);
5324             }
5325             var paths = path.split(",");
5326             var results = [];
5327             for(var i = 0, len = paths.length; i < len; i++){
5328                 var p = paths[i].replace(trimRe, "");
5329                 if(!cache[p]){
5330                     Roo.log(p);
5331                     cache[p] = Roo.DomQuery.compile(p);
5332                     if(!cache[p]){
5333                         throw p + " is not a valid selector";
5334                     }
5335                 }
5336                 var result = cache[p](root);
5337                 if(result && result != document){
5338                     results = results.concat(result);
5339                 }
5340             }
5341             if(paths.length > 1){
5342                 return nodup(results);
5343             }
5344             return results;
5345         },
5346
5347         /**
5348          * Selects a single element.
5349          * @param {String} selector The selector/xpath query
5350          * @param {Node} root (optional) The start of the query (defaults to document).
5351          * @return {Element}
5352          */
5353         selectNode : function(path, root){
5354             return Roo.DomQuery.select(path, root)[0];
5355         },
5356
5357         /**
5358          * Selects the value of a node, optionally replacing null with the defaultValue.
5359          * @param {String} selector The selector/xpath query
5360          * @param {Node} root (optional) The start of the query (defaults to document).
5361          * @param {String} defaultValue
5362          */
5363         selectValue : function(path, root, defaultValue){
5364             path = path.replace(trimRe, "");
5365             if(!valueCache[path]){
5366                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5367             }
5368             var n = valueCache[path](root);
5369             n = n[0] ? n[0] : n;
5370             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5371             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5372         },
5373
5374         /**
5375          * Selects the value of a node, parsing integers and floats.
5376          * @param {String} selector The selector/xpath query
5377          * @param {Node} root (optional) The start of the query (defaults to document).
5378          * @param {Number} defaultValue
5379          * @return {Number}
5380          */
5381         selectNumber : function(path, root, defaultValue){
5382             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5383             return parseFloat(v);
5384         },
5385
5386         /**
5387          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5388          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5389          * @param {String} selector The simple selector to test
5390          * @return {Boolean}
5391          */
5392         is : function(el, ss){
5393             if(typeof el == "string"){
5394                 el = document.getElementById(el);
5395             }
5396             var isArray = (el instanceof Array);
5397             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5398             return isArray ? (result.length == el.length) : (result.length > 0);
5399         },
5400
5401         /**
5402          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5403          * @param {Array} el An array of elements to filter
5404          * @param {String} selector The simple selector to test
5405          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5406          * the selector instead of the ones that match
5407          * @return {Array}
5408          */
5409         filter : function(els, ss, nonMatches){
5410             ss = ss.replace(trimRe, "");
5411             if(!simpleCache[ss]){
5412                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5413             }
5414             var result = simpleCache[ss](els);
5415             return nonMatches ? quickDiff(result, els) : result;
5416         },
5417
5418         /**
5419          * Collection of matching regular expressions and code snippets.
5420          */
5421         matchers : [{
5422                 re: /^\.([\w-]+)/,
5423                 select: 'n = byClassName(n, null, " {1} ");'
5424             }, {
5425                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5426                 select: 'n = byPseudo(n, "{1}", "{2}");'
5427             },{
5428                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5429                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5430             }, {
5431                 re: /^#([\w-]+)/,
5432                 select: 'n = byId(n, null, "{1}");'
5433             },{
5434                 re: /^@([\w-]+)/,
5435                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5436             }
5437         ],
5438
5439         /**
5440          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5441          * 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;.
5442          */
5443         operators : {
5444             "=" : function(a, v){
5445                 return a == v;
5446             },
5447             "!=" : function(a, v){
5448                 return a != v;
5449             },
5450             "^=" : function(a, v){
5451                 return a && a.substr(0, v.length) == v;
5452             },
5453             "$=" : function(a, v){
5454                 return a && a.substr(a.length-v.length) == v;
5455             },
5456             "*=" : function(a, v){
5457                 return a && a.indexOf(v) !== -1;
5458             },
5459             "%=" : function(a, v){
5460                 return (a % v) == 0;
5461             },
5462             "|=" : function(a, v){
5463                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5464             },
5465             "~=" : function(a, v){
5466                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5467             }
5468         },
5469
5470         /**
5471          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5472          * and the argument (if any) supplied in the selector.
5473          */
5474         pseudos : {
5475             "first-child" : function(c){
5476                 var r = [], ri = -1, n;
5477                 for(var i = 0, ci; ci = n = c[i]; i++){
5478                     while((n = n.previousSibling) && n.nodeType != 1);
5479                     if(!n){
5480                         r[++ri] = ci;
5481                     }
5482                 }
5483                 return r;
5484             },
5485
5486             "last-child" : function(c){
5487                 var r = [], ri = -1, n;
5488                 for(var i = 0, ci; ci = n = c[i]; i++){
5489                     while((n = n.nextSibling) && n.nodeType != 1);
5490                     if(!n){
5491                         r[++ri] = ci;
5492                     }
5493                 }
5494                 return r;
5495             },
5496
5497             "nth-child" : function(c, a) {
5498                 var r = [], ri = -1;
5499                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5500                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5501                 for(var i = 0, n; n = c[i]; i++){
5502                     var pn = n.parentNode;
5503                     if (batch != pn._batch) {
5504                         var j = 0;
5505                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5506                             if(cn.nodeType == 1){
5507                                cn.nodeIndex = ++j;
5508                             }
5509                         }
5510                         pn._batch = batch;
5511                     }
5512                     if (f == 1) {
5513                         if (l == 0 || n.nodeIndex == l){
5514                             r[++ri] = n;
5515                         }
5516                     } else if ((n.nodeIndex + l) % f == 0){
5517                         r[++ri] = n;
5518                     }
5519                 }
5520
5521                 return r;
5522             },
5523
5524             "only-child" : function(c){
5525                 var r = [], ri = -1;;
5526                 for(var i = 0, ci; ci = c[i]; i++){
5527                     if(!prev(ci) && !next(ci)){
5528                         r[++ri] = ci;
5529                     }
5530                 }
5531                 return r;
5532             },
5533
5534             "empty" : function(c){
5535                 var r = [], ri = -1;
5536                 for(var i = 0, ci; ci = c[i]; i++){
5537                     var cns = ci.childNodes, j = 0, cn, empty = true;
5538                     while(cn = cns[j]){
5539                         ++j;
5540                         if(cn.nodeType == 1 || cn.nodeType == 3){
5541                             empty = false;
5542                             break;
5543                         }
5544                     }
5545                     if(empty){
5546                         r[++ri] = ci;
5547                     }
5548                 }
5549                 return r;
5550             },
5551
5552             "contains" : function(c, v){
5553                 var r = [], ri = -1;
5554                 for(var i = 0, ci; ci = c[i]; i++){
5555                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5556                         r[++ri] = ci;
5557                     }
5558                 }
5559                 return r;
5560             },
5561
5562             "nodeValue" : function(c, v){
5563                 var r = [], ri = -1;
5564                 for(var i = 0, ci; ci = c[i]; i++){
5565                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5566                         r[++ri] = ci;
5567                     }
5568                 }
5569                 return r;
5570             },
5571
5572             "checked" : function(c){
5573                 var r = [], ri = -1;
5574                 for(var i = 0, ci; ci = c[i]; i++){
5575                     if(ci.checked == true){
5576                         r[++ri] = ci;
5577                     }
5578                 }
5579                 return r;
5580             },
5581
5582             "not" : function(c, ss){
5583                 return Roo.DomQuery.filter(c, ss, true);
5584             },
5585
5586             "odd" : function(c){
5587                 return this["nth-child"](c, "odd");
5588             },
5589
5590             "even" : function(c){
5591                 return this["nth-child"](c, "even");
5592             },
5593
5594             "nth" : function(c, a){
5595                 return c[a-1] || [];
5596             },
5597
5598             "first" : function(c){
5599                 return c[0] || [];
5600             },
5601
5602             "last" : function(c){
5603                 return c[c.length-1] || [];
5604             },
5605
5606             "has" : function(c, ss){
5607                 var s = Roo.DomQuery.select;
5608                 var r = [], ri = -1;
5609                 for(var i = 0, ci; ci = c[i]; i++){
5610                     if(s(ss, ci).length > 0){
5611                         r[++ri] = ci;
5612                     }
5613                 }
5614                 return r;
5615             },
5616
5617             "next" : function(c, ss){
5618                 var is = Roo.DomQuery.is;
5619                 var r = [], ri = -1;
5620                 for(var i = 0, ci; ci = c[i]; i++){
5621                     var n = next(ci);
5622                     if(n && is(n, ss)){
5623                         r[++ri] = ci;
5624                     }
5625                 }
5626                 return r;
5627             },
5628
5629             "prev" : function(c, ss){
5630                 var is = Roo.DomQuery.is;
5631                 var r = [], ri = -1;
5632                 for(var i = 0, ci; ci = c[i]; i++){
5633                     var n = prev(ci);
5634                     if(n && is(n, ss)){
5635                         r[++ri] = ci;
5636                     }
5637                 }
5638                 return r;
5639             }
5640         }
5641     };
5642 }();
5643
5644 /**
5645  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5646  * @param {String} path The selector/xpath query
5647  * @param {Node} root (optional) The start of the query (defaults to document).
5648  * @return {Array}
5649  * @member Roo
5650  * @method query
5651  */
5652 Roo.query = Roo.DomQuery.select;
5653 /*
5654  * Based on:
5655  * Ext JS Library 1.1.1
5656  * Copyright(c) 2006-2007, Ext JS, LLC.
5657  *
5658  * Originally Released Under LGPL - original licence link has changed is not relivant.
5659  *
5660  * Fork - LGPL
5661  * <script type="text/javascript">
5662  */
5663
5664 /**
5665  * @class Roo.util.Observable
5666  * Base class that provides a common interface for publishing events. Subclasses are expected to
5667  * to have a property "events" with all the events defined.<br>
5668  * For example:
5669  * <pre><code>
5670  Employee = function(name){
5671     this.name = name;
5672     this.addEvents({
5673         "fired" : true,
5674         "quit" : true
5675     });
5676  }
5677  Roo.extend(Employee, Roo.util.Observable);
5678 </code></pre>
5679  * @param {Object} config properties to use (incuding events / listeners)
5680  */
5681
5682 Roo.util.Observable = function(cfg){
5683     
5684     cfg = cfg|| {};
5685     this.addEvents(cfg.events || {});
5686     if (cfg.events) {
5687         delete cfg.events; // make sure
5688     }
5689      
5690     Roo.apply(this, cfg);
5691     
5692     if(this.listeners){
5693         this.on(this.listeners);
5694         delete this.listeners;
5695     }
5696 };
5697 Roo.util.Observable.prototype = {
5698     /** 
5699  * @cfg {Object} listeners  list of events and functions to call for this object, 
5700  * For example :
5701  * <pre><code>
5702     listeners :  { 
5703        'click' : function(e) {
5704            ..... 
5705         } ,
5706         .... 
5707     } 
5708   </code></pre>
5709  */
5710     
5711     
5712     /**
5713      * Fires the specified event with the passed parameters (minus the event name).
5714      * @param {String} eventName
5715      * @param {Object...} args Variable number of parameters are passed to handlers
5716      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5717      */
5718     fireEvent : function(){
5719         var ce = this.events[arguments[0].toLowerCase()];
5720         if(typeof ce == "object"){
5721             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5722         }else{
5723             return true;
5724         }
5725     },
5726
5727     // private
5728     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5729
5730     /**
5731      * Appends an event handler to this component
5732      * @param {String}   eventName The type of event to listen for
5733      * @param {Function} handler The method the event invokes
5734      * @param {Object}   scope (optional) The scope in which to execute the handler
5735      * function. The handler function's "this" context.
5736      * @param {Object}   options (optional) An object containing handler configuration
5737      * properties. This may contain any of the following properties:<ul>
5738      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5739      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5740      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5741      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5742      * by the specified number of milliseconds. If the event fires again within that time, the original
5743      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5744      * </ul><br>
5745      * <p>
5746      * <b>Combining Options</b><br>
5747      * Using the options argument, it is possible to combine different types of listeners:<br>
5748      * <br>
5749      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5750                 <pre><code>
5751                 el.on('click', this.onClick, this, {
5752                         single: true,
5753                 delay: 100,
5754                 forumId: 4
5755                 });
5756                 </code></pre>
5757      * <p>
5758      * <b>Attaching multiple handlers in 1 call</b><br>
5759      * The method also allows for a single argument to be passed which is a config object containing properties
5760      * which specify multiple handlers.
5761      * <pre><code>
5762                 el.on({
5763                         'click': {
5764                         fn: this.onClick,
5765                         scope: this,
5766                         delay: 100
5767                 }, 
5768                 'mouseover': {
5769                         fn: this.onMouseOver,
5770                         scope: this
5771                 },
5772                 'mouseout': {
5773                         fn: this.onMouseOut,
5774                         scope: this
5775                 }
5776                 });
5777                 </code></pre>
5778      * <p>
5779      * Or a shorthand syntax which passes the same scope object to all handlers:
5780         <pre><code>
5781                 el.on({
5782                         'click': this.onClick,
5783                 'mouseover': this.onMouseOver,
5784                 'mouseout': this.onMouseOut,
5785                 scope: this
5786                 });
5787                 </code></pre>
5788      */
5789     addListener : function(eventName, fn, scope, o){
5790         if(typeof eventName == "object"){
5791             o = eventName;
5792             for(var e in o){
5793                 if(this.filterOptRe.test(e)){
5794                     continue;
5795                 }
5796                 if(typeof o[e] == "function"){
5797                     // shared options
5798                     this.addListener(e, o[e], o.scope,  o);
5799                 }else{
5800                     // individual options
5801                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5802                 }
5803             }
5804             return;
5805         }
5806         o = (!o || typeof o == "boolean") ? {} : o;
5807         eventName = eventName.toLowerCase();
5808         var ce = this.events[eventName] || true;
5809         if(typeof ce == "boolean"){
5810             ce = new Roo.util.Event(this, eventName);
5811             this.events[eventName] = ce;
5812         }
5813         ce.addListener(fn, scope, o);
5814     },
5815
5816     /**
5817      * Removes a listener
5818      * @param {String}   eventName     The type of event to listen for
5819      * @param {Function} handler        The handler to remove
5820      * @param {Object}   scope  (optional) The scope (this object) for the handler
5821      */
5822     removeListener : function(eventName, fn, scope){
5823         var ce = this.events[eventName.toLowerCase()];
5824         if(typeof ce == "object"){
5825             ce.removeListener(fn, scope);
5826         }
5827     },
5828
5829     /**
5830      * Removes all listeners for this object
5831      */
5832     purgeListeners : function(){
5833         for(var evt in this.events){
5834             if(typeof this.events[evt] == "object"){
5835                  this.events[evt].clearListeners();
5836             }
5837         }
5838     },
5839
5840     relayEvents : function(o, events){
5841         var createHandler = function(ename){
5842             return function(){
5843                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5844             };
5845         };
5846         for(var i = 0, len = events.length; i < len; i++){
5847             var ename = events[i];
5848             if(!this.events[ename]){ this.events[ename] = true; };
5849             o.on(ename, createHandler(ename), this);
5850         }
5851     },
5852
5853     /**
5854      * Used to define events on this Observable
5855      * @param {Object} object The object with the events defined
5856      */
5857     addEvents : function(o){
5858         if(!this.events){
5859             this.events = {};
5860         }
5861         Roo.applyIf(this.events, o);
5862     },
5863
5864     /**
5865      * Checks to see if this object has any listeners for a specified event
5866      * @param {String} eventName The name of the event to check for
5867      * @return {Boolean} True if the event is being listened for, else false
5868      */
5869     hasListener : function(eventName){
5870         var e = this.events[eventName];
5871         return typeof e == "object" && e.listeners.length > 0;
5872     }
5873 };
5874 /**
5875  * Appends an event handler to this element (shorthand for addListener)
5876  * @param {String}   eventName     The type of event to listen for
5877  * @param {Function} handler        The method the event invokes
5878  * @param {Object}   scope (optional) The scope in which to execute the handler
5879  * function. The handler function's "this" context.
5880  * @param {Object}   options  (optional)
5881  * @method
5882  */
5883 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5884 /**
5885  * Removes a listener (shorthand for removeListener)
5886  * @param {String}   eventName     The type of event to listen for
5887  * @param {Function} handler        The handler to remove
5888  * @param {Object}   scope  (optional) The scope (this object) for the handler
5889  * @method
5890  */
5891 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5892
5893 /**
5894  * Starts capture on the specified Observable. All events will be passed
5895  * to the supplied function with the event name + standard signature of the event
5896  * <b>before</b> the event is fired. If the supplied function returns false,
5897  * the event will not fire.
5898  * @param {Observable} o The Observable to capture
5899  * @param {Function} fn The function to call
5900  * @param {Object} scope (optional) The scope (this object) for the fn
5901  * @static
5902  */
5903 Roo.util.Observable.capture = function(o, fn, scope){
5904     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5905 };
5906
5907 /**
5908  * Removes <b>all</b> added captures from the Observable.
5909  * @param {Observable} o The Observable to release
5910  * @static
5911  */
5912 Roo.util.Observable.releaseCapture = function(o){
5913     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5914 };
5915
5916 (function(){
5917
5918     var createBuffered = function(h, o, scope){
5919         var task = new Roo.util.DelayedTask();
5920         return function(){
5921             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5922         };
5923     };
5924
5925     var createSingle = function(h, e, fn, scope){
5926         return function(){
5927             e.removeListener(fn, scope);
5928             return h.apply(scope, arguments);
5929         };
5930     };
5931
5932     var createDelayed = function(h, o, scope){
5933         return function(){
5934             var args = Array.prototype.slice.call(arguments, 0);
5935             setTimeout(function(){
5936                 h.apply(scope, args);
5937             }, o.delay || 10);
5938         };
5939     };
5940
5941     Roo.util.Event = function(obj, name){
5942         this.name = name;
5943         this.obj = obj;
5944         this.listeners = [];
5945     };
5946
5947     Roo.util.Event.prototype = {
5948         addListener : function(fn, scope, options){
5949             var o = options || {};
5950             scope = scope || this.obj;
5951             if(!this.isListening(fn, scope)){
5952                 var l = {fn: fn, scope: scope, options: o};
5953                 var h = fn;
5954                 if(o.delay){
5955                     h = createDelayed(h, o, scope);
5956                 }
5957                 if(o.single){
5958                     h = createSingle(h, this, fn, scope);
5959                 }
5960                 if(o.buffer){
5961                     h = createBuffered(h, o, scope);
5962                 }
5963                 l.fireFn = h;
5964                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5965                     this.listeners.push(l);
5966                 }else{
5967                     this.listeners = this.listeners.slice(0);
5968                     this.listeners.push(l);
5969                 }
5970             }
5971         },
5972
5973         findListener : function(fn, scope){
5974             scope = scope || this.obj;
5975             var ls = this.listeners;
5976             for(var i = 0, len = ls.length; i < len; i++){
5977                 var l = ls[i];
5978                 if(l.fn == fn && l.scope == scope){
5979                     return i;
5980                 }
5981             }
5982             return -1;
5983         },
5984
5985         isListening : function(fn, scope){
5986             return this.findListener(fn, scope) != -1;
5987         },
5988
5989         removeListener : function(fn, scope){
5990             var index;
5991             if((index = this.findListener(fn, scope)) != -1){
5992                 if(!this.firing){
5993                     this.listeners.splice(index, 1);
5994                 }else{
5995                     this.listeners = this.listeners.slice(0);
5996                     this.listeners.splice(index, 1);
5997                 }
5998                 return true;
5999             }
6000             return false;
6001         },
6002
6003         clearListeners : function(){
6004             this.listeners = [];
6005         },
6006
6007         fire : function(){
6008             var ls = this.listeners, scope, len = ls.length;
6009             if(len > 0){
6010                 this.firing = true;
6011                 var args = Array.prototype.slice.call(arguments, 0);
6012                 for(var i = 0; i < len; i++){
6013                     var l = ls[i];
6014                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6015                         this.firing = false;
6016                         return false;
6017                     }
6018                 }
6019                 this.firing = false;
6020             }
6021             return true;
6022         }
6023     };
6024 })();/*
6025  * Based on:
6026  * Ext JS Library 1.1.1
6027  * Copyright(c) 2006-2007, Ext JS, LLC.
6028  *
6029  * Originally Released Under LGPL - original licence link has changed is not relivant.
6030  *
6031  * Fork - LGPL
6032  * <script type="text/javascript">
6033  */
6034
6035 /**
6036  * @class Roo.EventManager
6037  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6038  * several useful events directly.
6039  * See {@link Roo.EventObject} for more details on normalized event objects.
6040  * @singleton
6041  */
6042 Roo.EventManager = function(){
6043     var docReadyEvent, docReadyProcId, docReadyState = false;
6044     var resizeEvent, resizeTask, textEvent, textSize;
6045     var E = Roo.lib.Event;
6046     var D = Roo.lib.Dom;
6047
6048
6049     var fireDocReady = function(){
6050         if(!docReadyState){
6051             docReadyState = true;
6052             Roo.isReady = true;
6053             if(docReadyProcId){
6054                 clearInterval(docReadyProcId);
6055             }
6056             if(Roo.isGecko || Roo.isOpera) {
6057                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6058             }
6059             if(Roo.isIE){
6060                 var defer = document.getElementById("ie-deferred-loader");
6061                 if(defer){
6062                     defer.onreadystatechange = null;
6063                     defer.parentNode.removeChild(defer);
6064                 }
6065             }
6066             if(docReadyEvent){
6067                 docReadyEvent.fire();
6068                 docReadyEvent.clearListeners();
6069             }
6070         }
6071     };
6072     
6073     var initDocReady = function(){
6074         docReadyEvent = new Roo.util.Event();
6075         if(Roo.isGecko || Roo.isOpera) {
6076             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6077         }else if(Roo.isIE){
6078             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6079             var defer = document.getElementById("ie-deferred-loader");
6080             defer.onreadystatechange = function(){
6081                 if(this.readyState == "complete"){
6082                     fireDocReady();
6083                 }
6084             };
6085         }else if(Roo.isSafari){ 
6086             docReadyProcId = setInterval(function(){
6087                 var rs = document.readyState;
6088                 if(rs == "complete") {
6089                     fireDocReady();     
6090                  }
6091             }, 10);
6092         }
6093         // no matter what, make sure it fires on load
6094         E.on(window, "load", fireDocReady);
6095     };
6096
6097     var createBuffered = function(h, o){
6098         var task = new Roo.util.DelayedTask(h);
6099         return function(e){
6100             // create new event object impl so new events don't wipe out properties
6101             e = new Roo.EventObjectImpl(e);
6102             task.delay(o.buffer, h, null, [e]);
6103         };
6104     };
6105
6106     var createSingle = function(h, el, ename, fn){
6107         return function(e){
6108             Roo.EventManager.removeListener(el, ename, fn);
6109             h(e);
6110         };
6111     };
6112
6113     var createDelayed = function(h, o){
6114         return function(e){
6115             // create new event object impl so new events don't wipe out properties
6116             e = new Roo.EventObjectImpl(e);
6117             setTimeout(function(){
6118                 h(e);
6119             }, o.delay || 10);
6120         };
6121     };
6122
6123     var listen = function(element, ename, opt, fn, scope){
6124         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6125         fn = fn || o.fn; scope = scope || o.scope;
6126         var el = Roo.getDom(element);
6127         if(!el){
6128             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6129         }
6130         var h = function(e){
6131             e = Roo.EventObject.setEvent(e);
6132             var t;
6133             if(o.delegate){
6134                 t = e.getTarget(o.delegate, el);
6135                 if(!t){
6136                     return;
6137                 }
6138             }else{
6139                 t = e.target;
6140             }
6141             if(o.stopEvent === true){
6142                 e.stopEvent();
6143             }
6144             if(o.preventDefault === true){
6145                e.preventDefault();
6146             }
6147             if(o.stopPropagation === true){
6148                 e.stopPropagation();
6149             }
6150
6151             if(o.normalized === false){
6152                 e = e.browserEvent;
6153             }
6154
6155             fn.call(scope || el, e, t, o);
6156         };
6157         if(o.delay){
6158             h = createDelayed(h, o);
6159         }
6160         if(o.single){
6161             h = createSingle(h, el, ename, fn);
6162         }
6163         if(o.buffer){
6164             h = createBuffered(h, o);
6165         }
6166         fn._handlers = fn._handlers || [];
6167         fn._handlers.push([Roo.id(el), ename, h]);
6168
6169         E.on(el, ename, h);
6170         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6171             el.addEventListener("DOMMouseScroll", h, false);
6172             E.on(window, 'unload', function(){
6173                 el.removeEventListener("DOMMouseScroll", h, false);
6174             });
6175         }
6176         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6177             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6178         }
6179         return h;
6180     };
6181
6182     var stopListening = function(el, ename, fn){
6183         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6184         if(hds){
6185             for(var i = 0, len = hds.length; i < len; i++){
6186                 var h = hds[i];
6187                 if(h[0] == id && h[1] == ename){
6188                     hd = h[2];
6189                     hds.splice(i, 1);
6190                     break;
6191                 }
6192             }
6193         }
6194         E.un(el, ename, hd);
6195         el = Roo.getDom(el);
6196         if(ename == "mousewheel" && el.addEventListener){
6197             el.removeEventListener("DOMMouseScroll", hd, false);
6198         }
6199         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6200             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6201         }
6202     };
6203
6204     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6205     
6206     var pub = {
6207         
6208         
6209         /** 
6210          * Fix for doc tools
6211          * @scope Roo.EventManager
6212          */
6213         
6214         
6215         /** 
6216          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6217          * object with a Roo.EventObject
6218          * @param {Function} fn        The method the event invokes
6219          * @param {Object}   scope    An object that becomes the scope of the handler
6220          * @param {boolean}  override If true, the obj passed in becomes
6221          *                             the execution scope of the listener
6222          * @return {Function} The wrapped function
6223          * @deprecated
6224          */
6225         wrap : function(fn, scope, override){
6226             return function(e){
6227                 Roo.EventObject.setEvent(e);
6228                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6229             };
6230         },
6231         
6232         /**
6233      * Appends an event handler to an element (shorthand for addListener)
6234      * @param {String/HTMLElement}   element        The html element or id to assign the
6235      * @param {String}   eventName The type of event to listen for
6236      * @param {Function} handler The method the event invokes
6237      * @param {Object}   scope (optional) The scope in which to execute the handler
6238      * function. The handler function's "this" context.
6239      * @param {Object}   options (optional) An object containing handler configuration
6240      * properties. This may contain any of the following properties:<ul>
6241      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6242      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6243      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6244      * <li>preventDefault {Boolean} True to prevent the default action</li>
6245      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6246      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6247      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6248      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6249      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6250      * by the specified number of milliseconds. If the event fires again within that time, the original
6251      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6252      * </ul><br>
6253      * <p>
6254      * <b>Combining Options</b><br>
6255      * Using the options argument, it is possible to combine different types of listeners:<br>
6256      * <br>
6257      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6258      * Code:<pre><code>
6259 el.on('click', this.onClick, this, {
6260     single: true,
6261     delay: 100,
6262     stopEvent : true,
6263     forumId: 4
6264 });</code></pre>
6265      * <p>
6266      * <b>Attaching multiple handlers in 1 call</b><br>
6267       * The method also allows for a single argument to be passed which is a config object containing properties
6268      * which specify multiple handlers.
6269      * <p>
6270      * Code:<pre><code>
6271 el.on({
6272     'click' : {
6273         fn: this.onClick
6274         scope: this,
6275         delay: 100
6276     },
6277     'mouseover' : {
6278         fn: this.onMouseOver
6279         scope: this
6280     },
6281     'mouseout' : {
6282         fn: this.onMouseOut
6283         scope: this
6284     }
6285 });</code></pre>
6286      * <p>
6287      * Or a shorthand syntax:<br>
6288      * Code:<pre><code>
6289 el.on({
6290     'click' : this.onClick,
6291     'mouseover' : this.onMouseOver,
6292     'mouseout' : this.onMouseOut
6293     scope: this
6294 });</code></pre>
6295      */
6296         addListener : function(element, eventName, fn, scope, options){
6297             if(typeof eventName == "object"){
6298                 var o = eventName;
6299                 for(var e in o){
6300                     if(propRe.test(e)){
6301                         continue;
6302                     }
6303                     if(typeof o[e] == "function"){
6304                         // shared options
6305                         listen(element, e, o, o[e], o.scope);
6306                     }else{
6307                         // individual options
6308                         listen(element, e, o[e]);
6309                     }
6310                 }
6311                 return;
6312             }
6313             return listen(element, eventName, options, fn, scope);
6314         },
6315         
6316         /**
6317          * Removes an event handler
6318          *
6319          * @param {String/HTMLElement}   element        The id or html element to remove the 
6320          *                             event from
6321          * @param {String}   eventName     The type of event
6322          * @param {Function} fn
6323          * @return {Boolean} True if a listener was actually removed
6324          */
6325         removeListener : function(element, eventName, fn){
6326             return stopListening(element, eventName, fn);
6327         },
6328         
6329         /**
6330          * Fires when the document is ready (before onload and before images are loaded). Can be 
6331          * accessed shorthanded Roo.onReady().
6332          * @param {Function} fn        The method the event invokes
6333          * @param {Object}   scope    An  object that becomes the scope of the handler
6334          * @param {boolean}  options
6335          */
6336         onDocumentReady : function(fn, scope, options){
6337             if(docReadyState){ // if it already fired
6338                 docReadyEvent.addListener(fn, scope, options);
6339                 docReadyEvent.fire();
6340                 docReadyEvent.clearListeners();
6341                 return;
6342             }
6343             if(!docReadyEvent){
6344                 initDocReady();
6345             }
6346             docReadyEvent.addListener(fn, scope, options);
6347         },
6348         
6349         /**
6350          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6351          * @param {Function} fn        The method the event invokes
6352          * @param {Object}   scope    An object that becomes the scope of the handler
6353          * @param {boolean}  options
6354          */
6355         onWindowResize : function(fn, scope, options){
6356             if(!resizeEvent){
6357                 resizeEvent = new Roo.util.Event();
6358                 resizeTask = new Roo.util.DelayedTask(function(){
6359                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6360                 });
6361                 E.on(window, "resize", function(){
6362                     if(Roo.isIE){
6363                         resizeTask.delay(50);
6364                     }else{
6365                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6366                     }
6367                 });
6368             }
6369             resizeEvent.addListener(fn, scope, options);
6370         },
6371
6372         /**
6373          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6374          * @param {Function} fn        The method the event invokes
6375          * @param {Object}   scope    An object that becomes the scope of the handler
6376          * @param {boolean}  options
6377          */
6378         onTextResize : function(fn, scope, options){
6379             if(!textEvent){
6380                 textEvent = new Roo.util.Event();
6381                 var textEl = new Roo.Element(document.createElement('div'));
6382                 textEl.dom.className = 'x-text-resize';
6383                 textEl.dom.innerHTML = 'X';
6384                 textEl.appendTo(document.body);
6385                 textSize = textEl.dom.offsetHeight;
6386                 setInterval(function(){
6387                     if(textEl.dom.offsetHeight != textSize){
6388                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6389                     }
6390                 }, this.textResizeInterval);
6391             }
6392             textEvent.addListener(fn, scope, options);
6393         },
6394
6395         /**
6396          * Removes the passed window resize listener.
6397          * @param {Function} fn        The method the event invokes
6398          * @param {Object}   scope    The scope of handler
6399          */
6400         removeResizeListener : function(fn, scope){
6401             if(resizeEvent){
6402                 resizeEvent.removeListener(fn, scope);
6403             }
6404         },
6405
6406         // private
6407         fireResize : function(){
6408             if(resizeEvent){
6409                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6410             }   
6411         },
6412         /**
6413          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6414          */
6415         ieDeferSrc : false,
6416         /**
6417          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6418          */
6419         textResizeInterval : 50
6420     };
6421     
6422     /**
6423      * Fix for doc tools
6424      * @scopeAlias pub=Roo.EventManager
6425      */
6426     
6427      /**
6428      * Appends an event handler to an element (shorthand for addListener)
6429      * @param {String/HTMLElement}   element        The html element or id to assign the
6430      * @param {String}   eventName The type of event to listen for
6431      * @param {Function} handler The method the event invokes
6432      * @param {Object}   scope (optional) The scope in which to execute the handler
6433      * function. The handler function's "this" context.
6434      * @param {Object}   options (optional) An object containing handler configuration
6435      * properties. This may contain any of the following properties:<ul>
6436      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6437      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6438      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6439      * <li>preventDefault {Boolean} True to prevent the default action</li>
6440      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6441      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6442      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6443      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6444      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6445      * by the specified number of milliseconds. If the event fires again within that time, the original
6446      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6447      * </ul><br>
6448      * <p>
6449      * <b>Combining Options</b><br>
6450      * Using the options argument, it is possible to combine different types of listeners:<br>
6451      * <br>
6452      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6453      * Code:<pre><code>
6454 el.on('click', this.onClick, this, {
6455     single: true,
6456     delay: 100,
6457     stopEvent : true,
6458     forumId: 4
6459 });</code></pre>
6460      * <p>
6461      * <b>Attaching multiple handlers in 1 call</b><br>
6462       * The method also allows for a single argument to be passed which is a config object containing properties
6463      * which specify multiple handlers.
6464      * <p>
6465      * Code:<pre><code>
6466 el.on({
6467     'click' : {
6468         fn: this.onClick
6469         scope: this,
6470         delay: 100
6471     },
6472     'mouseover' : {
6473         fn: this.onMouseOver
6474         scope: this
6475     },
6476     'mouseout' : {
6477         fn: this.onMouseOut
6478         scope: this
6479     }
6480 });</code></pre>
6481      * <p>
6482      * Or a shorthand syntax:<br>
6483      * Code:<pre><code>
6484 el.on({
6485     'click' : this.onClick,
6486     'mouseover' : this.onMouseOver,
6487     'mouseout' : this.onMouseOut
6488     scope: this
6489 });</code></pre>
6490      */
6491     pub.on = pub.addListener;
6492     pub.un = pub.removeListener;
6493
6494     pub.stoppedMouseDownEvent = new Roo.util.Event();
6495     return pub;
6496 }();
6497 /**
6498   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6499   * @param {Function} fn        The method the event invokes
6500   * @param {Object}   scope    An  object that becomes the scope of the handler
6501   * @param {boolean}  override If true, the obj passed in becomes
6502   *                             the execution scope of the listener
6503   * @member Roo
6504   * @method onReady
6505  */
6506 Roo.onReady = Roo.EventManager.onDocumentReady;
6507
6508 Roo.onReady(function(){
6509     var bd = Roo.get(document.body);
6510     if(!bd){ return; }
6511
6512     var cls = [
6513             Roo.isIE ? "roo-ie"
6514             : Roo.isGecko ? "roo-gecko"
6515             : Roo.isOpera ? "roo-opera"
6516             : Roo.isSafari ? "roo-safari" : ""];
6517
6518     if(Roo.isMac){
6519         cls.push("roo-mac");
6520     }
6521     if(Roo.isLinux){
6522         cls.push("roo-linux");
6523     }
6524     if(Roo.isBorderBox){
6525         cls.push('roo-border-box');
6526     }
6527     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6528         var p = bd.dom.parentNode;
6529         if(p){
6530             p.className += ' roo-strict';
6531         }
6532     }
6533     bd.addClass(cls.join(' '));
6534 });
6535
6536 /**
6537  * @class Roo.EventObject
6538  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6539  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6540  * Example:
6541  * <pre><code>
6542  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6543     e.preventDefault();
6544     var target = e.getTarget();
6545     ...
6546  }
6547  var myDiv = Roo.get("myDiv");
6548  myDiv.on("click", handleClick);
6549  //or
6550  Roo.EventManager.on("myDiv", 'click', handleClick);
6551  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6552  </code></pre>
6553  * @singleton
6554  */
6555 Roo.EventObject = function(){
6556     
6557     var E = Roo.lib.Event;
6558     
6559     // safari keypress events for special keys return bad keycodes
6560     var safariKeys = {
6561         63234 : 37, // left
6562         63235 : 39, // right
6563         63232 : 38, // up
6564         63233 : 40, // down
6565         63276 : 33, // page up
6566         63277 : 34, // page down
6567         63272 : 46, // delete
6568         63273 : 36, // home
6569         63275 : 35  // end
6570     };
6571
6572     // normalize button clicks
6573     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6574                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6575
6576     Roo.EventObjectImpl = function(e){
6577         if(e){
6578             this.setEvent(e.browserEvent || e);
6579         }
6580     };
6581     Roo.EventObjectImpl.prototype = {
6582         /**
6583          * Used to fix doc tools.
6584          * @scope Roo.EventObject.prototype
6585          */
6586             
6587
6588         
6589         
6590         /** The normal browser event */
6591         browserEvent : null,
6592         /** The button pressed in a mouse event */
6593         button : -1,
6594         /** True if the shift key was down during the event */
6595         shiftKey : false,
6596         /** True if the control key was down during the event */
6597         ctrlKey : false,
6598         /** True if the alt key was down during the event */
6599         altKey : false,
6600
6601         /** Key constant 
6602         * @type Number */
6603         BACKSPACE : 8,
6604         /** Key constant 
6605         * @type Number */
6606         TAB : 9,
6607         /** Key constant 
6608         * @type Number */
6609         RETURN : 13,
6610         /** Key constant 
6611         * @type Number */
6612         ENTER : 13,
6613         /** Key constant 
6614         * @type Number */
6615         SHIFT : 16,
6616         /** Key constant 
6617         * @type Number */
6618         CONTROL : 17,
6619         /** Key constant 
6620         * @type Number */
6621         ESC : 27,
6622         /** Key constant 
6623         * @type Number */
6624         SPACE : 32,
6625         /** Key constant 
6626         * @type Number */
6627         PAGEUP : 33,
6628         /** Key constant 
6629         * @type Number */
6630         PAGEDOWN : 34,
6631         /** Key constant 
6632         * @type Number */
6633         END : 35,
6634         /** Key constant 
6635         * @type Number */
6636         HOME : 36,
6637         /** Key constant 
6638         * @type Number */
6639         LEFT : 37,
6640         /** Key constant 
6641         * @type Number */
6642         UP : 38,
6643         /** Key constant 
6644         * @type Number */
6645         RIGHT : 39,
6646         /** Key constant 
6647         * @type Number */
6648         DOWN : 40,
6649         /** Key constant 
6650         * @type Number */
6651         DELETE : 46,
6652         /** Key constant 
6653         * @type Number */
6654         F5 : 116,
6655
6656            /** @private */
6657         setEvent : function(e){
6658             if(e == this || (e && e.browserEvent)){ // already wrapped
6659                 return e;
6660             }
6661             this.browserEvent = e;
6662             if(e){
6663                 // normalize buttons
6664                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6665                 if(e.type == 'click' && this.button == -1){
6666                     this.button = 0;
6667                 }
6668                 this.type = e.type;
6669                 this.shiftKey = e.shiftKey;
6670                 // mac metaKey behaves like ctrlKey
6671                 this.ctrlKey = e.ctrlKey || e.metaKey;
6672                 this.altKey = e.altKey;
6673                 // in getKey these will be normalized for the mac
6674                 this.keyCode = e.keyCode;
6675                 // keyup warnings on firefox.
6676                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6677                 // cache the target for the delayed and or buffered events
6678                 this.target = E.getTarget(e);
6679                 // same for XY
6680                 this.xy = E.getXY(e);
6681             }else{
6682                 this.button = -1;
6683                 this.shiftKey = false;
6684                 this.ctrlKey = false;
6685                 this.altKey = false;
6686                 this.keyCode = 0;
6687                 this.charCode =0;
6688                 this.target = null;
6689                 this.xy = [0, 0];
6690             }
6691             return this;
6692         },
6693
6694         /**
6695          * Stop the event (preventDefault and stopPropagation)
6696          */
6697         stopEvent : function(){
6698             if(this.browserEvent){
6699                 if(this.browserEvent.type == 'mousedown'){
6700                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6701                 }
6702                 E.stopEvent(this.browserEvent);
6703             }
6704         },
6705
6706         /**
6707          * Prevents the browsers default handling of the event.
6708          */
6709         preventDefault : function(){
6710             if(this.browserEvent){
6711                 E.preventDefault(this.browserEvent);
6712             }
6713         },
6714
6715         /** @private */
6716         isNavKeyPress : function(){
6717             var k = this.keyCode;
6718             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6719             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6720         },
6721
6722         isSpecialKey : function(){
6723             var k = this.keyCode;
6724             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6725             (k == 16) || (k == 17) ||
6726             (k >= 18 && k <= 20) ||
6727             (k >= 33 && k <= 35) ||
6728             (k >= 36 && k <= 39) ||
6729             (k >= 44 && k <= 45);
6730         },
6731         /**
6732          * Cancels bubbling of the event.
6733          */
6734         stopPropagation : function(){
6735             if(this.browserEvent){
6736                 if(this.type == 'mousedown'){
6737                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6738                 }
6739                 E.stopPropagation(this.browserEvent);
6740             }
6741         },
6742
6743         /**
6744          * Gets the key code for the event.
6745          * @return {Number}
6746          */
6747         getCharCode : function(){
6748             return this.charCode || this.keyCode;
6749         },
6750
6751         /**
6752          * Returns a normalized keyCode for the event.
6753          * @return {Number} The key code
6754          */
6755         getKey : function(){
6756             var k = this.keyCode || this.charCode;
6757             return Roo.isSafari ? (safariKeys[k] || k) : k;
6758         },
6759
6760         /**
6761          * Gets the x coordinate of the event.
6762          * @return {Number}
6763          */
6764         getPageX : function(){
6765             return this.xy[0];
6766         },
6767
6768         /**
6769          * Gets the y coordinate of the event.
6770          * @return {Number}
6771          */
6772         getPageY : function(){
6773             return this.xy[1];
6774         },
6775
6776         /**
6777          * Gets the time of the event.
6778          * @return {Number}
6779          */
6780         getTime : function(){
6781             if(this.browserEvent){
6782                 return E.getTime(this.browserEvent);
6783             }
6784             return null;
6785         },
6786
6787         /**
6788          * Gets the page coordinates of the event.
6789          * @return {Array} The xy values like [x, y]
6790          */
6791         getXY : function(){
6792             return this.xy;
6793         },
6794
6795         /**
6796          * Gets the target for the event.
6797          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6798          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6799                 search as a number or element (defaults to 10 || document.body)
6800          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6801          * @return {HTMLelement}
6802          */
6803         getTarget : function(selector, maxDepth, returnEl){
6804             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6805         },
6806         /**
6807          * Gets the related target.
6808          * @return {HTMLElement}
6809          */
6810         getRelatedTarget : function(){
6811             if(this.browserEvent){
6812                 return E.getRelatedTarget(this.browserEvent);
6813             }
6814             return null;
6815         },
6816
6817         /**
6818          * Normalizes mouse wheel delta across browsers
6819          * @return {Number} The delta
6820          */
6821         getWheelDelta : function(){
6822             var e = this.browserEvent;
6823             var delta = 0;
6824             if(e.wheelDelta){ /* IE/Opera. */
6825                 delta = e.wheelDelta/120;
6826             }else if(e.detail){ /* Mozilla case. */
6827                 delta = -e.detail/3;
6828             }
6829             return delta;
6830         },
6831
6832         /**
6833          * Returns true if the control, meta, shift or alt key was pressed during this event.
6834          * @return {Boolean}
6835          */
6836         hasModifier : function(){
6837             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6838         },
6839
6840         /**
6841          * Returns true if the target of this event equals el or is a child of el
6842          * @param {String/HTMLElement/Element} el
6843          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6844          * @return {Boolean}
6845          */
6846         within : function(el, related){
6847             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6848             return t && Roo.fly(el).contains(t);
6849         },
6850
6851         getPoint : function(){
6852             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6853         }
6854     };
6855
6856     return new Roo.EventObjectImpl();
6857 }();
6858             
6859     /*
6860  * Based on:
6861  * Ext JS Library 1.1.1
6862  * Copyright(c) 2006-2007, Ext JS, LLC.
6863  *
6864  * Originally Released Under LGPL - original licence link has changed is not relivant.
6865  *
6866  * Fork - LGPL
6867  * <script type="text/javascript">
6868  */
6869
6870  
6871 // was in Composite Element!??!?!
6872  
6873 (function(){
6874     var D = Roo.lib.Dom;
6875     var E = Roo.lib.Event;
6876     var A = Roo.lib.Anim;
6877
6878     // local style camelizing for speed
6879     var propCache = {};
6880     var camelRe = /(-[a-z])/gi;
6881     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6882     var view = document.defaultView;
6883
6884 /**
6885  * @class Roo.Element
6886  * Represents an Element in the DOM.<br><br>
6887  * Usage:<br>
6888 <pre><code>
6889 var el = Roo.get("my-div");
6890
6891 // or with getEl
6892 var el = getEl("my-div");
6893
6894 // or with a DOM element
6895 var el = Roo.get(myDivElement);
6896 </code></pre>
6897  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6898  * each call instead of constructing a new one.<br><br>
6899  * <b>Animations</b><br />
6900  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6901  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6902 <pre>
6903 Option    Default   Description
6904 --------- --------  ---------------------------------------------
6905 duration  .35       The duration of the animation in seconds
6906 easing    easeOut   The YUI easing method
6907 callback  none      A function to execute when the anim completes
6908 scope     this      The scope (this) of the callback function
6909 </pre>
6910 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6911 * manipulate the animation. Here's an example:
6912 <pre><code>
6913 var el = Roo.get("my-div");
6914
6915 // no animation
6916 el.setWidth(100);
6917
6918 // default animation
6919 el.setWidth(100, true);
6920
6921 // animation with some options set
6922 el.setWidth(100, {
6923     duration: 1,
6924     callback: this.foo,
6925     scope: this
6926 });
6927
6928 // using the "anim" property to get the Anim object
6929 var opt = {
6930     duration: 1,
6931     callback: this.foo,
6932     scope: this
6933 };
6934 el.setWidth(100, opt);
6935 ...
6936 if(opt.anim.isAnimated()){
6937     opt.anim.stop();
6938 }
6939 </code></pre>
6940 * <b> Composite (Collections of) Elements</b><br />
6941  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6942  * @constructor Create a new Element directly.
6943  * @param {String/HTMLElement} element
6944  * @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).
6945  */
6946     Roo.Element = function(element, forceNew){
6947         var dom = typeof element == "string" ?
6948                 document.getElementById(element) : element;
6949         if(!dom){ // invalid id/element
6950             return null;
6951         }
6952         var id = dom.id;
6953         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6954             return Roo.Element.cache[id];
6955         }
6956
6957         /**
6958          * The DOM element
6959          * @type HTMLElement
6960          */
6961         this.dom = dom;
6962
6963         /**
6964          * The DOM element ID
6965          * @type String
6966          */
6967         this.id = id || Roo.id(dom);
6968     };
6969
6970     var El = Roo.Element;
6971
6972     El.prototype = {
6973         /**
6974          * The element's default display mode  (defaults to "")
6975          * @type String
6976          */
6977         originalDisplay : "",
6978
6979         visibilityMode : 1,
6980         /**
6981          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6982          * @type String
6983          */
6984         defaultUnit : "px",
6985         /**
6986          * Sets the element's visibility mode. When setVisible() is called it
6987          * will use this to determine whether to set the visibility or the display property.
6988          * @param visMode Element.VISIBILITY or Element.DISPLAY
6989          * @return {Roo.Element} this
6990          */
6991         setVisibilityMode : function(visMode){
6992             this.visibilityMode = visMode;
6993             return this;
6994         },
6995         /**
6996          * Convenience method for setVisibilityMode(Element.DISPLAY)
6997          * @param {String} display (optional) What to set display to when visible
6998          * @return {Roo.Element} this
6999          */
7000         enableDisplayMode : function(display){
7001             this.setVisibilityMode(El.DISPLAY);
7002             if(typeof display != "undefined") this.originalDisplay = display;
7003             return this;
7004         },
7005
7006         /**
7007          * 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)
7008          * @param {String} selector The simple selector to test
7009          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7010                 search as a number or element (defaults to 10 || document.body)
7011          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7012          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7013          */
7014         findParent : function(simpleSelector, maxDepth, returnEl){
7015             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7016             maxDepth = maxDepth || 50;
7017             if(typeof maxDepth != "number"){
7018                 stopEl = Roo.getDom(maxDepth);
7019                 maxDepth = 10;
7020             }
7021             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7022                 if(dq.is(p, simpleSelector)){
7023                     return returnEl ? Roo.get(p) : p;
7024                 }
7025                 depth++;
7026                 p = p.parentNode;
7027             }
7028             return null;
7029         },
7030
7031
7032         /**
7033          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7034          * @param {String} selector The simple selector to test
7035          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7036                 search as a number or element (defaults to 10 || document.body)
7037          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7038          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7039          */
7040         findParentNode : function(simpleSelector, maxDepth, returnEl){
7041             var p = Roo.fly(this.dom.parentNode, '_internal');
7042             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7043         },
7044
7045         /**
7046          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7047          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7048          * @param {String} selector The simple selector to test
7049          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7050                 search as a number or element (defaults to 10 || document.body)
7051          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7052          */
7053         up : function(simpleSelector, maxDepth){
7054             return this.findParentNode(simpleSelector, maxDepth, true);
7055         },
7056
7057
7058
7059         /**
7060          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7061          * @param {String} selector The simple selector to test
7062          * @return {Boolean} True if this element matches the selector, else false
7063          */
7064         is : function(simpleSelector){
7065             return Roo.DomQuery.is(this.dom, simpleSelector);
7066         },
7067
7068         /**
7069          * Perform animation on this element.
7070          * @param {Object} args The YUI animation control args
7071          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7072          * @param {Function} onComplete (optional) Function to call when animation completes
7073          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7074          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7075          * @return {Roo.Element} this
7076          */
7077         animate : function(args, duration, onComplete, easing, animType){
7078             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7079             return this;
7080         },
7081
7082         /*
7083          * @private Internal animation call
7084          */
7085         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7086             animType = animType || 'run';
7087             opt = opt || {};
7088             var anim = Roo.lib.Anim[animType](
7089                 this.dom, args,
7090                 (opt.duration || defaultDur) || .35,
7091                 (opt.easing || defaultEase) || 'easeOut',
7092                 function(){
7093                     Roo.callback(cb, this);
7094                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7095                 },
7096                 this
7097             );
7098             opt.anim = anim;
7099             return anim;
7100         },
7101
7102         // private legacy anim prep
7103         preanim : function(a, i){
7104             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7105         },
7106
7107         /**
7108          * Removes worthless text nodes
7109          * @param {Boolean} forceReclean (optional) By default the element
7110          * keeps track if it has been cleaned already so
7111          * you can call this over and over. However, if you update the element and
7112          * need to force a reclean, you can pass true.
7113          */
7114         clean : function(forceReclean){
7115             if(this.isCleaned && forceReclean !== true){
7116                 return this;
7117             }
7118             var ns = /\S/;
7119             var d = this.dom, n = d.firstChild, ni = -1;
7120             while(n){
7121                 var nx = n.nextSibling;
7122                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7123                     d.removeChild(n);
7124                 }else{
7125                     n.nodeIndex = ++ni;
7126                 }
7127                 n = nx;
7128             }
7129             this.isCleaned = true;
7130             return this;
7131         },
7132
7133         // private
7134         calcOffsetsTo : function(el){
7135             el = Roo.get(el);
7136             var d = el.dom;
7137             var restorePos = false;
7138             if(el.getStyle('position') == 'static'){
7139                 el.position('relative');
7140                 restorePos = true;
7141             }
7142             var x = 0, y =0;
7143             var op = this.dom;
7144             while(op && op != d && op.tagName != 'HTML'){
7145                 x+= op.offsetLeft;
7146                 y+= op.offsetTop;
7147                 op = op.offsetParent;
7148             }
7149             if(restorePos){
7150                 el.position('static');
7151             }
7152             return [x, y];
7153         },
7154
7155         /**
7156          * Scrolls this element into view within the passed container.
7157          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7158          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7159          * @return {Roo.Element} this
7160          */
7161         scrollIntoView : function(container, hscroll){
7162             var c = Roo.getDom(container) || document.body;
7163             var el = this.dom;
7164
7165             var o = this.calcOffsetsTo(c),
7166                 l = o[0],
7167                 t = o[1],
7168                 b = t+el.offsetHeight,
7169                 r = l+el.offsetWidth;
7170
7171             var ch = c.clientHeight;
7172             var ct = parseInt(c.scrollTop, 10);
7173             var cl = parseInt(c.scrollLeft, 10);
7174             var cb = ct + ch;
7175             var cr = cl + c.clientWidth;
7176
7177             if(t < ct){
7178                 c.scrollTop = t;
7179             }else if(b > cb){
7180                 c.scrollTop = b-ch;
7181             }
7182
7183             if(hscroll !== false){
7184                 if(l < cl){
7185                     c.scrollLeft = l;
7186                 }else if(r > cr){
7187                     c.scrollLeft = r-c.clientWidth;
7188                 }
7189             }
7190             return this;
7191         },
7192
7193         // private
7194         scrollChildIntoView : function(child, hscroll){
7195             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7196         },
7197
7198         /**
7199          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7200          * the new height may not be available immediately.
7201          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7202          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7203          * @param {Function} onComplete (optional) Function to call when animation completes
7204          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7205          * @return {Roo.Element} this
7206          */
7207         autoHeight : function(animate, duration, onComplete, easing){
7208             var oldHeight = this.getHeight();
7209             this.clip();
7210             this.setHeight(1); // force clipping
7211             setTimeout(function(){
7212                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7213                 if(!animate){
7214                     this.setHeight(height);
7215                     this.unclip();
7216                     if(typeof onComplete == "function"){
7217                         onComplete();
7218                     }
7219                 }else{
7220                     this.setHeight(oldHeight); // restore original height
7221                     this.setHeight(height, animate, duration, function(){
7222                         this.unclip();
7223                         if(typeof onComplete == "function") onComplete();
7224                     }.createDelegate(this), easing);
7225                 }
7226             }.createDelegate(this), 0);
7227             return this;
7228         },
7229
7230         /**
7231          * Returns true if this element is an ancestor of the passed element
7232          * @param {HTMLElement/String} el The element to check
7233          * @return {Boolean} True if this element is an ancestor of el, else false
7234          */
7235         contains : function(el){
7236             if(!el){return false;}
7237             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7238         },
7239
7240         /**
7241          * Checks whether the element is currently visible using both visibility and display properties.
7242          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7243          * @return {Boolean} True if the element is currently visible, else false
7244          */
7245         isVisible : function(deep) {
7246             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7247             if(deep !== true || !vis){
7248                 return vis;
7249             }
7250             var p = this.dom.parentNode;
7251             while(p && p.tagName.toLowerCase() != "body"){
7252                 if(!Roo.fly(p, '_isVisible').isVisible()){
7253                     return false;
7254                 }
7255                 p = p.parentNode;
7256             }
7257             return true;
7258         },
7259
7260         /**
7261          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7262          * @param {String} selector The CSS selector
7263          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7264          * @return {CompositeElement/CompositeElementLite} The composite element
7265          */
7266         select : function(selector, unique){
7267             return El.select(selector, unique, this.dom);
7268         },
7269
7270         /**
7271          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7272          * @param {String} selector The CSS selector
7273          * @return {Array} An array of the matched nodes
7274          */
7275         query : function(selector, unique){
7276             return Roo.DomQuery.select(selector, this.dom);
7277         },
7278
7279         /**
7280          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7281          * @param {String} selector The CSS selector
7282          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7283          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284          */
7285         child : function(selector, returnDom){
7286             var n = Roo.DomQuery.selectNode(selector, this.dom);
7287             return returnDom ? n : Roo.get(n);
7288         },
7289
7290         /**
7291          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7292          * @param {String} selector The CSS selector
7293          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7294          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7295          */
7296         down : function(selector, returnDom){
7297             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7298             return returnDom ? n : Roo.get(n);
7299         },
7300
7301         /**
7302          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7303          * @param {String} group The group the DD object is member of
7304          * @param {Object} config The DD config object
7305          * @param {Object} overrides An object containing methods to override/implement on the DD object
7306          * @return {Roo.dd.DD} The DD object
7307          */
7308         initDD : function(group, config, overrides){
7309             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7310             return Roo.apply(dd, overrides);
7311         },
7312
7313         /**
7314          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7315          * @param {String} group The group the DDProxy object is member of
7316          * @param {Object} config The DDProxy config object
7317          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7318          * @return {Roo.dd.DDProxy} The DDProxy object
7319          */
7320         initDDProxy : function(group, config, overrides){
7321             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7322             return Roo.apply(dd, overrides);
7323         },
7324
7325         /**
7326          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7327          * @param {String} group The group the DDTarget object is member of
7328          * @param {Object} config The DDTarget config object
7329          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7330          * @return {Roo.dd.DDTarget} The DDTarget object
7331          */
7332         initDDTarget : function(group, config, overrides){
7333             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7334             return Roo.apply(dd, overrides);
7335         },
7336
7337         /**
7338          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7339          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7340          * @param {Boolean} visible Whether the element is visible
7341          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7342          * @return {Roo.Element} this
7343          */
7344          setVisible : function(visible, animate){
7345             if(!animate || !A){
7346                 if(this.visibilityMode == El.DISPLAY){
7347                     this.setDisplayed(visible);
7348                 }else{
7349                     this.fixDisplay();
7350                     this.dom.style.visibility = visible ? "visible" : "hidden";
7351                 }
7352             }else{
7353                 // closure for composites
7354                 var dom = this.dom;
7355                 var visMode = this.visibilityMode;
7356                 if(visible){
7357                     this.setOpacity(.01);
7358                     this.setVisible(true);
7359                 }
7360                 this.anim({opacity: { to: (visible?1:0) }},
7361                       this.preanim(arguments, 1),
7362                       null, .35, 'easeIn', function(){
7363                          if(!visible){
7364                              if(visMode == El.DISPLAY){
7365                                  dom.style.display = "none";
7366                              }else{
7367                                  dom.style.visibility = "hidden";
7368                              }
7369                              Roo.get(dom).setOpacity(1);
7370                          }
7371                      });
7372             }
7373             return this;
7374         },
7375
7376         /**
7377          * Returns true if display is not "none"
7378          * @return {Boolean}
7379          */
7380         isDisplayed : function() {
7381             return this.getStyle("display") != "none";
7382         },
7383
7384         /**
7385          * Toggles the element's visibility or display, depending on visibility mode.
7386          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7387          * @return {Roo.Element} this
7388          */
7389         toggle : function(animate){
7390             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7391             return this;
7392         },
7393
7394         /**
7395          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7396          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7397          * @return {Roo.Element} this
7398          */
7399         setDisplayed : function(value) {
7400             if(typeof value == "boolean"){
7401                value = value ? this.originalDisplay : "none";
7402             }
7403             this.setStyle("display", value);
7404             return this;
7405         },
7406
7407         /**
7408          * Tries to focus the element. Any exceptions are caught and ignored.
7409          * @return {Roo.Element} this
7410          */
7411         focus : function() {
7412             try{
7413                 this.dom.focus();
7414             }catch(e){}
7415             return this;
7416         },
7417
7418         /**
7419          * Tries to blur the element. Any exceptions are caught and ignored.
7420          * @return {Roo.Element} this
7421          */
7422         blur : function() {
7423             try{
7424                 this.dom.blur();
7425             }catch(e){}
7426             return this;
7427         },
7428
7429         /**
7430          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7431          * @param {String/Array} className The CSS class to add, or an array of classes
7432          * @return {Roo.Element} this
7433          */
7434         addClass : function(className){
7435             if(className instanceof Array){
7436                 for(var i = 0, len = className.length; i < len; i++) {
7437                     this.addClass(className[i]);
7438                 }
7439             }else{
7440                 if(className && !this.hasClass(className)){
7441                     this.dom.className = this.dom.className + " " + className;
7442                 }
7443             }
7444             return this;
7445         },
7446
7447         /**
7448          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7449          * @param {String/Array} className The CSS class to add, or an array of classes
7450          * @return {Roo.Element} this
7451          */
7452         radioClass : function(className){
7453             var siblings = this.dom.parentNode.childNodes;
7454             for(var i = 0; i < siblings.length; i++) {
7455                 var s = siblings[i];
7456                 if(s.nodeType == 1){
7457                     Roo.get(s).removeClass(className);
7458                 }
7459             }
7460             this.addClass(className);
7461             return this;
7462         },
7463
7464         /**
7465          * Removes one or more CSS classes from the element.
7466          * @param {String/Array} className The CSS class to remove, or an array of classes
7467          * @return {Roo.Element} this
7468          */
7469         removeClass : function(className){
7470             if(!className || !this.dom.className){
7471                 return this;
7472             }
7473             if(className instanceof Array){
7474                 for(var i = 0, len = className.length; i < len; i++) {
7475                     this.removeClass(className[i]);
7476                 }
7477             }else{
7478                 if(this.hasClass(className)){
7479                     var re = this.classReCache[className];
7480                     if (!re) {
7481                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7482                        this.classReCache[className] = re;
7483                     }
7484                     this.dom.className =
7485                         this.dom.className.replace(re, " ");
7486                 }
7487             }
7488             return this;
7489         },
7490
7491         // private
7492         classReCache: {},
7493
7494         /**
7495          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7496          * @param {String} className The CSS class to toggle
7497          * @return {Roo.Element} this
7498          */
7499         toggleClass : function(className){
7500             if(this.hasClass(className)){
7501                 this.removeClass(className);
7502             }else{
7503                 this.addClass(className);
7504             }
7505             return this;
7506         },
7507
7508         /**
7509          * Checks if the specified CSS class exists on this element's DOM node.
7510          * @param {String} className The CSS class to check for
7511          * @return {Boolean} True if the class exists, else false
7512          */
7513         hasClass : function(className){
7514             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7515         },
7516
7517         /**
7518          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7519          * @param {String} oldClassName The CSS class to replace
7520          * @param {String} newClassName The replacement CSS class
7521          * @return {Roo.Element} this
7522          */
7523         replaceClass : function(oldClassName, newClassName){
7524             this.removeClass(oldClassName);
7525             this.addClass(newClassName);
7526             return this;
7527         },
7528
7529         /**
7530          * Returns an object with properties matching the styles requested.
7531          * For example, el.getStyles('color', 'font-size', 'width') might return
7532          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7533          * @param {String} style1 A style name
7534          * @param {String} style2 A style name
7535          * @param {String} etc.
7536          * @return {Object} The style object
7537          */
7538         getStyles : function(){
7539             var a = arguments, len = a.length, r = {};
7540             for(var i = 0; i < len; i++){
7541                 r[a[i]] = this.getStyle(a[i]);
7542             }
7543             return r;
7544         },
7545
7546         /**
7547          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7548          * @param {String} property The style property whose value is returned.
7549          * @return {String} The current value of the style property for this element.
7550          */
7551         getStyle : function(){
7552             return view && view.getComputedStyle ?
7553                 function(prop){
7554                     var el = this.dom, v, cs, camel;
7555                     if(prop == 'float'){
7556                         prop = "cssFloat";
7557                     }
7558                     if(el.style && (v = el.style[prop])){
7559                         return v;
7560                     }
7561                     if(cs = view.getComputedStyle(el, "")){
7562                         if(!(camel = propCache[prop])){
7563                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7564                         }
7565                         return cs[camel];
7566                     }
7567                     return null;
7568                 } :
7569                 function(prop){
7570                     var el = this.dom, v, cs, camel;
7571                     if(prop == 'opacity'){
7572                         if(typeof el.style.filter == 'string'){
7573                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7574                             if(m){
7575                                 var fv = parseFloat(m[1]);
7576                                 if(!isNaN(fv)){
7577                                     return fv ? fv / 100 : 0;
7578                                 }
7579                             }
7580                         }
7581                         return 1;
7582                     }else if(prop == 'float'){
7583                         prop = "styleFloat";
7584                     }
7585                     if(!(camel = propCache[prop])){
7586                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7587                     }
7588                     if(v = el.style[camel]){
7589                         return v;
7590                     }
7591                     if(cs = el.currentStyle){
7592                         return cs[camel];
7593                     }
7594                     return null;
7595                 };
7596         }(),
7597
7598         /**
7599          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7600          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7601          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7602          * @return {Roo.Element} this
7603          */
7604         setStyle : function(prop, value){
7605             if(typeof prop == "string"){
7606                 
7607                 if (prop == 'float') {
7608                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7609                     return this;
7610                 }
7611                 
7612                 var camel;
7613                 if(!(camel = propCache[prop])){
7614                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7615                 }
7616                 
7617                 if(camel == 'opacity') {
7618                     this.setOpacity(value);
7619                 }else{
7620                     this.dom.style[camel] = value;
7621                 }
7622             }else{
7623                 for(var style in prop){
7624                     if(typeof prop[style] != "function"){
7625                        this.setStyle(style, prop[style]);
7626                     }
7627                 }
7628             }
7629             return this;
7630         },
7631
7632         /**
7633          * More flexible version of {@link #setStyle} for setting style properties.
7634          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7635          * a function which returns such a specification.
7636          * @return {Roo.Element} this
7637          */
7638         applyStyles : function(style){
7639             Roo.DomHelper.applyStyles(this.dom, style);
7640             return this;
7641         },
7642
7643         /**
7644           * 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).
7645           * @return {Number} The X position of the element
7646           */
7647         getX : function(){
7648             return D.getX(this.dom);
7649         },
7650
7651         /**
7652           * 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).
7653           * @return {Number} The Y position of the element
7654           */
7655         getY : function(){
7656             return D.getY(this.dom);
7657         },
7658
7659         /**
7660           * 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).
7661           * @return {Array} The XY position of the element
7662           */
7663         getXY : function(){
7664             return D.getXY(this.dom);
7665         },
7666
7667         /**
7668          * 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).
7669          * @param {Number} The X position of the element
7670          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7671          * @return {Roo.Element} this
7672          */
7673         setX : function(x, animate){
7674             if(!animate || !A){
7675                 D.setX(this.dom, x);
7676             }else{
7677                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7678             }
7679             return this;
7680         },
7681
7682         /**
7683          * 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).
7684          * @param {Number} The Y position of the element
7685          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7686          * @return {Roo.Element} this
7687          */
7688         setY : function(y, animate){
7689             if(!animate || !A){
7690                 D.setY(this.dom, y);
7691             }else{
7692                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7693             }
7694             return this;
7695         },
7696
7697         /**
7698          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7699          * @param {String} left The left CSS property value
7700          * @return {Roo.Element} this
7701          */
7702         setLeft : function(left){
7703             this.setStyle("left", this.addUnits(left));
7704             return this;
7705         },
7706
7707         /**
7708          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7709          * @param {String} top The top CSS property value
7710          * @return {Roo.Element} this
7711          */
7712         setTop : function(top){
7713             this.setStyle("top", this.addUnits(top));
7714             return this;
7715         },
7716
7717         /**
7718          * Sets the element's CSS right style.
7719          * @param {String} right The right CSS property value
7720          * @return {Roo.Element} this
7721          */
7722         setRight : function(right){
7723             this.setStyle("right", this.addUnits(right));
7724             return this;
7725         },
7726
7727         /**
7728          * Sets the element's CSS bottom style.
7729          * @param {String} bottom The bottom CSS property value
7730          * @return {Roo.Element} this
7731          */
7732         setBottom : function(bottom){
7733             this.setStyle("bottom", this.addUnits(bottom));
7734             return this;
7735         },
7736
7737         /**
7738          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7739          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7740          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7741          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7742          * @return {Roo.Element} this
7743          */
7744         setXY : function(pos, animate){
7745             if(!animate || !A){
7746                 D.setXY(this.dom, pos);
7747             }else{
7748                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7749             }
7750             return this;
7751         },
7752
7753         /**
7754          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7755          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7756          * @param {Number} x X value for new position (coordinates are page-based)
7757          * @param {Number} y Y value for new position (coordinates are page-based)
7758          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7759          * @return {Roo.Element} this
7760          */
7761         setLocation : function(x, y, animate){
7762             this.setXY([x, y], this.preanim(arguments, 2));
7763             return this;
7764         },
7765
7766         /**
7767          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7768          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7769          * @param {Number} x X value for new position (coordinates are page-based)
7770          * @param {Number} y Y value for new position (coordinates are page-based)
7771          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7772          * @return {Roo.Element} this
7773          */
7774         moveTo : function(x, y, animate){
7775             this.setXY([x, y], this.preanim(arguments, 2));
7776             return this;
7777         },
7778
7779         /**
7780          * Returns the region of the given element.
7781          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7782          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7783          */
7784         getRegion : function(){
7785             return D.getRegion(this.dom);
7786         },
7787
7788         /**
7789          * Returns the offset height of the element
7790          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7791          * @return {Number} The element's height
7792          */
7793         getHeight : function(contentHeight){
7794             var h = this.dom.offsetHeight || 0;
7795             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7796         },
7797
7798         /**
7799          * Returns the offset width of the element
7800          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7801          * @return {Number} The element's width
7802          */
7803         getWidth : function(contentWidth){
7804             var w = this.dom.offsetWidth || 0;
7805             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7806         },
7807
7808         /**
7809          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7810          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7811          * if a height has not been set using CSS.
7812          * @return {Number}
7813          */
7814         getComputedHeight : function(){
7815             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7816             if(!h){
7817                 h = parseInt(this.getStyle('height'), 10) || 0;
7818                 if(!this.isBorderBox()){
7819                     h += this.getFrameWidth('tb');
7820                 }
7821             }
7822             return h;
7823         },
7824
7825         /**
7826          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7827          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7828          * if a width has not been set using CSS.
7829          * @return {Number}
7830          */
7831         getComputedWidth : function(){
7832             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7833             if(!w){
7834                 w = parseInt(this.getStyle('width'), 10) || 0;
7835                 if(!this.isBorderBox()){
7836                     w += this.getFrameWidth('lr');
7837                 }
7838             }
7839             return w;
7840         },
7841
7842         /**
7843          * Returns the size of the element.
7844          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7845          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7846          */
7847         getSize : function(contentSize){
7848             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7849         },
7850
7851         /**
7852          * Returns the width and height of the viewport.
7853          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7854          */
7855         getViewSize : function(){
7856             var d = this.dom, doc = document, aw = 0, ah = 0;
7857             if(d == doc || d == doc.body){
7858                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7859             }else{
7860                 return {
7861                     width : d.clientWidth,
7862                     height: d.clientHeight
7863                 };
7864             }
7865         },
7866
7867         /**
7868          * Returns the value of the "value" attribute
7869          * @param {Boolean} asNumber true to parse the value as a number
7870          * @return {String/Number}
7871          */
7872         getValue : function(asNumber){
7873             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7874         },
7875
7876         // private
7877         adjustWidth : function(width){
7878             if(typeof width == "number"){
7879                 if(this.autoBoxAdjust && !this.isBorderBox()){
7880                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7881                 }
7882                 if(width < 0){
7883                     width = 0;
7884                 }
7885             }
7886             return width;
7887         },
7888
7889         // private
7890         adjustHeight : function(height){
7891             if(typeof height == "number"){
7892                if(this.autoBoxAdjust && !this.isBorderBox()){
7893                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7894                }
7895                if(height < 0){
7896                    height = 0;
7897                }
7898             }
7899             return height;
7900         },
7901
7902         /**
7903          * Set the width of the element
7904          * @param {Number} width The new width
7905          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7906          * @return {Roo.Element} this
7907          */
7908         setWidth : function(width, animate){
7909             width = this.adjustWidth(width);
7910             if(!animate || !A){
7911                 this.dom.style.width = this.addUnits(width);
7912             }else{
7913                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7914             }
7915             return this;
7916         },
7917
7918         /**
7919          * Set the height of the element
7920          * @param {Number} height The new height
7921          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7922          * @return {Roo.Element} this
7923          */
7924          setHeight : function(height, animate){
7925             height = this.adjustHeight(height);
7926             if(!animate || !A){
7927                 this.dom.style.height = this.addUnits(height);
7928             }else{
7929                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7930             }
7931             return this;
7932         },
7933
7934         /**
7935          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7936          * @param {Number} width The new width
7937          * @param {Number} height The new height
7938          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7939          * @return {Roo.Element} this
7940          */
7941          setSize : function(width, height, animate){
7942             if(typeof width == "object"){ // in case of object from getSize()
7943                 height = width.height; width = width.width;
7944             }
7945             width = this.adjustWidth(width); height = this.adjustHeight(height);
7946             if(!animate || !A){
7947                 this.dom.style.width = this.addUnits(width);
7948                 this.dom.style.height = this.addUnits(height);
7949             }else{
7950                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7951             }
7952             return this;
7953         },
7954
7955         /**
7956          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7957          * @param {Number} x X value for new position (coordinates are page-based)
7958          * @param {Number} y Y value for new position (coordinates are page-based)
7959          * @param {Number} width The new width
7960          * @param {Number} height The new height
7961          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7962          * @return {Roo.Element} this
7963          */
7964         setBounds : function(x, y, width, height, animate){
7965             if(!animate || !A){
7966                 this.setSize(width, height);
7967                 this.setLocation(x, y);
7968             }else{
7969                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7970                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7971                               this.preanim(arguments, 4), 'motion');
7972             }
7973             return this;
7974         },
7975
7976         /**
7977          * 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.
7978          * @param {Roo.lib.Region} region The region to fill
7979          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7980          * @return {Roo.Element} this
7981          */
7982         setRegion : function(region, animate){
7983             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7984             return this;
7985         },
7986
7987         /**
7988          * Appends an event handler
7989          *
7990          * @param {String}   eventName     The type of event to append
7991          * @param {Function} fn        The method the event invokes
7992          * @param {Object} scope       (optional) The scope (this object) of the fn
7993          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7994          */
7995         addListener : function(eventName, fn, scope, options){
7996             if (this.dom) {
7997                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7998             }
7999         },
8000
8001         /**
8002          * Removes an event handler from this element
8003          * @param {String} eventName the type of event to remove
8004          * @param {Function} fn the method the event invokes
8005          * @return {Roo.Element} this
8006          */
8007         removeListener : function(eventName, fn){
8008             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8009             return this;
8010         },
8011
8012         /**
8013          * Removes all previous added listeners from this element
8014          * @return {Roo.Element} this
8015          */
8016         removeAllListeners : function(){
8017             E.purgeElement(this.dom);
8018             return this;
8019         },
8020
8021         relayEvent : function(eventName, observable){
8022             this.on(eventName, function(e){
8023                 observable.fireEvent(eventName, e);
8024             });
8025         },
8026
8027         /**
8028          * Set the opacity of the element
8029          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8030          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8031          * @return {Roo.Element} this
8032          */
8033          setOpacity : function(opacity, animate){
8034             if(!animate || !A){
8035                 var s = this.dom.style;
8036                 if(Roo.isIE){
8037                     s.zoom = 1;
8038                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8039                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8040                 }else{
8041                     s.opacity = opacity;
8042                 }
8043             }else{
8044                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8045             }
8046             return this;
8047         },
8048
8049         /**
8050          * Gets the left X coordinate
8051          * @param {Boolean} local True to get the local css position instead of page coordinate
8052          * @return {Number}
8053          */
8054         getLeft : function(local){
8055             if(!local){
8056                 return this.getX();
8057             }else{
8058                 return parseInt(this.getStyle("left"), 10) || 0;
8059             }
8060         },
8061
8062         /**
8063          * Gets the right X coordinate of the element (element X position + element width)
8064          * @param {Boolean} local True to get the local css position instead of page coordinate
8065          * @return {Number}
8066          */
8067         getRight : function(local){
8068             if(!local){
8069                 return this.getX() + this.getWidth();
8070             }else{
8071                 return (this.getLeft(true) + this.getWidth()) || 0;
8072             }
8073         },
8074
8075         /**
8076          * Gets the top Y coordinate
8077          * @param {Boolean} local True to get the local css position instead of page coordinate
8078          * @return {Number}
8079          */
8080         getTop : function(local) {
8081             if(!local){
8082                 return this.getY();
8083             }else{
8084                 return parseInt(this.getStyle("top"), 10) || 0;
8085             }
8086         },
8087
8088         /**
8089          * Gets the bottom Y coordinate of the element (element Y position + element height)
8090          * @param {Boolean} local True to get the local css position instead of page coordinate
8091          * @return {Number}
8092          */
8093         getBottom : function(local){
8094             if(!local){
8095                 return this.getY() + this.getHeight();
8096             }else{
8097                 return (this.getTop(true) + this.getHeight()) || 0;
8098             }
8099         },
8100
8101         /**
8102         * Initializes positioning on this element. If a desired position is not passed, it will make the
8103         * the element positioned relative IF it is not already positioned.
8104         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8105         * @param {Number} zIndex (optional) The zIndex to apply
8106         * @param {Number} x (optional) Set the page X position
8107         * @param {Number} y (optional) Set the page Y position
8108         */
8109         position : function(pos, zIndex, x, y){
8110             if(!pos){
8111                if(this.getStyle('position') == 'static'){
8112                    this.setStyle('position', 'relative');
8113                }
8114             }else{
8115                 this.setStyle("position", pos);
8116             }
8117             if(zIndex){
8118                 this.setStyle("z-index", zIndex);
8119             }
8120             if(x !== undefined && y !== undefined){
8121                 this.setXY([x, y]);
8122             }else if(x !== undefined){
8123                 this.setX(x);
8124             }else if(y !== undefined){
8125                 this.setY(y);
8126             }
8127         },
8128
8129         /**
8130         * Clear positioning back to the default when the document was loaded
8131         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8132         * @return {Roo.Element} this
8133          */
8134         clearPositioning : function(value){
8135             value = value ||'';
8136             this.setStyle({
8137                 "left": value,
8138                 "right": value,
8139                 "top": value,
8140                 "bottom": value,
8141                 "z-index": "",
8142                 "position" : "static"
8143             });
8144             return this;
8145         },
8146
8147         /**
8148         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8149         * snapshot before performing an update and then restoring the element.
8150         * @return {Object}
8151         */
8152         getPositioning : function(){
8153             var l = this.getStyle("left");
8154             var t = this.getStyle("top");
8155             return {
8156                 "position" : this.getStyle("position"),
8157                 "left" : l,
8158                 "right" : l ? "" : this.getStyle("right"),
8159                 "top" : t,
8160                 "bottom" : t ? "" : this.getStyle("bottom"),
8161                 "z-index" : this.getStyle("z-index")
8162             };
8163         },
8164
8165         /**
8166          * Gets the width of the border(s) for the specified side(s)
8167          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8168          * passing lr would get the border (l)eft width + the border (r)ight width.
8169          * @return {Number} The width of the sides passed added together
8170          */
8171         getBorderWidth : function(side){
8172             return this.addStyles(side, El.borders);
8173         },
8174
8175         /**
8176          * Gets the width of the padding(s) for the specified side(s)
8177          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8178          * passing lr would get the padding (l)eft + the padding (r)ight.
8179          * @return {Number} The padding of the sides passed added together
8180          */
8181         getPadding : function(side){
8182             return this.addStyles(side, El.paddings);
8183         },
8184
8185         /**
8186         * Set positioning with an object returned by getPositioning().
8187         * @param {Object} posCfg
8188         * @return {Roo.Element} this
8189          */
8190         setPositioning : function(pc){
8191             this.applyStyles(pc);
8192             if(pc.right == "auto"){
8193                 this.dom.style.right = "";
8194             }
8195             if(pc.bottom == "auto"){
8196                 this.dom.style.bottom = "";
8197             }
8198             return this;
8199         },
8200
8201         // private
8202         fixDisplay : function(){
8203             if(this.getStyle("display") == "none"){
8204                 this.setStyle("visibility", "hidden");
8205                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8206                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8207                     this.setStyle("display", "block");
8208                 }
8209             }
8210         },
8211
8212         /**
8213          * Quick set left and top adding default units
8214          * @param {String} left The left CSS property value
8215          * @param {String} top The top CSS property value
8216          * @return {Roo.Element} this
8217          */
8218          setLeftTop : function(left, top){
8219             this.dom.style.left = this.addUnits(left);
8220             this.dom.style.top = this.addUnits(top);
8221             return this;
8222         },
8223
8224         /**
8225          * Move this element relative to its current position.
8226          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8227          * @param {Number} distance How far to move the element in pixels
8228          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8229          * @return {Roo.Element} this
8230          */
8231          move : function(direction, distance, animate){
8232             var xy = this.getXY();
8233             direction = direction.toLowerCase();
8234             switch(direction){
8235                 case "l":
8236                 case "left":
8237                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8238                     break;
8239                case "r":
8240                case "right":
8241                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8242                     break;
8243                case "t":
8244                case "top":
8245                case "up":
8246                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8247                     break;
8248                case "b":
8249                case "bottom":
8250                case "down":
8251                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8252                     break;
8253             }
8254             return this;
8255         },
8256
8257         /**
8258          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8259          * @return {Roo.Element} this
8260          */
8261         clip : function(){
8262             if(!this.isClipped){
8263                this.isClipped = true;
8264                this.originalClip = {
8265                    "o": this.getStyle("overflow"),
8266                    "x": this.getStyle("overflow-x"),
8267                    "y": this.getStyle("overflow-y")
8268                };
8269                this.setStyle("overflow", "hidden");
8270                this.setStyle("overflow-x", "hidden");
8271                this.setStyle("overflow-y", "hidden");
8272             }
8273             return this;
8274         },
8275
8276         /**
8277          *  Return clipping (overflow) to original clipping before clip() was called
8278          * @return {Roo.Element} this
8279          */
8280         unclip : function(){
8281             if(this.isClipped){
8282                 this.isClipped = false;
8283                 var o = this.originalClip;
8284                 if(o.o){this.setStyle("overflow", o.o);}
8285                 if(o.x){this.setStyle("overflow-x", o.x);}
8286                 if(o.y){this.setStyle("overflow-y", o.y);}
8287             }
8288             return this;
8289         },
8290
8291
8292         /**
8293          * Gets the x,y coordinates specified by the anchor position on the element.
8294          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8295          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8296          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8297          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8298          * @return {Array} [x, y] An array containing the element's x and y coordinates
8299          */
8300         getAnchorXY : function(anchor, local, s){
8301             //Passing a different size is useful for pre-calculating anchors,
8302             //especially for anchored animations that change the el size.
8303
8304             var w, h, vp = false;
8305             if(!s){
8306                 var d = this.dom;
8307                 if(d == document.body || d == document){
8308                     vp = true;
8309                     w = D.getViewWidth(); h = D.getViewHeight();
8310                 }else{
8311                     w = this.getWidth(); h = this.getHeight();
8312                 }
8313             }else{
8314                 w = s.width;  h = s.height;
8315             }
8316             var x = 0, y = 0, r = Math.round;
8317             switch((anchor || "tl").toLowerCase()){
8318                 case "c":
8319                     x = r(w*.5);
8320                     y = r(h*.5);
8321                 break;
8322                 case "t":
8323                     x = r(w*.5);
8324                     y = 0;
8325                 break;
8326                 case "l":
8327                     x = 0;
8328                     y = r(h*.5);
8329                 break;
8330                 case "r":
8331                     x = w;
8332                     y = r(h*.5);
8333                 break;
8334                 case "b":
8335                     x = r(w*.5);
8336                     y = h;
8337                 break;
8338                 case "tl":
8339                     x = 0;
8340                     y = 0;
8341                 break;
8342                 case "bl":
8343                     x = 0;
8344                     y = h;
8345                 break;
8346                 case "br":
8347                     x = w;
8348                     y = h;
8349                 break;
8350                 case "tr":
8351                     x = w;
8352                     y = 0;
8353                 break;
8354             }
8355             if(local === true){
8356                 return [x, y];
8357             }
8358             if(vp){
8359                 var sc = this.getScroll();
8360                 return [x + sc.left, y + sc.top];
8361             }
8362             //Add the element's offset xy
8363             var o = this.getXY();
8364             return [x+o[0], y+o[1]];
8365         },
8366
8367         /**
8368          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8369          * supported position values.
8370          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8371          * @param {String} position The position to align to.
8372          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8373          * @return {Array} [x, y]
8374          */
8375         getAlignToXY : function(el, p, o){
8376             el = Roo.get(el);
8377             var d = this.dom;
8378             if(!el.dom){
8379                 throw "Element.alignTo with an element that doesn't exist";
8380             }
8381             var c = false; //constrain to viewport
8382             var p1 = "", p2 = "";
8383             o = o || [0,0];
8384
8385             if(!p){
8386                 p = "tl-bl";
8387             }else if(p == "?"){
8388                 p = "tl-bl?";
8389             }else if(p.indexOf("-") == -1){
8390                 p = "tl-" + p;
8391             }
8392             p = p.toLowerCase();
8393             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8394             if(!m){
8395                throw "Element.alignTo with an invalid alignment " + p;
8396             }
8397             p1 = m[1]; p2 = m[2]; c = !!m[3];
8398
8399             //Subtract the aligned el's internal xy from the target's offset xy
8400             //plus custom offset to get the aligned el's new offset xy
8401             var a1 = this.getAnchorXY(p1, true);
8402             var a2 = el.getAnchorXY(p2, false);
8403             var x = a2[0] - a1[0] + o[0];
8404             var y = a2[1] - a1[1] + o[1];
8405             if(c){
8406                 //constrain the aligned el to viewport if necessary
8407                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8408                 // 5px of margin for ie
8409                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8410
8411                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8412                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8413                 //otherwise swap the aligned el to the opposite border of the target.
8414                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8415                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8416                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8417                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8418
8419                var doc = document;
8420                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8421                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8422
8423                if((x+w) > dw + scrollX){
8424                     x = swapX ? r.left-w : dw+scrollX-w;
8425                 }
8426                if(x < scrollX){
8427                    x = swapX ? r.right : scrollX;
8428                }
8429                if((y+h) > dh + scrollY){
8430                     y = swapY ? r.top-h : dh+scrollY-h;
8431                 }
8432                if (y < scrollY){
8433                    y = swapY ? r.bottom : scrollY;
8434                }
8435             }
8436             return [x,y];
8437         },
8438
8439         // private
8440         getConstrainToXY : function(){
8441             var os = {top:0, left:0, bottom:0, right: 0};
8442
8443             return function(el, local, offsets, proposedXY){
8444                 el = Roo.get(el);
8445                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8446
8447                 var vw, vh, vx = 0, vy = 0;
8448                 if(el.dom == document.body || el.dom == document){
8449                     vw = Roo.lib.Dom.getViewWidth();
8450                     vh = Roo.lib.Dom.getViewHeight();
8451                 }else{
8452                     vw = el.dom.clientWidth;
8453                     vh = el.dom.clientHeight;
8454                     if(!local){
8455                         var vxy = el.getXY();
8456                         vx = vxy[0];
8457                         vy = vxy[1];
8458                     }
8459                 }
8460
8461                 var s = el.getScroll();
8462
8463                 vx += offsets.left + s.left;
8464                 vy += offsets.top + s.top;
8465
8466                 vw -= offsets.right;
8467                 vh -= offsets.bottom;
8468
8469                 var vr = vx+vw;
8470                 var vb = vy+vh;
8471
8472                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8473                 var x = xy[0], y = xy[1];
8474                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8475
8476                 // only move it if it needs it
8477                 var moved = false;
8478
8479                 // first validate right/bottom
8480                 if((x + w) > vr){
8481                     x = vr - w;
8482                     moved = true;
8483                 }
8484                 if((y + h) > vb){
8485                     y = vb - h;
8486                     moved = true;
8487                 }
8488                 // then make sure top/left isn't negative
8489                 if(x < vx){
8490                     x = vx;
8491                     moved = true;
8492                 }
8493                 if(y < vy){
8494                     y = vy;
8495                     moved = true;
8496                 }
8497                 return moved ? [x, y] : false;
8498             };
8499         }(),
8500
8501         // private
8502         adjustForConstraints : function(xy, parent, offsets){
8503             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8504         },
8505
8506         /**
8507          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8508          * document it aligns it to the viewport.
8509          * The position parameter is optional, and can be specified in any one of the following formats:
8510          * <ul>
8511          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8512          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8513          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8514          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8515          *   <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
8516          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8517          * </ul>
8518          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8519          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8520          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8521          * that specified in order to enforce the viewport constraints.
8522          * Following are all of the supported anchor positions:
8523     <pre>
8524     Value  Description
8525     -----  -----------------------------
8526     tl     The top left corner (default)
8527     t      The center of the top edge
8528     tr     The top right corner
8529     l      The center of the left edge
8530     c      In the center of the element
8531     r      The center of the right edge
8532     bl     The bottom left corner
8533     b      The center of the bottom edge
8534     br     The bottom right corner
8535     </pre>
8536     Example Usage:
8537     <pre><code>
8538     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8539     el.alignTo("other-el");
8540
8541     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8542     el.alignTo("other-el", "tr?");
8543
8544     // align the bottom right corner of el with the center left edge of other-el
8545     el.alignTo("other-el", "br-l?");
8546
8547     // align the center of el with the bottom left corner of other-el and
8548     // adjust the x position by -6 pixels (and the y position by 0)
8549     el.alignTo("other-el", "c-bl", [-6, 0]);
8550     </code></pre>
8551          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8552          * @param {String} position The position to align to.
8553          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8554          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8555          * @return {Roo.Element} this
8556          */
8557         alignTo : function(element, position, offsets, animate){
8558             var xy = this.getAlignToXY(element, position, offsets);
8559             this.setXY(xy, this.preanim(arguments, 3));
8560             return this;
8561         },
8562
8563         /**
8564          * Anchors an element to another element and realigns it when the window is resized.
8565          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8566          * @param {String} position The position to align to.
8567          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8568          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8569          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8570          * is a number, it is used as the buffer delay (defaults to 50ms).
8571          * @param {Function} callback The function to call after the animation finishes
8572          * @return {Roo.Element} this
8573          */
8574         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8575             var action = function(){
8576                 this.alignTo(el, alignment, offsets, animate);
8577                 Roo.callback(callback, this);
8578             };
8579             Roo.EventManager.onWindowResize(action, this);
8580             var tm = typeof monitorScroll;
8581             if(tm != 'undefined'){
8582                 Roo.EventManager.on(window, 'scroll', action, this,
8583                     {buffer: tm == 'number' ? monitorScroll : 50});
8584             }
8585             action.call(this); // align immediately
8586             return this;
8587         },
8588         /**
8589          * Clears any opacity settings from this element. Required in some cases for IE.
8590          * @return {Roo.Element} this
8591          */
8592         clearOpacity : function(){
8593             if (window.ActiveXObject) {
8594                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8595                     this.dom.style.filter = "";
8596                 }
8597             } else {
8598                 this.dom.style.opacity = "";
8599                 this.dom.style["-moz-opacity"] = "";
8600                 this.dom.style["-khtml-opacity"] = "";
8601             }
8602             return this;
8603         },
8604
8605         /**
8606          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8607          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8608          * @return {Roo.Element} this
8609          */
8610         hide : function(animate){
8611             this.setVisible(false, this.preanim(arguments, 0));
8612             return this;
8613         },
8614
8615         /**
8616         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8617         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8618          * @return {Roo.Element} this
8619          */
8620         show : function(animate){
8621             this.setVisible(true, this.preanim(arguments, 0));
8622             return this;
8623         },
8624
8625         /**
8626          * @private Test if size has a unit, otherwise appends the default
8627          */
8628         addUnits : function(size){
8629             return Roo.Element.addUnits(size, this.defaultUnit);
8630         },
8631
8632         /**
8633          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8634          * @return {Roo.Element} this
8635          */
8636         beginMeasure : function(){
8637             var el = this.dom;
8638             if(el.offsetWidth || el.offsetHeight){
8639                 return this; // offsets work already
8640             }
8641             var changed = [];
8642             var p = this.dom, b = document.body; // start with this element
8643             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8644                 var pe = Roo.get(p);
8645                 if(pe.getStyle('display') == 'none'){
8646                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8647                     p.style.visibility = "hidden";
8648                     p.style.display = "block";
8649                 }
8650                 p = p.parentNode;
8651             }
8652             this._measureChanged = changed;
8653             return this;
8654
8655         },
8656
8657         /**
8658          * Restores displays to before beginMeasure was called
8659          * @return {Roo.Element} this
8660          */
8661         endMeasure : function(){
8662             var changed = this._measureChanged;
8663             if(changed){
8664                 for(var i = 0, len = changed.length; i < len; i++) {
8665                     var r = changed[i];
8666                     r.el.style.visibility = r.visibility;
8667                     r.el.style.display = "none";
8668                 }
8669                 this._measureChanged = null;
8670             }
8671             return this;
8672         },
8673
8674         /**
8675         * Update the innerHTML of this element, optionally searching for and processing scripts
8676         * @param {String} html The new HTML
8677         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8678         * @param {Function} callback For async script loading you can be noticed when the update completes
8679         * @return {Roo.Element} this
8680          */
8681         update : function(html, loadScripts, callback){
8682             if(typeof html == "undefined"){
8683                 html = "";
8684             }
8685             if(loadScripts !== true){
8686                 this.dom.innerHTML = html;
8687                 if(typeof callback == "function"){
8688                     callback();
8689                 }
8690                 return this;
8691             }
8692             var id = Roo.id();
8693             var dom = this.dom;
8694
8695             html += '<span id="' + id + '"></span>';
8696
8697             E.onAvailable(id, function(){
8698                 var hd = document.getElementsByTagName("head")[0];
8699                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8700                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8701                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8702
8703                 var match;
8704                 while(match = re.exec(html)){
8705                     var attrs = match[1];
8706                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8707                     if(srcMatch && srcMatch[2]){
8708                        var s = document.createElement("script");
8709                        s.src = srcMatch[2];
8710                        var typeMatch = attrs.match(typeRe);
8711                        if(typeMatch && typeMatch[2]){
8712                            s.type = typeMatch[2];
8713                        }
8714                        hd.appendChild(s);
8715                     }else if(match[2] && match[2].length > 0){
8716                         if(window.execScript) {
8717                            window.execScript(match[2]);
8718                         } else {
8719                             /**
8720                              * eval:var:id
8721                              * eval:var:dom
8722                              * eval:var:html
8723                              * 
8724                              */
8725                            window.eval(match[2]);
8726                         }
8727                     }
8728                 }
8729                 var el = document.getElementById(id);
8730                 if(el){el.parentNode.removeChild(el);}
8731                 if(typeof callback == "function"){
8732                     callback();
8733                 }
8734             });
8735             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8736             return this;
8737         },
8738
8739         /**
8740          * Direct access to the UpdateManager update() method (takes the same parameters).
8741          * @param {String/Function} url The url for this request or a function to call to get the url
8742          * @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}
8743          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8744          * @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.
8745          * @return {Roo.Element} this
8746          */
8747         load : function(){
8748             var um = this.getUpdateManager();
8749             um.update.apply(um, arguments);
8750             return this;
8751         },
8752
8753         /**
8754         * Gets this element's UpdateManager
8755         * @return {Roo.UpdateManager} The UpdateManager
8756         */
8757         getUpdateManager : function(){
8758             if(!this.updateManager){
8759                 this.updateManager = new Roo.UpdateManager(this);
8760             }
8761             return this.updateManager;
8762         },
8763
8764         /**
8765          * Disables text selection for this element (normalized across browsers)
8766          * @return {Roo.Element} this
8767          */
8768         unselectable : function(){
8769             this.dom.unselectable = "on";
8770             this.swallowEvent("selectstart", true);
8771             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8772             this.addClass("x-unselectable");
8773             return this;
8774         },
8775
8776         /**
8777         * Calculates the x, y to center this element on the screen
8778         * @return {Array} The x, y values [x, y]
8779         */
8780         getCenterXY : function(){
8781             return this.getAlignToXY(document, 'c-c');
8782         },
8783
8784         /**
8785         * Centers the Element in either the viewport, or another Element.
8786         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8787         */
8788         center : function(centerIn){
8789             this.alignTo(centerIn || document, 'c-c');
8790             return this;
8791         },
8792
8793         /**
8794          * Tests various css rules/browsers to determine if this element uses a border box
8795          * @return {Boolean}
8796          */
8797         isBorderBox : function(){
8798             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8799         },
8800
8801         /**
8802          * Return a box {x, y, width, height} that can be used to set another elements
8803          * size/location to match this element.
8804          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8805          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8806          * @return {Object} box An object in the format {x, y, width, height}
8807          */
8808         getBox : function(contentBox, local){
8809             var xy;
8810             if(!local){
8811                 xy = this.getXY();
8812             }else{
8813                 var left = parseInt(this.getStyle("left"), 10) || 0;
8814                 var top = parseInt(this.getStyle("top"), 10) || 0;
8815                 xy = [left, top];
8816             }
8817             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8818             if(!contentBox){
8819                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8820             }else{
8821                 var l = this.getBorderWidth("l")+this.getPadding("l");
8822                 var r = this.getBorderWidth("r")+this.getPadding("r");
8823                 var t = this.getBorderWidth("t")+this.getPadding("t");
8824                 var b = this.getBorderWidth("b")+this.getPadding("b");
8825                 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)};
8826             }
8827             bx.right = bx.x + bx.width;
8828             bx.bottom = bx.y + bx.height;
8829             return bx;
8830         },
8831
8832         /**
8833          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8834          for more information about the sides.
8835          * @param {String} sides
8836          * @return {Number}
8837          */
8838         getFrameWidth : function(sides, onlyContentBox){
8839             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8840         },
8841
8842         /**
8843          * 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.
8844          * @param {Object} box The box to fill {x, y, width, height}
8845          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8846          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8847          * @return {Roo.Element} this
8848          */
8849         setBox : function(box, adjust, animate){
8850             var w = box.width, h = box.height;
8851             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8852                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8853                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8854             }
8855             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8856             return this;
8857         },
8858
8859         /**
8860          * Forces the browser to repaint this element
8861          * @return {Roo.Element} this
8862          */
8863          repaint : function(){
8864             var dom = this.dom;
8865             this.addClass("x-repaint");
8866             setTimeout(function(){
8867                 Roo.get(dom).removeClass("x-repaint");
8868             }, 1);
8869             return this;
8870         },
8871
8872         /**
8873          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8874          * then it returns the calculated width of the sides (see getPadding)
8875          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8876          * @return {Object/Number}
8877          */
8878         getMargins : function(side){
8879             if(!side){
8880                 return {
8881                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8882                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8883                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8884                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8885                 };
8886             }else{
8887                 return this.addStyles(side, El.margins);
8888              }
8889         },
8890
8891         // private
8892         addStyles : function(sides, styles){
8893             var val = 0, v, w;
8894             for(var i = 0, len = sides.length; i < len; i++){
8895                 v = this.getStyle(styles[sides.charAt(i)]);
8896                 if(v){
8897                      w = parseInt(v, 10);
8898                      if(w){ val += w; }
8899                 }
8900             }
8901             return val;
8902         },
8903
8904         /**
8905          * Creates a proxy element of this element
8906          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8907          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8908          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8909          * @return {Roo.Element} The new proxy element
8910          */
8911         createProxy : function(config, renderTo, matchBox){
8912             if(renderTo){
8913                 renderTo = Roo.getDom(renderTo);
8914             }else{
8915                 renderTo = document.body;
8916             }
8917             config = typeof config == "object" ?
8918                 config : {tag : "div", cls: config};
8919             var proxy = Roo.DomHelper.append(renderTo, config, true);
8920             if(matchBox){
8921                proxy.setBox(this.getBox());
8922             }
8923             return proxy;
8924         },
8925
8926         /**
8927          * Puts a mask over this element to disable user interaction. Requires core.css.
8928          * This method can only be applied to elements which accept child nodes.
8929          * @param {String} msg (optional) A message to display in the mask
8930          * @param {String} msgCls (optional) A css class to apply to the msg element
8931          * @return {Element} The mask  element
8932          */
8933         mask : function(msg, msgCls)
8934         {
8935             if(this.getStyle("position") == "static"){
8936                 this.setStyle("position", "relative");
8937             }
8938             if(!this._mask){
8939                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8940             }
8941             this.addClass("x-masked");
8942             this._mask.setDisplayed(true);
8943             
8944             // we wander
8945             var z = 0;
8946             var dom = this.dom
8947             while (dom && dom.style) {
8948                 if (!isNaN(parseInt(dom.style.zIndex))) {
8949                     z = Math.max(z, parseInt(dom.style.zIndex));
8950                 }
8951                 dom = dom.parentNode;
8952             }
8953             // if we are masking the body - then it hides everything..
8954             if (this.dom == document.body) {
8955                 z = 1000000;
8956                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8957                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8958             }
8959            
8960             if(typeof msg == 'string'){
8961                 if(!this._maskMsg){
8962                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8963                 }
8964                 var mm = this._maskMsg;
8965                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8966                 mm.dom.firstChild.innerHTML = msg;
8967                 mm.setDisplayed(true);
8968                 mm.center(this);
8969                 mm.setStyle('z-index', z + 102);
8970             }
8971             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8972                 this._mask.setHeight(this.getHeight());
8973             }
8974             this._mask.setStyle('z-index', z + 100);
8975             
8976             return this._mask;
8977         },
8978
8979         /**
8980          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8981          * it is cached for reuse.
8982          */
8983         unmask : function(removeEl){
8984             if(this._mask){
8985                 if(removeEl === true){
8986                     this._mask.remove();
8987                     delete this._mask;
8988                     if(this._maskMsg){
8989                         this._maskMsg.remove();
8990                         delete this._maskMsg;
8991                     }
8992                 }else{
8993                     this._mask.setDisplayed(false);
8994                     if(this._maskMsg){
8995                         this._maskMsg.setDisplayed(false);
8996                     }
8997                 }
8998             }
8999             this.removeClass("x-masked");
9000         },
9001
9002         /**
9003          * Returns true if this element is masked
9004          * @return {Boolean}
9005          */
9006         isMasked : function(){
9007             return this._mask && this._mask.isVisible();
9008         },
9009
9010         /**
9011          * Creates an iframe shim for this element to keep selects and other windowed objects from
9012          * showing through.
9013          * @return {Roo.Element} The new shim element
9014          */
9015         createShim : function(){
9016             var el = document.createElement('iframe');
9017             el.frameBorder = 'no';
9018             el.className = 'roo-shim';
9019             if(Roo.isIE && Roo.isSecure){
9020                 el.src = Roo.SSL_SECURE_URL;
9021             }
9022             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9023             shim.autoBoxAdjust = false;
9024             return shim;
9025         },
9026
9027         /**
9028          * Removes this element from the DOM and deletes it from the cache
9029          */
9030         remove : function(){
9031             if(this.dom.parentNode){
9032                 this.dom.parentNode.removeChild(this.dom);
9033             }
9034             delete El.cache[this.dom.id];
9035         },
9036
9037         /**
9038          * Sets up event handlers to add and remove a css class when the mouse is over this element
9039          * @param {String} className
9040          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9041          * mouseout events for children elements
9042          * @return {Roo.Element} this
9043          */
9044         addClassOnOver : function(className, preventFlicker){
9045             this.on("mouseover", function(){
9046                 Roo.fly(this, '_internal').addClass(className);
9047             }, this.dom);
9048             var removeFn = function(e){
9049                 if(preventFlicker !== true || !e.within(this, true)){
9050                     Roo.fly(this, '_internal').removeClass(className);
9051                 }
9052             };
9053             this.on("mouseout", removeFn, this.dom);
9054             return this;
9055         },
9056
9057         /**
9058          * Sets up event handlers to add and remove a css class when this element has the focus
9059          * @param {String} className
9060          * @return {Roo.Element} this
9061          */
9062         addClassOnFocus : function(className){
9063             this.on("focus", function(){
9064                 Roo.fly(this, '_internal').addClass(className);
9065             }, this.dom);
9066             this.on("blur", function(){
9067                 Roo.fly(this, '_internal').removeClass(className);
9068             }, this.dom);
9069             return this;
9070         },
9071         /**
9072          * 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)
9073          * @param {String} className
9074          * @return {Roo.Element} this
9075          */
9076         addClassOnClick : function(className){
9077             var dom = this.dom;
9078             this.on("mousedown", function(){
9079                 Roo.fly(dom, '_internal').addClass(className);
9080                 var d = Roo.get(document);
9081                 var fn = function(){
9082                     Roo.fly(dom, '_internal').removeClass(className);
9083                     d.removeListener("mouseup", fn);
9084                 };
9085                 d.on("mouseup", fn);
9086             });
9087             return this;
9088         },
9089
9090         /**
9091          * Stops the specified event from bubbling and optionally prevents the default action
9092          * @param {String} eventName
9093          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9094          * @return {Roo.Element} this
9095          */
9096         swallowEvent : function(eventName, preventDefault){
9097             var fn = function(e){
9098                 e.stopPropagation();
9099                 if(preventDefault){
9100                     e.preventDefault();
9101                 }
9102             };
9103             if(eventName instanceof Array){
9104                 for(var i = 0, len = eventName.length; i < len; i++){
9105                      this.on(eventName[i], fn);
9106                 }
9107                 return this;
9108             }
9109             this.on(eventName, fn);
9110             return this;
9111         },
9112
9113         /**
9114          * @private
9115          */
9116       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9117
9118         /**
9119          * Sizes this element to its parent element's dimensions performing
9120          * neccessary box adjustments.
9121          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9122          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9123          * @return {Roo.Element} this
9124          */
9125         fitToParent : function(monitorResize, targetParent) {
9126           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9127           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9128           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9129             return;
9130           }
9131           var p = Roo.get(targetParent || this.dom.parentNode);
9132           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9133           if (monitorResize === true) {
9134             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9135             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9136           }
9137           return this;
9138         },
9139
9140         /**
9141          * Gets the next sibling, skipping text nodes
9142          * @return {HTMLElement} The next sibling or null
9143          */
9144         getNextSibling : function(){
9145             var n = this.dom.nextSibling;
9146             while(n && n.nodeType != 1){
9147                 n = n.nextSibling;
9148             }
9149             return n;
9150         },
9151
9152         /**
9153          * Gets the previous sibling, skipping text nodes
9154          * @return {HTMLElement} The previous sibling or null
9155          */
9156         getPrevSibling : function(){
9157             var n = this.dom.previousSibling;
9158             while(n && n.nodeType != 1){
9159                 n = n.previousSibling;
9160             }
9161             return n;
9162         },
9163
9164
9165         /**
9166          * Appends the passed element(s) to this element
9167          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9168          * @return {Roo.Element} this
9169          */
9170         appendChild: function(el){
9171             el = Roo.get(el);
9172             el.appendTo(this);
9173             return this;
9174         },
9175
9176         /**
9177          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9178          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9179          * automatically generated with the specified attributes.
9180          * @param {HTMLElement} insertBefore (optional) a child element of this element
9181          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9182          * @return {Roo.Element} The new child element
9183          */
9184         createChild: function(config, insertBefore, returnDom){
9185             config = config || {tag:'div'};
9186             if(insertBefore){
9187                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9188             }
9189             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9190         },
9191
9192         /**
9193          * Appends this element to the passed element
9194          * @param {String/HTMLElement/Element} el The new parent element
9195          * @return {Roo.Element} this
9196          */
9197         appendTo: function(el){
9198             el = Roo.getDom(el);
9199             el.appendChild(this.dom);
9200             return this;
9201         },
9202
9203         /**
9204          * Inserts this element before the passed element in the DOM
9205          * @param {String/HTMLElement/Element} el The element to insert before
9206          * @return {Roo.Element} this
9207          */
9208         insertBefore: function(el){
9209             el = Roo.getDom(el);
9210             el.parentNode.insertBefore(this.dom, el);
9211             return this;
9212         },
9213
9214         /**
9215          * Inserts this element after the passed element in the DOM
9216          * @param {String/HTMLElement/Element} el The element to insert after
9217          * @return {Roo.Element} this
9218          */
9219         insertAfter: function(el){
9220             el = Roo.getDom(el);
9221             el.parentNode.insertBefore(this.dom, el.nextSibling);
9222             return this;
9223         },
9224
9225         /**
9226          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9227          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9228          * @return {Roo.Element} The new child
9229          */
9230         insertFirst: function(el, returnDom){
9231             el = el || {};
9232             if(typeof el == 'object' && !el.nodeType){ // dh config
9233                 return this.createChild(el, this.dom.firstChild, returnDom);
9234             }else{
9235                 el = Roo.getDom(el);
9236                 this.dom.insertBefore(el, this.dom.firstChild);
9237                 return !returnDom ? Roo.get(el) : el;
9238             }
9239         },
9240
9241         /**
9242          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9243          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9244          * @param {String} where (optional) 'before' or 'after' defaults to before
9245          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9246          * @return {Roo.Element} the inserted Element
9247          */
9248         insertSibling: function(el, where, returnDom){
9249             where = where ? where.toLowerCase() : 'before';
9250             el = el || {};
9251             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9252
9253             if(typeof el == 'object' && !el.nodeType){ // dh config
9254                 if(where == 'after' && !this.dom.nextSibling){
9255                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9256                 }else{
9257                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9258                 }
9259
9260             }else{
9261                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9262                             where == 'before' ? this.dom : this.dom.nextSibling);
9263                 if(!returnDom){
9264                     rt = Roo.get(rt);
9265                 }
9266             }
9267             return rt;
9268         },
9269
9270         /**
9271          * Creates and wraps this element with another element
9272          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9273          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9274          * @return {HTMLElement/Element} The newly created wrapper element
9275          */
9276         wrap: function(config, returnDom){
9277             if(!config){
9278                 config = {tag: "div"};
9279             }
9280             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9281             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9282             return newEl;
9283         },
9284
9285         /**
9286          * Replaces the passed element with this element
9287          * @param {String/HTMLElement/Element} el The element to replace
9288          * @return {Roo.Element} this
9289          */
9290         replace: function(el){
9291             el = Roo.get(el);
9292             this.insertBefore(el);
9293             el.remove();
9294             return this;
9295         },
9296
9297         /**
9298          * Inserts an html fragment into this element
9299          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9300          * @param {String} html The HTML fragment
9301          * @param {Boolean} returnEl True to return an Roo.Element
9302          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9303          */
9304         insertHtml : function(where, html, returnEl){
9305             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9306             return returnEl ? Roo.get(el) : el;
9307         },
9308
9309         /**
9310          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9311          * @param {Object} o The object with the attributes
9312          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9313          * @return {Roo.Element} this
9314          */
9315         set : function(o, useSet){
9316             var el = this.dom;
9317             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9318             for(var attr in o){
9319                 if(attr == "style" || typeof o[attr] == "function") continue;
9320                 if(attr=="cls"){
9321                     el.className = o["cls"];
9322                 }else{
9323                     if(useSet) el.setAttribute(attr, o[attr]);
9324                     else el[attr] = o[attr];
9325                 }
9326             }
9327             if(o.style){
9328                 Roo.DomHelper.applyStyles(el, o.style);
9329             }
9330             return this;
9331         },
9332
9333         /**
9334          * Convenience method for constructing a KeyMap
9335          * @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:
9336          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9337          * @param {Function} fn The function to call
9338          * @param {Object} scope (optional) The scope of the function
9339          * @return {Roo.KeyMap} The KeyMap created
9340          */
9341         addKeyListener : function(key, fn, scope){
9342             var config;
9343             if(typeof key != "object" || key instanceof Array){
9344                 config = {
9345                     key: key,
9346                     fn: fn,
9347                     scope: scope
9348                 };
9349             }else{
9350                 config = {
9351                     key : key.key,
9352                     shift : key.shift,
9353                     ctrl : key.ctrl,
9354                     alt : key.alt,
9355                     fn: fn,
9356                     scope: scope
9357                 };
9358             }
9359             return new Roo.KeyMap(this, config);
9360         },
9361
9362         /**
9363          * Creates a KeyMap for this element
9364          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9365          * @return {Roo.KeyMap} The KeyMap created
9366          */
9367         addKeyMap : function(config){
9368             return new Roo.KeyMap(this, config);
9369         },
9370
9371         /**
9372          * Returns true if this element is scrollable.
9373          * @return {Boolean}
9374          */
9375          isScrollable : function(){
9376             var dom = this.dom;
9377             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9378         },
9379
9380         /**
9381          * 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().
9382          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9383          * @param {Number} value The new scroll value
9384          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9385          * @return {Element} this
9386          */
9387
9388         scrollTo : function(side, value, animate){
9389             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9390             if(!animate || !A){
9391                 this.dom[prop] = value;
9392             }else{
9393                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9394                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9395             }
9396             return this;
9397         },
9398
9399         /**
9400          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9401          * within this element's scrollable range.
9402          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9403          * @param {Number} distance How far to scroll the element in pixels
9404          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9405          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9406          * was scrolled as far as it could go.
9407          */
9408          scroll : function(direction, distance, animate){
9409              if(!this.isScrollable()){
9410                  return;
9411              }
9412              var el = this.dom;
9413              var l = el.scrollLeft, t = el.scrollTop;
9414              var w = el.scrollWidth, h = el.scrollHeight;
9415              var cw = el.clientWidth, ch = el.clientHeight;
9416              direction = direction.toLowerCase();
9417              var scrolled = false;
9418              var a = this.preanim(arguments, 2);
9419              switch(direction){
9420                  case "l":
9421                  case "left":
9422                      if(w - l > cw){
9423                          var v = Math.min(l + distance, w-cw);
9424                          this.scrollTo("left", v, a);
9425                          scrolled = true;
9426                      }
9427                      break;
9428                 case "r":
9429                 case "right":
9430                      if(l > 0){
9431                          var v = Math.max(l - distance, 0);
9432                          this.scrollTo("left", v, a);
9433                          scrolled = true;
9434                      }
9435                      break;
9436                 case "t":
9437                 case "top":
9438                 case "up":
9439                      if(t > 0){
9440                          var v = Math.max(t - distance, 0);
9441                          this.scrollTo("top", v, a);
9442                          scrolled = true;
9443                      }
9444                      break;
9445                 case "b":
9446                 case "bottom":
9447                 case "down":
9448                      if(h - t > ch){
9449                          var v = Math.min(t + distance, h-ch);
9450                          this.scrollTo("top", v, a);
9451                          scrolled = true;
9452                      }
9453                      break;
9454              }
9455              return scrolled;
9456         },
9457
9458         /**
9459          * Translates the passed page coordinates into left/top css values for this element
9460          * @param {Number/Array} x The page x or an array containing [x, y]
9461          * @param {Number} y The page y
9462          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9463          */
9464         translatePoints : function(x, y){
9465             if(typeof x == 'object' || x instanceof Array){
9466                 y = x[1]; x = x[0];
9467             }
9468             var p = this.getStyle('position');
9469             var o = this.getXY();
9470
9471             var l = parseInt(this.getStyle('left'), 10);
9472             var t = parseInt(this.getStyle('top'), 10);
9473
9474             if(isNaN(l)){
9475                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9476             }
9477             if(isNaN(t)){
9478                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9479             }
9480
9481             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9482         },
9483
9484         /**
9485          * Returns the current scroll position of the element.
9486          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9487          */
9488         getScroll : function(){
9489             var d = this.dom, doc = document;
9490             if(d == doc || d == doc.body){
9491                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9492                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9493                 return {left: l, top: t};
9494             }else{
9495                 return {left: d.scrollLeft, top: d.scrollTop};
9496             }
9497         },
9498
9499         /**
9500          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9501          * are convert to standard 6 digit hex color.
9502          * @param {String} attr The css attribute
9503          * @param {String} defaultValue The default value to use when a valid color isn't found
9504          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9505          * YUI color anims.
9506          */
9507         getColor : function(attr, defaultValue, prefix){
9508             var v = this.getStyle(attr);
9509             if(!v || v == "transparent" || v == "inherit") {
9510                 return defaultValue;
9511             }
9512             var color = typeof prefix == "undefined" ? "#" : prefix;
9513             if(v.substr(0, 4) == "rgb("){
9514                 var rvs = v.slice(4, v.length -1).split(",");
9515                 for(var i = 0; i < 3; i++){
9516                     var h = parseInt(rvs[i]).toString(16);
9517                     if(h < 16){
9518                         h = "0" + h;
9519                     }
9520                     color += h;
9521                 }
9522             } else {
9523                 if(v.substr(0, 1) == "#"){
9524                     if(v.length == 4) {
9525                         for(var i = 1; i < 4; i++){
9526                             var c = v.charAt(i);
9527                             color +=  c + c;
9528                         }
9529                     }else if(v.length == 7){
9530                         color += v.substr(1);
9531                     }
9532                 }
9533             }
9534             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9535         },
9536
9537         /**
9538          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9539          * gradient background, rounded corners and a 4-way shadow.
9540          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9541          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9542          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9543          * @return {Roo.Element} this
9544          */
9545         boxWrap : function(cls){
9546             cls = cls || 'x-box';
9547             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9548             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9549             return el;
9550         },
9551
9552         /**
9553          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9554          * @param {String} namespace The namespace in which to look for the attribute
9555          * @param {String} name The attribute name
9556          * @return {String} The attribute value
9557          */
9558         getAttributeNS : Roo.isIE ? function(ns, name){
9559             var d = this.dom;
9560             var type = typeof d[ns+":"+name];
9561             if(type != 'undefined' && type != 'unknown'){
9562                 return d[ns+":"+name];
9563             }
9564             return d[name];
9565         } : function(ns, name){
9566             var d = this.dom;
9567             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9568         },
9569         
9570         
9571         /**
9572          * Sets or Returns the value the dom attribute value
9573          * @param {String} name The attribute name
9574          * @param {String} value (optional) The value to set the attribute to
9575          * @return {String} The attribute value
9576          */
9577         attr : function(name){
9578             if (arguments.length > 1) {
9579                 this.dom.setAttribute(name, arguments[1]);
9580                 return arguments[1];
9581             }
9582             if (!this.dom.hasAttribute(name)) {
9583                 return undefined;
9584             }
9585             return this.dom.getAttribute(name);
9586         }
9587         
9588         
9589         
9590     };
9591
9592     var ep = El.prototype;
9593
9594     /**
9595      * Appends an event handler (Shorthand for addListener)
9596      * @param {String}   eventName     The type of event to append
9597      * @param {Function} fn        The method the event invokes
9598      * @param {Object} scope       (optional) The scope (this object) of the fn
9599      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9600      * @method
9601      */
9602     ep.on = ep.addListener;
9603         // backwards compat
9604     ep.mon = ep.addListener;
9605
9606     /**
9607      * Removes an event handler from this element (shorthand for removeListener)
9608      * @param {String} eventName the type of event to remove
9609      * @param {Function} fn the method the event invokes
9610      * @return {Roo.Element} this
9611      * @method
9612      */
9613     ep.un = ep.removeListener;
9614
9615     /**
9616      * true to automatically adjust width and height settings for box-model issues (default to true)
9617      */
9618     ep.autoBoxAdjust = true;
9619
9620     // private
9621     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9622
9623     // private
9624     El.addUnits = function(v, defaultUnit){
9625         if(v === "" || v == "auto"){
9626             return v;
9627         }
9628         if(v === undefined){
9629             return '';
9630         }
9631         if(typeof v == "number" || !El.unitPattern.test(v)){
9632             return v + (defaultUnit || 'px');
9633         }
9634         return v;
9635     };
9636
9637     // special markup used throughout Roo when box wrapping elements
9638     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>';
9639     /**
9640      * Visibility mode constant - Use visibility to hide element
9641      * @static
9642      * @type Number
9643      */
9644     El.VISIBILITY = 1;
9645     /**
9646      * Visibility mode constant - Use display to hide element
9647      * @static
9648      * @type Number
9649      */
9650     El.DISPLAY = 2;
9651
9652     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9653     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9654     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9655
9656
9657
9658     /**
9659      * @private
9660      */
9661     El.cache = {};
9662
9663     var docEl;
9664
9665     /**
9666      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9667      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9668      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9669      * @return {Element} The Element object
9670      * @static
9671      */
9672     El.get = function(el){
9673         var ex, elm, id;
9674         if(!el){ return null; }
9675         if(typeof el == "string"){ // element id
9676             if(!(elm = document.getElementById(el))){
9677                 return null;
9678             }
9679             if(ex = El.cache[el]){
9680                 ex.dom = elm;
9681             }else{
9682                 ex = El.cache[el] = new El(elm);
9683             }
9684             return ex;
9685         }else if(el.tagName){ // dom element
9686             if(!(id = el.id)){
9687                 id = Roo.id(el);
9688             }
9689             if(ex = El.cache[id]){
9690                 ex.dom = el;
9691             }else{
9692                 ex = El.cache[id] = new El(el);
9693             }
9694             return ex;
9695         }else if(el instanceof El){
9696             if(el != docEl){
9697                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9698                                                               // catch case where it hasn't been appended
9699                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9700             }
9701             return el;
9702         }else if(el.isComposite){
9703             return el;
9704         }else if(el instanceof Array){
9705             return El.select(el);
9706         }else if(el == document){
9707             // create a bogus element object representing the document object
9708             if(!docEl){
9709                 var f = function(){};
9710                 f.prototype = El.prototype;
9711                 docEl = new f();
9712                 docEl.dom = document;
9713             }
9714             return docEl;
9715         }
9716         return null;
9717     };
9718
9719     // private
9720     El.uncache = function(el){
9721         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9722             if(a[i]){
9723                 delete El.cache[a[i].id || a[i]];
9724             }
9725         }
9726     };
9727
9728     // private
9729     // Garbage collection - uncache elements/purge listeners on orphaned elements
9730     // so we don't hold a reference and cause the browser to retain them
9731     El.garbageCollect = function(){
9732         if(!Roo.enableGarbageCollector){
9733             clearInterval(El.collectorThread);
9734             return;
9735         }
9736         for(var eid in El.cache){
9737             var el = El.cache[eid], d = el.dom;
9738             // -------------------------------------------------------
9739             // Determining what is garbage:
9740             // -------------------------------------------------------
9741             // !d
9742             // dom node is null, definitely garbage
9743             // -------------------------------------------------------
9744             // !d.parentNode
9745             // no parentNode == direct orphan, definitely garbage
9746             // -------------------------------------------------------
9747             // !d.offsetParent && !document.getElementById(eid)
9748             // display none elements have no offsetParent so we will
9749             // also try to look it up by it's id. However, check
9750             // offsetParent first so we don't do unneeded lookups.
9751             // This enables collection of elements that are not orphans
9752             // directly, but somewhere up the line they have an orphan
9753             // parent.
9754             // -------------------------------------------------------
9755             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9756                 delete El.cache[eid];
9757                 if(d && Roo.enableListenerCollection){
9758                     E.purgeElement(d);
9759                 }
9760             }
9761         }
9762     }
9763     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9764
9765
9766     // dom is optional
9767     El.Flyweight = function(dom){
9768         this.dom = dom;
9769     };
9770     El.Flyweight.prototype = El.prototype;
9771
9772     El._flyweights = {};
9773     /**
9774      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9775      * the dom node can be overwritten by other code.
9776      * @param {String/HTMLElement} el The dom node or id
9777      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9778      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9779      * @static
9780      * @return {Element} The shared Element object
9781      */
9782     El.fly = function(el, named){
9783         named = named || '_global';
9784         el = Roo.getDom(el);
9785         if(!el){
9786             return null;
9787         }
9788         if(!El._flyweights[named]){
9789             El._flyweights[named] = new El.Flyweight();
9790         }
9791         El._flyweights[named].dom = el;
9792         return El._flyweights[named];
9793     };
9794
9795     /**
9796      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9797      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9798      * Shorthand of {@link Roo.Element#get}
9799      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9800      * @return {Element} The Element object
9801      * @member Roo
9802      * @method get
9803      */
9804     Roo.get = El.get;
9805     /**
9806      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9807      * the dom node can be overwritten by other code.
9808      * Shorthand of {@link Roo.Element#fly}
9809      * @param {String/HTMLElement} el The dom node or id
9810      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9811      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9812      * @static
9813      * @return {Element} The shared Element object
9814      * @member Roo
9815      * @method fly
9816      */
9817     Roo.fly = El.fly;
9818
9819     // speedy lookup for elements never to box adjust
9820     var noBoxAdjust = Roo.isStrict ? {
9821         select:1
9822     } : {
9823         input:1, select:1, textarea:1
9824     };
9825     if(Roo.isIE || Roo.isGecko){
9826         noBoxAdjust['button'] = 1;
9827     }
9828
9829
9830     Roo.EventManager.on(window, 'unload', function(){
9831         delete El.cache;
9832         delete El._flyweights;
9833     });
9834 })();
9835
9836
9837
9838
9839 if(Roo.DomQuery){
9840     Roo.Element.selectorFunction = Roo.DomQuery.select;
9841 }
9842
9843 Roo.Element.select = function(selector, unique, root){
9844     var els;
9845     if(typeof selector == "string"){
9846         els = Roo.Element.selectorFunction(selector, root);
9847     }else if(selector.length !== undefined){
9848         els = selector;
9849     }else{
9850         throw "Invalid selector";
9851     }
9852     if(unique === true){
9853         return new Roo.CompositeElement(els);
9854     }else{
9855         return new Roo.CompositeElementLite(els);
9856     }
9857 };
9858 /**
9859  * Selects elements based on the passed CSS selector to enable working on them as 1.
9860  * @param {String/Array} selector The CSS selector or an array of elements
9861  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9862  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9863  * @return {CompositeElementLite/CompositeElement}
9864  * @member Roo
9865  * @method select
9866  */
9867 Roo.select = Roo.Element.select;
9868
9869
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882 /*
9883  * Based on:
9884  * Ext JS Library 1.1.1
9885  * Copyright(c) 2006-2007, Ext JS, LLC.
9886  *
9887  * Originally Released Under LGPL - original licence link has changed is not relivant.
9888  *
9889  * Fork - LGPL
9890  * <script type="text/javascript">
9891  */
9892
9893
9894
9895 //Notifies Element that fx methods are available
9896 Roo.enableFx = true;
9897
9898 /**
9899  * @class Roo.Fx
9900  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9901  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9902  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9903  * Element effects to work.</p><br/>
9904  *
9905  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9906  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9907  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9908  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9909  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9910  * expected results and should be done with care.</p><br/>
9911  *
9912  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9913  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9914 <pre>
9915 Value  Description
9916 -----  -----------------------------
9917 tl     The top left corner
9918 t      The center of the top edge
9919 tr     The top right corner
9920 l      The center of the left edge
9921 r      The center of the right edge
9922 bl     The bottom left corner
9923 b      The center of the bottom edge
9924 br     The bottom right corner
9925 </pre>
9926  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9927  * below are common options that can be passed to any Fx method.</b>
9928  * @cfg {Function} callback A function called when the effect is finished
9929  * @cfg {Object} scope The scope of the effect function
9930  * @cfg {String} easing A valid Easing value for the effect
9931  * @cfg {String} afterCls A css class to apply after the effect
9932  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9933  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9934  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9935  * effects that end with the element being visually hidden, ignored otherwise)
9936  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9937  * a function which returns such a specification that will be applied to the Element after the effect finishes
9938  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9939  * @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
9940  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9941  */
9942 Roo.Fx = {
9943         /**
9944          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9945          * origin for the slide effect.  This function automatically handles wrapping the element with
9946          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9947          * Usage:
9948          *<pre><code>
9949 // default: slide the element in from the top
9950 el.slideIn();
9951
9952 // custom: slide the element in from the right with a 2-second duration
9953 el.slideIn('r', { duration: 2 });
9954
9955 // common config options shown with default values
9956 el.slideIn('t', {
9957     easing: 'easeOut',
9958     duration: .5
9959 });
9960 </code></pre>
9961          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9962          * @param {Object} options (optional) Object literal with any of the Fx config options
9963          * @return {Roo.Element} The Element
9964          */
9965     slideIn : function(anchor, o){
9966         var el = this.getFxEl();
9967         o = o || {};
9968
9969         el.queueFx(o, function(){
9970
9971             anchor = anchor || "t";
9972
9973             // fix display to visibility
9974             this.fixDisplay();
9975
9976             // restore values after effect
9977             var r = this.getFxRestore();
9978             var b = this.getBox();
9979             // fixed size for slide
9980             this.setSize(b);
9981
9982             // wrap if needed
9983             var wrap = this.fxWrap(r.pos, o, "hidden");
9984
9985             var st = this.dom.style;
9986             st.visibility = "visible";
9987             st.position = "absolute";
9988
9989             // clear out temp styles after slide and unwrap
9990             var after = function(){
9991                 el.fxUnwrap(wrap, r.pos, o);
9992                 st.width = r.width;
9993                 st.height = r.height;
9994                 el.afterFx(o);
9995             };
9996             // time to calc the positions
9997             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9998
9999             switch(anchor.toLowerCase()){
10000                 case "t":
10001                     wrap.setSize(b.width, 0);
10002                     st.left = st.bottom = "0";
10003                     a = {height: bh};
10004                 break;
10005                 case "l":
10006                     wrap.setSize(0, b.height);
10007                     st.right = st.top = "0";
10008                     a = {width: bw};
10009                 break;
10010                 case "r":
10011                     wrap.setSize(0, b.height);
10012                     wrap.setX(b.right);
10013                     st.left = st.top = "0";
10014                     a = {width: bw, points: pt};
10015                 break;
10016                 case "b":
10017                     wrap.setSize(b.width, 0);
10018                     wrap.setY(b.bottom);
10019                     st.left = st.top = "0";
10020                     a = {height: bh, points: pt};
10021                 break;
10022                 case "tl":
10023                     wrap.setSize(0, 0);
10024                     st.right = st.bottom = "0";
10025                     a = {width: bw, height: bh};
10026                 break;
10027                 case "bl":
10028                     wrap.setSize(0, 0);
10029                     wrap.setY(b.y+b.height);
10030                     st.right = st.top = "0";
10031                     a = {width: bw, height: bh, points: pt};
10032                 break;
10033                 case "br":
10034                     wrap.setSize(0, 0);
10035                     wrap.setXY([b.right, b.bottom]);
10036                     st.left = st.top = "0";
10037                     a = {width: bw, height: bh, points: pt};
10038                 break;
10039                 case "tr":
10040                     wrap.setSize(0, 0);
10041                     wrap.setX(b.x+b.width);
10042                     st.left = st.bottom = "0";
10043                     a = {width: bw, height: bh, points: pt};
10044                 break;
10045             }
10046             this.dom.style.visibility = "visible";
10047             wrap.show();
10048
10049             arguments.callee.anim = wrap.fxanim(a,
10050                 o,
10051                 'motion',
10052                 .5,
10053                 'easeOut', after);
10054         });
10055         return this;
10056     },
10057     
10058         /**
10059          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10060          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10061          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10062          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10063          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10064          * Usage:
10065          *<pre><code>
10066 // default: slide the element out to the top
10067 el.slideOut();
10068
10069 // custom: slide the element out to the right with a 2-second duration
10070 el.slideOut('r', { duration: 2 });
10071
10072 // common config options shown with default values
10073 el.slideOut('t', {
10074     easing: 'easeOut',
10075     duration: .5,
10076     remove: false,
10077     useDisplay: false
10078 });
10079 </code></pre>
10080          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10081          * @param {Object} options (optional) Object literal with any of the Fx config options
10082          * @return {Roo.Element} The Element
10083          */
10084     slideOut : function(anchor, o){
10085         var el = this.getFxEl();
10086         o = o || {};
10087
10088         el.queueFx(o, function(){
10089
10090             anchor = anchor || "t";
10091
10092             // restore values after effect
10093             var r = this.getFxRestore();
10094             
10095             var b = this.getBox();
10096             // fixed size for slide
10097             this.setSize(b);
10098
10099             // wrap if needed
10100             var wrap = this.fxWrap(r.pos, o, "visible");
10101
10102             var st = this.dom.style;
10103             st.visibility = "visible";
10104             st.position = "absolute";
10105
10106             wrap.setSize(b);
10107
10108             var after = function(){
10109                 if(o.useDisplay){
10110                     el.setDisplayed(false);
10111                 }else{
10112                     el.hide();
10113                 }
10114
10115                 el.fxUnwrap(wrap, r.pos, o);
10116
10117                 st.width = r.width;
10118                 st.height = r.height;
10119
10120                 el.afterFx(o);
10121             };
10122
10123             var a, zero = {to: 0};
10124             switch(anchor.toLowerCase()){
10125                 case "t":
10126                     st.left = st.bottom = "0";
10127                     a = {height: zero};
10128                 break;
10129                 case "l":
10130                     st.right = st.top = "0";
10131                     a = {width: zero};
10132                 break;
10133                 case "r":
10134                     st.left = st.top = "0";
10135                     a = {width: zero, points: {to:[b.right, b.y]}};
10136                 break;
10137                 case "b":
10138                     st.left = st.top = "0";
10139                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10140                 break;
10141                 case "tl":
10142                     st.right = st.bottom = "0";
10143                     a = {width: zero, height: zero};
10144                 break;
10145                 case "bl":
10146                     st.right = st.top = "0";
10147                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10148                 break;
10149                 case "br":
10150                     st.left = st.top = "0";
10151                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10152                 break;
10153                 case "tr":
10154                     st.left = st.bottom = "0";
10155                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10156                 break;
10157             }
10158
10159             arguments.callee.anim = wrap.fxanim(a,
10160                 o,
10161                 'motion',
10162                 .5,
10163                 "easeOut", after);
10164         });
10165         return this;
10166     },
10167
10168         /**
10169          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10170          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10171          * The element must be removed from the DOM using the 'remove' config option if desired.
10172          * Usage:
10173          *<pre><code>
10174 // default
10175 el.puff();
10176
10177 // common config options shown with default values
10178 el.puff({
10179     easing: 'easeOut',
10180     duration: .5,
10181     remove: false,
10182     useDisplay: false
10183 });
10184 </code></pre>
10185          * @param {Object} options (optional) Object literal with any of the Fx config options
10186          * @return {Roo.Element} The Element
10187          */
10188     puff : function(o){
10189         var el = this.getFxEl();
10190         o = o || {};
10191
10192         el.queueFx(o, function(){
10193             this.clearOpacity();
10194             this.show();
10195
10196             // restore values after effect
10197             var r = this.getFxRestore();
10198             var st = this.dom.style;
10199
10200             var after = function(){
10201                 if(o.useDisplay){
10202                     el.setDisplayed(false);
10203                 }else{
10204                     el.hide();
10205                 }
10206
10207                 el.clearOpacity();
10208
10209                 el.setPositioning(r.pos);
10210                 st.width = r.width;
10211                 st.height = r.height;
10212                 st.fontSize = '';
10213                 el.afterFx(o);
10214             };
10215
10216             var width = this.getWidth();
10217             var height = this.getHeight();
10218
10219             arguments.callee.anim = this.fxanim({
10220                     width : {to: this.adjustWidth(width * 2)},
10221                     height : {to: this.adjustHeight(height * 2)},
10222                     points : {by: [-(width * .5), -(height * .5)]},
10223                     opacity : {to: 0},
10224                     fontSize: {to:200, unit: "%"}
10225                 },
10226                 o,
10227                 'motion',
10228                 .5,
10229                 "easeOut", after);
10230         });
10231         return this;
10232     },
10233
10234         /**
10235          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10236          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10237          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10238          * Usage:
10239          *<pre><code>
10240 // default
10241 el.switchOff();
10242
10243 // all config options shown with default values
10244 el.switchOff({
10245     easing: 'easeIn',
10246     duration: .3,
10247     remove: false,
10248     useDisplay: false
10249 });
10250 </code></pre>
10251          * @param {Object} options (optional) Object literal with any of the Fx config options
10252          * @return {Roo.Element} The Element
10253          */
10254     switchOff : function(o){
10255         var el = this.getFxEl();
10256         o = o || {};
10257
10258         el.queueFx(o, function(){
10259             this.clearOpacity();
10260             this.clip();
10261
10262             // restore values after effect
10263             var r = this.getFxRestore();
10264             var st = this.dom.style;
10265
10266             var after = function(){
10267                 if(o.useDisplay){
10268                     el.setDisplayed(false);
10269                 }else{
10270                     el.hide();
10271                 }
10272
10273                 el.clearOpacity();
10274                 el.setPositioning(r.pos);
10275                 st.width = r.width;
10276                 st.height = r.height;
10277
10278                 el.afterFx(o);
10279             };
10280
10281             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10282                 this.clearOpacity();
10283                 (function(){
10284                     this.fxanim({
10285                         height:{to:1},
10286                         points:{by:[0, this.getHeight() * .5]}
10287                     }, o, 'motion', 0.3, 'easeIn', after);
10288                 }).defer(100, this);
10289             });
10290         });
10291         return this;
10292     },
10293
10294     /**
10295      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10296      * changed using the "attr" config option) and then fading back to the original color. If no original
10297      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10298      * Usage:
10299 <pre><code>
10300 // default: highlight background to yellow
10301 el.highlight();
10302
10303 // custom: highlight foreground text to blue for 2 seconds
10304 el.highlight("0000ff", { attr: 'color', duration: 2 });
10305
10306 // common config options shown with default values
10307 el.highlight("ffff9c", {
10308     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10309     endColor: (current color) or "ffffff",
10310     easing: 'easeIn',
10311     duration: 1
10312 });
10313 </code></pre>
10314      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10315      * @param {Object} options (optional) Object literal with any of the Fx config options
10316      * @return {Roo.Element} The Element
10317      */ 
10318     highlight : function(color, o){
10319         var el = this.getFxEl();
10320         o = o || {};
10321
10322         el.queueFx(o, function(){
10323             color = color || "ffff9c";
10324             attr = o.attr || "backgroundColor";
10325
10326             this.clearOpacity();
10327             this.show();
10328
10329             var origColor = this.getColor(attr);
10330             var restoreColor = this.dom.style[attr];
10331             endColor = (o.endColor || origColor) || "ffffff";
10332
10333             var after = function(){
10334                 el.dom.style[attr] = restoreColor;
10335                 el.afterFx(o);
10336             };
10337
10338             var a = {};
10339             a[attr] = {from: color, to: endColor};
10340             arguments.callee.anim = this.fxanim(a,
10341                 o,
10342                 'color',
10343                 1,
10344                 'easeIn', after);
10345         });
10346         return this;
10347     },
10348
10349    /**
10350     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10351     * Usage:
10352 <pre><code>
10353 // default: a single light blue ripple
10354 el.frame();
10355
10356 // custom: 3 red ripples lasting 3 seconds total
10357 el.frame("ff0000", 3, { duration: 3 });
10358
10359 // common config options shown with default values
10360 el.frame("C3DAF9", 1, {
10361     duration: 1 //duration of entire animation (not each individual ripple)
10362     // Note: Easing is not configurable and will be ignored if included
10363 });
10364 </code></pre>
10365     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10366     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10367     * @param {Object} options (optional) Object literal with any of the Fx config options
10368     * @return {Roo.Element} The Element
10369     */
10370     frame : function(color, count, o){
10371         var el = this.getFxEl();
10372         o = o || {};
10373
10374         el.queueFx(o, function(){
10375             color = color || "#C3DAF9";
10376             if(color.length == 6){
10377                 color = "#" + color;
10378             }
10379             count = count || 1;
10380             duration = o.duration || 1;
10381             this.show();
10382
10383             var b = this.getBox();
10384             var animFn = function(){
10385                 var proxy = this.createProxy({
10386
10387                      style:{
10388                         visbility:"hidden",
10389                         position:"absolute",
10390                         "z-index":"35000", // yee haw
10391                         border:"0px solid " + color
10392                      }
10393                   });
10394                 var scale = Roo.isBorderBox ? 2 : 1;
10395                 proxy.animate({
10396                     top:{from:b.y, to:b.y - 20},
10397                     left:{from:b.x, to:b.x - 20},
10398                     borderWidth:{from:0, to:10},
10399                     opacity:{from:1, to:0},
10400                     height:{from:b.height, to:(b.height + (20*scale))},
10401                     width:{from:b.width, to:(b.width + (20*scale))}
10402                 }, duration, function(){
10403                     proxy.remove();
10404                 });
10405                 if(--count > 0){
10406                      animFn.defer((duration/2)*1000, this);
10407                 }else{
10408                     el.afterFx(o);
10409                 }
10410             };
10411             animFn.call(this);
10412         });
10413         return this;
10414     },
10415
10416    /**
10417     * Creates a pause before any subsequent queued effects begin.  If there are
10418     * no effects queued after the pause it will have no effect.
10419     * Usage:
10420 <pre><code>
10421 el.pause(1);
10422 </code></pre>
10423     * @param {Number} seconds The length of time to pause (in seconds)
10424     * @return {Roo.Element} The Element
10425     */
10426     pause : function(seconds){
10427         var el = this.getFxEl();
10428         var o = {};
10429
10430         el.queueFx(o, function(){
10431             setTimeout(function(){
10432                 el.afterFx(o);
10433             }, seconds * 1000);
10434         });
10435         return this;
10436     },
10437
10438    /**
10439     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10440     * using the "endOpacity" config option.
10441     * Usage:
10442 <pre><code>
10443 // default: fade in from opacity 0 to 100%
10444 el.fadeIn();
10445
10446 // custom: fade in from opacity 0 to 75% over 2 seconds
10447 el.fadeIn({ endOpacity: .75, duration: 2});
10448
10449 // common config options shown with default values
10450 el.fadeIn({
10451     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10452     easing: 'easeOut',
10453     duration: .5
10454 });
10455 </code></pre>
10456     * @param {Object} options (optional) Object literal with any of the Fx config options
10457     * @return {Roo.Element} The Element
10458     */
10459     fadeIn : function(o){
10460         var el = this.getFxEl();
10461         o = o || {};
10462         el.queueFx(o, function(){
10463             this.setOpacity(0);
10464             this.fixDisplay();
10465             this.dom.style.visibility = 'visible';
10466             var to = o.endOpacity || 1;
10467             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10468                 o, null, .5, "easeOut", function(){
10469                 if(to == 1){
10470                     this.clearOpacity();
10471                 }
10472                 el.afterFx(o);
10473             });
10474         });
10475         return this;
10476     },
10477
10478    /**
10479     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10480     * using the "endOpacity" config option.
10481     * Usage:
10482 <pre><code>
10483 // default: fade out from the element's current opacity to 0
10484 el.fadeOut();
10485
10486 // custom: fade out from the element's current opacity to 25% over 2 seconds
10487 el.fadeOut({ endOpacity: .25, duration: 2});
10488
10489 // common config options shown with default values
10490 el.fadeOut({
10491     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10492     easing: 'easeOut',
10493     duration: .5
10494     remove: false,
10495     useDisplay: false
10496 });
10497 </code></pre>
10498     * @param {Object} options (optional) Object literal with any of the Fx config options
10499     * @return {Roo.Element} The Element
10500     */
10501     fadeOut : function(o){
10502         var el = this.getFxEl();
10503         o = o || {};
10504         el.queueFx(o, function(){
10505             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10506                 o, null, .5, "easeOut", function(){
10507                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10508                      this.dom.style.display = "none";
10509                 }else{
10510                      this.dom.style.visibility = "hidden";
10511                 }
10512                 this.clearOpacity();
10513                 el.afterFx(o);
10514             });
10515         });
10516         return this;
10517     },
10518
10519    /**
10520     * Animates the transition of an element's dimensions from a starting height/width
10521     * to an ending height/width.
10522     * Usage:
10523 <pre><code>
10524 // change height and width to 100x100 pixels
10525 el.scale(100, 100);
10526
10527 // common config options shown with default values.  The height and width will default to
10528 // the element's existing values if passed as null.
10529 el.scale(
10530     [element's width],
10531     [element's height], {
10532     easing: 'easeOut',
10533     duration: .35
10534 });
10535 </code></pre>
10536     * @param {Number} width  The new width (pass undefined to keep the original width)
10537     * @param {Number} height  The new height (pass undefined to keep the original height)
10538     * @param {Object} options (optional) Object literal with any of the Fx config options
10539     * @return {Roo.Element} The Element
10540     */
10541     scale : function(w, h, o){
10542         this.shift(Roo.apply({}, o, {
10543             width: w,
10544             height: h
10545         }));
10546         return this;
10547     },
10548
10549    /**
10550     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10551     * Any of these properties not specified in the config object will not be changed.  This effect 
10552     * requires that at least one new dimension, position or opacity setting must be passed in on
10553     * the config object in order for the function to have any effect.
10554     * Usage:
10555 <pre><code>
10556 // slide the element horizontally to x position 200 while changing the height and opacity
10557 el.shift({ x: 200, height: 50, opacity: .8 });
10558
10559 // common config options shown with default values.
10560 el.shift({
10561     width: [element's width],
10562     height: [element's height],
10563     x: [element's x position],
10564     y: [element's y position],
10565     opacity: [element's opacity],
10566     easing: 'easeOut',
10567     duration: .35
10568 });
10569 </code></pre>
10570     * @param {Object} options  Object literal with any of the Fx config options
10571     * @return {Roo.Element} The Element
10572     */
10573     shift : function(o){
10574         var el = this.getFxEl();
10575         o = o || {};
10576         el.queueFx(o, function(){
10577             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10578             if(w !== undefined){
10579                 a.width = {to: this.adjustWidth(w)};
10580             }
10581             if(h !== undefined){
10582                 a.height = {to: this.adjustHeight(h)};
10583             }
10584             if(x !== undefined || y !== undefined){
10585                 a.points = {to: [
10586                     x !== undefined ? x : this.getX(),
10587                     y !== undefined ? y : this.getY()
10588                 ]};
10589             }
10590             if(op !== undefined){
10591                 a.opacity = {to: op};
10592             }
10593             if(o.xy !== undefined){
10594                 a.points = {to: o.xy};
10595             }
10596             arguments.callee.anim = this.fxanim(a,
10597                 o, 'motion', .35, "easeOut", function(){
10598                 el.afterFx(o);
10599             });
10600         });
10601         return this;
10602     },
10603
10604         /**
10605          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10606          * ending point of the effect.
10607          * Usage:
10608          *<pre><code>
10609 // default: slide the element downward while fading out
10610 el.ghost();
10611
10612 // custom: slide the element out to the right with a 2-second duration
10613 el.ghost('r', { duration: 2 });
10614
10615 // common config options shown with default values
10616 el.ghost('b', {
10617     easing: 'easeOut',
10618     duration: .5
10619     remove: false,
10620     useDisplay: false
10621 });
10622 </code></pre>
10623          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10624          * @param {Object} options (optional) Object literal with any of the Fx config options
10625          * @return {Roo.Element} The Element
10626          */
10627     ghost : function(anchor, o){
10628         var el = this.getFxEl();
10629         o = o || {};
10630
10631         el.queueFx(o, function(){
10632             anchor = anchor || "b";
10633
10634             // restore values after effect
10635             var r = this.getFxRestore();
10636             var w = this.getWidth(),
10637                 h = this.getHeight();
10638
10639             var st = this.dom.style;
10640
10641             var after = function(){
10642                 if(o.useDisplay){
10643                     el.setDisplayed(false);
10644                 }else{
10645                     el.hide();
10646                 }
10647
10648                 el.clearOpacity();
10649                 el.setPositioning(r.pos);
10650                 st.width = r.width;
10651                 st.height = r.height;
10652
10653                 el.afterFx(o);
10654             };
10655
10656             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10657             switch(anchor.toLowerCase()){
10658                 case "t":
10659                     pt.by = [0, -h];
10660                 break;
10661                 case "l":
10662                     pt.by = [-w, 0];
10663                 break;
10664                 case "r":
10665                     pt.by = [w, 0];
10666                 break;
10667                 case "b":
10668                     pt.by = [0, h];
10669                 break;
10670                 case "tl":
10671                     pt.by = [-w, -h];
10672                 break;
10673                 case "bl":
10674                     pt.by = [-w, h];
10675                 break;
10676                 case "br":
10677                     pt.by = [w, h];
10678                 break;
10679                 case "tr":
10680                     pt.by = [w, -h];
10681                 break;
10682             }
10683
10684             arguments.callee.anim = this.fxanim(a,
10685                 o,
10686                 'motion',
10687                 .5,
10688                 "easeOut", after);
10689         });
10690         return this;
10691     },
10692
10693         /**
10694          * Ensures that all effects queued after syncFx is called on the element are
10695          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10696          * @return {Roo.Element} The Element
10697          */
10698     syncFx : function(){
10699         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10700             block : false,
10701             concurrent : true,
10702             stopFx : false
10703         });
10704         return this;
10705     },
10706
10707         /**
10708          * Ensures that all effects queued after sequenceFx is called on the element are
10709          * run in sequence.  This is the opposite of {@link #syncFx}.
10710          * @return {Roo.Element} The Element
10711          */
10712     sequenceFx : function(){
10713         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10714             block : false,
10715             concurrent : false,
10716             stopFx : false
10717         });
10718         return this;
10719     },
10720
10721         /* @private */
10722     nextFx : function(){
10723         var ef = this.fxQueue[0];
10724         if(ef){
10725             ef.call(this);
10726         }
10727     },
10728
10729         /**
10730          * Returns true if the element has any effects actively running or queued, else returns false.
10731          * @return {Boolean} True if element has active effects, else false
10732          */
10733     hasActiveFx : function(){
10734         return this.fxQueue && this.fxQueue[0];
10735     },
10736
10737         /**
10738          * Stops any running effects and clears the element's internal effects queue if it contains
10739          * any additional effects that haven't started yet.
10740          * @return {Roo.Element} The Element
10741          */
10742     stopFx : function(){
10743         if(this.hasActiveFx()){
10744             var cur = this.fxQueue[0];
10745             if(cur && cur.anim && cur.anim.isAnimated()){
10746                 this.fxQueue = [cur]; // clear out others
10747                 cur.anim.stop(true);
10748             }
10749         }
10750         return this;
10751     },
10752
10753         /* @private */
10754     beforeFx : function(o){
10755         if(this.hasActiveFx() && !o.concurrent){
10756            if(o.stopFx){
10757                this.stopFx();
10758                return true;
10759            }
10760            return false;
10761         }
10762         return true;
10763     },
10764
10765         /**
10766          * Returns true if the element is currently blocking so that no other effect can be queued
10767          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10768          * used to ensure that an effect initiated by a user action runs to completion prior to the
10769          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10770          * @return {Boolean} True if blocking, else false
10771          */
10772     hasFxBlock : function(){
10773         var q = this.fxQueue;
10774         return q && q[0] && q[0].block;
10775     },
10776
10777         /* @private */
10778     queueFx : function(o, fn){
10779         if(!this.fxQueue){
10780             this.fxQueue = [];
10781         }
10782         if(!this.hasFxBlock()){
10783             Roo.applyIf(o, this.fxDefaults);
10784             if(!o.concurrent){
10785                 var run = this.beforeFx(o);
10786                 fn.block = o.block;
10787                 this.fxQueue.push(fn);
10788                 if(run){
10789                     this.nextFx();
10790                 }
10791             }else{
10792                 fn.call(this);
10793             }
10794         }
10795         return this;
10796     },
10797
10798         /* @private */
10799     fxWrap : function(pos, o, vis){
10800         var wrap;
10801         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10802             var wrapXY;
10803             if(o.fixPosition){
10804                 wrapXY = this.getXY();
10805             }
10806             var div = document.createElement("div");
10807             div.style.visibility = vis;
10808             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10809             wrap.setPositioning(pos);
10810             if(wrap.getStyle("position") == "static"){
10811                 wrap.position("relative");
10812             }
10813             this.clearPositioning('auto');
10814             wrap.clip();
10815             wrap.dom.appendChild(this.dom);
10816             if(wrapXY){
10817                 wrap.setXY(wrapXY);
10818             }
10819         }
10820         return wrap;
10821     },
10822
10823         /* @private */
10824     fxUnwrap : function(wrap, pos, o){
10825         this.clearPositioning();
10826         this.setPositioning(pos);
10827         if(!o.wrap){
10828             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10829             wrap.remove();
10830         }
10831     },
10832
10833         /* @private */
10834     getFxRestore : function(){
10835         var st = this.dom.style;
10836         return {pos: this.getPositioning(), width: st.width, height : st.height};
10837     },
10838
10839         /* @private */
10840     afterFx : function(o){
10841         if(o.afterStyle){
10842             this.applyStyles(o.afterStyle);
10843         }
10844         if(o.afterCls){
10845             this.addClass(o.afterCls);
10846         }
10847         if(o.remove === true){
10848             this.remove();
10849         }
10850         Roo.callback(o.callback, o.scope, [this]);
10851         if(!o.concurrent){
10852             this.fxQueue.shift();
10853             this.nextFx();
10854         }
10855     },
10856
10857         /* @private */
10858     getFxEl : function(){ // support for composite element fx
10859         return Roo.get(this.dom);
10860     },
10861
10862         /* @private */
10863     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10864         animType = animType || 'run';
10865         opt = opt || {};
10866         var anim = Roo.lib.Anim[animType](
10867             this.dom, args,
10868             (opt.duration || defaultDur) || .35,
10869             (opt.easing || defaultEase) || 'easeOut',
10870             function(){
10871                 Roo.callback(cb, this);
10872             },
10873             this
10874         );
10875         opt.anim = anim;
10876         return anim;
10877     }
10878 };
10879
10880 // backwords compat
10881 Roo.Fx.resize = Roo.Fx.scale;
10882
10883 //When included, Roo.Fx is automatically applied to Element so that all basic
10884 //effects are available directly via the Element API
10885 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10886  * Based on:
10887  * Ext JS Library 1.1.1
10888  * Copyright(c) 2006-2007, Ext JS, LLC.
10889  *
10890  * Originally Released Under LGPL - original licence link has changed is not relivant.
10891  *
10892  * Fork - LGPL
10893  * <script type="text/javascript">
10894  */
10895
10896
10897 /**
10898  * @class Roo.CompositeElement
10899  * Standard composite class. Creates a Roo.Element for every element in the collection.
10900  * <br><br>
10901  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10902  * actions will be performed on all the elements in this collection.</b>
10903  * <br><br>
10904  * All methods return <i>this</i> and can be chained.
10905  <pre><code>
10906  var els = Roo.select("#some-el div.some-class", true);
10907  // or select directly from an existing element
10908  var el = Roo.get('some-el');
10909  el.select('div.some-class', true);
10910
10911  els.setWidth(100); // all elements become 100 width
10912  els.hide(true); // all elements fade out and hide
10913  // or
10914  els.setWidth(100).hide(true);
10915  </code></pre>
10916  */
10917 Roo.CompositeElement = function(els){
10918     this.elements = [];
10919     this.addElements(els);
10920 };
10921 Roo.CompositeElement.prototype = {
10922     isComposite: true,
10923     addElements : function(els){
10924         if(!els) return this;
10925         if(typeof els == "string"){
10926             els = Roo.Element.selectorFunction(els);
10927         }
10928         var yels = this.elements;
10929         var index = yels.length-1;
10930         for(var i = 0, len = els.length; i < len; i++) {
10931                 yels[++index] = Roo.get(els[i]);
10932         }
10933         return this;
10934     },
10935
10936     /**
10937     * Clears this composite and adds the elements returned by the passed selector.
10938     * @param {String/Array} els A string CSS selector, an array of elements or an element
10939     * @return {CompositeElement} this
10940     */
10941     fill : function(els){
10942         this.elements = [];
10943         this.add(els);
10944         return this;
10945     },
10946
10947     /**
10948     * Filters this composite to only elements that match the passed selector.
10949     * @param {String} selector A string CSS selector
10950     * @return {CompositeElement} this
10951     */
10952     filter : function(selector){
10953         var els = [];
10954         this.each(function(el){
10955             if(el.is(selector)){
10956                 els[els.length] = el.dom;
10957             }
10958         });
10959         this.fill(els);
10960         return this;
10961     },
10962
10963     invoke : function(fn, args){
10964         var els = this.elements;
10965         for(var i = 0, len = els.length; i < len; i++) {
10966                 Roo.Element.prototype[fn].apply(els[i], args);
10967         }
10968         return this;
10969     },
10970     /**
10971     * Adds elements to this composite.
10972     * @param {String/Array} els A string CSS selector, an array of elements or an element
10973     * @return {CompositeElement} this
10974     */
10975     add : function(els){
10976         if(typeof els == "string"){
10977             this.addElements(Roo.Element.selectorFunction(els));
10978         }else if(els.length !== undefined){
10979             this.addElements(els);
10980         }else{
10981             this.addElements([els]);
10982         }
10983         return this;
10984     },
10985     /**
10986     * Calls the passed function passing (el, this, index) for each element in this composite.
10987     * @param {Function} fn The function to call
10988     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10989     * @return {CompositeElement} this
10990     */
10991     each : function(fn, scope){
10992         var els = this.elements;
10993         for(var i = 0, len = els.length; i < len; i++){
10994             if(fn.call(scope || els[i], els[i], this, i) === false) {
10995                 break;
10996             }
10997         }
10998         return this;
10999     },
11000
11001     /**
11002      * Returns the Element object at the specified index
11003      * @param {Number} index
11004      * @return {Roo.Element}
11005      */
11006     item : function(index){
11007         return this.elements[index] || null;
11008     },
11009
11010     /**
11011      * Returns the first Element
11012      * @return {Roo.Element}
11013      */
11014     first : function(){
11015         return this.item(0);
11016     },
11017
11018     /**
11019      * Returns the last Element
11020      * @return {Roo.Element}
11021      */
11022     last : function(){
11023         return this.item(this.elements.length-1);
11024     },
11025
11026     /**
11027      * Returns the number of elements in this composite
11028      * @return Number
11029      */
11030     getCount : function(){
11031         return this.elements.length;
11032     },
11033
11034     /**
11035      * Returns true if this composite contains the passed element
11036      * @return Boolean
11037      */
11038     contains : function(el){
11039         return this.indexOf(el) !== -1;
11040     },
11041
11042     /**
11043      * Returns true if this composite contains the passed element
11044      * @return Boolean
11045      */
11046     indexOf : function(el){
11047         return this.elements.indexOf(Roo.get(el));
11048     },
11049
11050
11051     /**
11052     * Removes the specified element(s).
11053     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11054     * or an array of any of those.
11055     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11056     * @return {CompositeElement} this
11057     */
11058     removeElement : function(el, removeDom){
11059         if(el instanceof Array){
11060             for(var i = 0, len = el.length; i < len; i++){
11061                 this.removeElement(el[i]);
11062             }
11063             return this;
11064         }
11065         var index = typeof el == 'number' ? el : this.indexOf(el);
11066         if(index !== -1){
11067             if(removeDom){
11068                 var d = this.elements[index];
11069                 if(d.dom){
11070                     d.remove();
11071                 }else{
11072                     d.parentNode.removeChild(d);
11073                 }
11074             }
11075             this.elements.splice(index, 1);
11076         }
11077         return this;
11078     },
11079
11080     /**
11081     * Replaces the specified element with the passed element.
11082     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11083     * to replace.
11084     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11085     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11086     * @return {CompositeElement} this
11087     */
11088     replaceElement : function(el, replacement, domReplace){
11089         var index = typeof el == 'number' ? el : this.indexOf(el);
11090         if(index !== -1){
11091             if(domReplace){
11092                 this.elements[index].replaceWith(replacement);
11093             }else{
11094                 this.elements.splice(index, 1, Roo.get(replacement))
11095             }
11096         }
11097         return this;
11098     },
11099
11100     /**
11101      * Removes all elements.
11102      */
11103     clear : function(){
11104         this.elements = [];
11105     }
11106 };
11107 (function(){
11108     Roo.CompositeElement.createCall = function(proto, fnName){
11109         if(!proto[fnName]){
11110             proto[fnName] = function(){
11111                 return this.invoke(fnName, arguments);
11112             };
11113         }
11114     };
11115     for(var fnName in Roo.Element.prototype){
11116         if(typeof Roo.Element.prototype[fnName] == "function"){
11117             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11118         }
11119     };
11120 })();
11121 /*
11122  * Based on:
11123  * Ext JS Library 1.1.1
11124  * Copyright(c) 2006-2007, Ext JS, LLC.
11125  *
11126  * Originally Released Under LGPL - original licence link has changed is not relivant.
11127  *
11128  * Fork - LGPL
11129  * <script type="text/javascript">
11130  */
11131
11132 /**
11133  * @class Roo.CompositeElementLite
11134  * @extends Roo.CompositeElement
11135  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11136  <pre><code>
11137  var els = Roo.select("#some-el div.some-class");
11138  // or select directly from an existing element
11139  var el = Roo.get('some-el');
11140  el.select('div.some-class');
11141
11142  els.setWidth(100); // all elements become 100 width
11143  els.hide(true); // all elements fade out and hide
11144  // or
11145  els.setWidth(100).hide(true);
11146  </code></pre><br><br>
11147  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11148  * actions will be performed on all the elements in this collection.</b>
11149  */
11150 Roo.CompositeElementLite = function(els){
11151     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11152     this.el = new Roo.Element.Flyweight();
11153 };
11154 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11155     addElements : function(els){
11156         if(els){
11157             if(els instanceof Array){
11158                 this.elements = this.elements.concat(els);
11159             }else{
11160                 var yels = this.elements;
11161                 var index = yels.length-1;
11162                 for(var i = 0, len = els.length; i < len; i++) {
11163                     yels[++index] = els[i];
11164                 }
11165             }
11166         }
11167         return this;
11168     },
11169     invoke : function(fn, args){
11170         var els = this.elements;
11171         var el = this.el;
11172         for(var i = 0, len = els.length; i < len; i++) {
11173             el.dom = els[i];
11174                 Roo.Element.prototype[fn].apply(el, args);
11175         }
11176         return this;
11177     },
11178     /**
11179      * Returns a flyweight Element of the dom element object at the specified index
11180      * @param {Number} index
11181      * @return {Roo.Element}
11182      */
11183     item : function(index){
11184         if(!this.elements[index]){
11185             return null;
11186         }
11187         this.el.dom = this.elements[index];
11188         return this.el;
11189     },
11190
11191     // fixes scope with flyweight
11192     addListener : function(eventName, handler, scope, opt){
11193         var els = this.elements;
11194         for(var i = 0, len = els.length; i < len; i++) {
11195             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11196         }
11197         return this;
11198     },
11199
11200     /**
11201     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11202     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11203     * a reference to the dom node, use el.dom.</b>
11204     * @param {Function} fn The function to call
11205     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11206     * @return {CompositeElement} this
11207     */
11208     each : function(fn, scope){
11209         var els = this.elements;
11210         var el = this.el;
11211         for(var i = 0, len = els.length; i < len; i++){
11212             el.dom = els[i];
11213                 if(fn.call(scope || el, el, this, i) === false){
11214                 break;
11215             }
11216         }
11217         return this;
11218     },
11219
11220     indexOf : function(el){
11221         return this.elements.indexOf(Roo.getDom(el));
11222     },
11223
11224     replaceElement : function(el, replacement, domReplace){
11225         var index = typeof el == 'number' ? el : this.indexOf(el);
11226         if(index !== -1){
11227             replacement = Roo.getDom(replacement);
11228             if(domReplace){
11229                 var d = this.elements[index];
11230                 d.parentNode.insertBefore(replacement, d);
11231                 d.parentNode.removeChild(d);
11232             }
11233             this.elements.splice(index, 1, replacement);
11234         }
11235         return this;
11236     }
11237 });
11238 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11239
11240 /*
11241  * Based on:
11242  * Ext JS Library 1.1.1
11243  * Copyright(c) 2006-2007, Ext JS, LLC.
11244  *
11245  * Originally Released Under LGPL - original licence link has changed is not relivant.
11246  *
11247  * Fork - LGPL
11248  * <script type="text/javascript">
11249  */
11250
11251  
11252
11253 /**
11254  * @class Roo.data.Connection
11255  * @extends Roo.util.Observable
11256  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11257  * either to a configured URL, or to a URL specified at request time.<br><br>
11258  * <p>
11259  * Requests made by this class are asynchronous, and will return immediately. No data from
11260  * the server will be available to the statement immediately following the {@link #request} call.
11261  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11262  * <p>
11263  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11264  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11265  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11266  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11267  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11268  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11269  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11270  * standard DOM methods.
11271  * @constructor
11272  * @param {Object} config a configuration object.
11273  */
11274 Roo.data.Connection = function(config){
11275     Roo.apply(this, config);
11276     this.addEvents({
11277         /**
11278          * @event beforerequest
11279          * Fires before a network request is made to retrieve a data object.
11280          * @param {Connection} conn This Connection object.
11281          * @param {Object} options The options config object passed to the {@link #request} method.
11282          */
11283         "beforerequest" : true,
11284         /**
11285          * @event requestcomplete
11286          * Fires if the request was successfully completed.
11287          * @param {Connection} conn This Connection object.
11288          * @param {Object} response The XHR object containing the response data.
11289          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11290          * @param {Object} options The options config object passed to the {@link #request} method.
11291          */
11292         "requestcomplete" : true,
11293         /**
11294          * @event requestexception
11295          * Fires if an error HTTP status was returned from the server.
11296          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11297          * @param {Connection} conn This Connection object.
11298          * @param {Object} response The XHR object containing the response data.
11299          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11300          * @param {Object} options The options config object passed to the {@link #request} method.
11301          */
11302         "requestexception" : true
11303     });
11304     Roo.data.Connection.superclass.constructor.call(this);
11305 };
11306
11307 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11308     /**
11309      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11310      */
11311     /**
11312      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11313      * extra parameters to each request made by this object. (defaults to undefined)
11314      */
11315     /**
11316      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11317      *  to each request made by this object. (defaults to undefined)
11318      */
11319     /**
11320      * @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)
11321      */
11322     /**
11323      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11324      */
11325     timeout : 30000,
11326     /**
11327      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11328      * @type Boolean
11329      */
11330     autoAbort:false,
11331
11332     /**
11333      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11334      * @type Boolean
11335      */
11336     disableCaching: true,
11337
11338     /**
11339      * Sends an HTTP request to a remote server.
11340      * @param {Object} options An object which may contain the following properties:<ul>
11341      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11342      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11343      * request, a url encoded string or a function to call to get either.</li>
11344      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11345      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11346      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11347      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11348      * <li>options {Object} The parameter to the request call.</li>
11349      * <li>success {Boolean} True if the request succeeded.</li>
11350      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11351      * </ul></li>
11352      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11353      * The callback is passed the following parameters:<ul>
11354      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11355      * <li>options {Object} The parameter to the request call.</li>
11356      * </ul></li>
11357      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11358      * The callback is passed the following parameters:<ul>
11359      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11360      * <li>options {Object} The parameter to the request call.</li>
11361      * </ul></li>
11362      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11363      * for the callback function. Defaults to the browser window.</li>
11364      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11365      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11366      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11367      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11368      * params for the post data. Any params will be appended to the URL.</li>
11369      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11370      * </ul>
11371      * @return {Number} transactionId
11372      */
11373     request : function(o){
11374         if(this.fireEvent("beforerequest", this, o) !== false){
11375             var p = o.params;
11376
11377             if(typeof p == "function"){
11378                 p = p.call(o.scope||window, o);
11379             }
11380             if(typeof p == "object"){
11381                 p = Roo.urlEncode(o.params);
11382             }
11383             if(this.extraParams){
11384                 var extras = Roo.urlEncode(this.extraParams);
11385                 p = p ? (p + '&' + extras) : extras;
11386             }
11387
11388             var url = o.url || this.url;
11389             if(typeof url == 'function'){
11390                 url = url.call(o.scope||window, o);
11391             }
11392
11393             if(o.form){
11394                 var form = Roo.getDom(o.form);
11395                 url = url || form.action;
11396
11397                 var enctype = form.getAttribute("enctype");
11398                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11399                     return this.doFormUpload(o, p, url);
11400                 }
11401                 var f = Roo.lib.Ajax.serializeForm(form);
11402                 p = p ? (p + '&' + f) : f;
11403             }
11404
11405             var hs = o.headers;
11406             if(this.defaultHeaders){
11407                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11408                 if(!o.headers){
11409                     o.headers = hs;
11410                 }
11411             }
11412
11413             var cb = {
11414                 success: this.handleResponse,
11415                 failure: this.handleFailure,
11416                 scope: this,
11417                 argument: {options: o},
11418                 timeout : o.timeout || this.timeout
11419             };
11420
11421             var method = o.method||this.method||(p ? "POST" : "GET");
11422
11423             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11424                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11425             }
11426
11427             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11428                 if(o.autoAbort){
11429                     this.abort();
11430                 }
11431             }else if(this.autoAbort !== false){
11432                 this.abort();
11433             }
11434
11435             if((method == 'GET' && p) || o.xmlData){
11436                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11437                 p = '';
11438             }
11439             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11440             return this.transId;
11441         }else{
11442             Roo.callback(o.callback, o.scope, [o, null, null]);
11443             return null;
11444         }
11445     },
11446
11447     /**
11448      * Determine whether this object has a request outstanding.
11449      * @param {Number} transactionId (Optional) defaults to the last transaction
11450      * @return {Boolean} True if there is an outstanding request.
11451      */
11452     isLoading : function(transId){
11453         if(transId){
11454             return Roo.lib.Ajax.isCallInProgress(transId);
11455         }else{
11456             return this.transId ? true : false;
11457         }
11458     },
11459
11460     /**
11461      * Aborts any outstanding request.
11462      * @param {Number} transactionId (Optional) defaults to the last transaction
11463      */
11464     abort : function(transId){
11465         if(transId || this.isLoading()){
11466             Roo.lib.Ajax.abort(transId || this.transId);
11467         }
11468     },
11469
11470     // private
11471     handleResponse : function(response){
11472         this.transId = false;
11473         var options = response.argument.options;
11474         response.argument = options ? options.argument : null;
11475         this.fireEvent("requestcomplete", this, response, options);
11476         Roo.callback(options.success, options.scope, [response, options]);
11477         Roo.callback(options.callback, options.scope, [options, true, response]);
11478     },
11479
11480     // private
11481     handleFailure : function(response, e){
11482         this.transId = false;
11483         var options = response.argument.options;
11484         response.argument = options ? options.argument : null;
11485         this.fireEvent("requestexception", this, response, options, e);
11486         Roo.callback(options.failure, options.scope, [response, options]);
11487         Roo.callback(options.callback, options.scope, [options, false, response]);
11488     },
11489
11490     // private
11491     doFormUpload : function(o, ps, url){
11492         var id = Roo.id();
11493         var frame = document.createElement('iframe');
11494         frame.id = id;
11495         frame.name = id;
11496         frame.className = 'x-hidden';
11497         if(Roo.isIE){
11498             frame.src = Roo.SSL_SECURE_URL;
11499         }
11500         document.body.appendChild(frame);
11501
11502         if(Roo.isIE){
11503            document.frames[id].name = id;
11504         }
11505
11506         var form = Roo.getDom(o.form);
11507         form.target = id;
11508         form.method = 'POST';
11509         form.enctype = form.encoding = 'multipart/form-data';
11510         if(url){
11511             form.action = url;
11512         }
11513
11514         var hiddens, hd;
11515         if(ps){ // add dynamic params
11516             hiddens = [];
11517             ps = Roo.urlDecode(ps, false);
11518             for(var k in ps){
11519                 if(ps.hasOwnProperty(k)){
11520                     hd = document.createElement('input');
11521                     hd.type = 'hidden';
11522                     hd.name = k;
11523                     hd.value = ps[k];
11524                     form.appendChild(hd);
11525                     hiddens.push(hd);
11526                 }
11527             }
11528         }
11529
11530         function cb(){
11531             var r = {  // bogus response object
11532                 responseText : '',
11533                 responseXML : null
11534             };
11535
11536             r.argument = o ? o.argument : null;
11537
11538             try { //
11539                 var doc;
11540                 if(Roo.isIE){
11541                     doc = frame.contentWindow.document;
11542                 }else {
11543                     doc = (frame.contentDocument || window.frames[id].document);
11544                 }
11545                 if(doc && doc.body){
11546                     r.responseText = doc.body.innerHTML;
11547                 }
11548                 if(doc && doc.XMLDocument){
11549                     r.responseXML = doc.XMLDocument;
11550                 }else {
11551                     r.responseXML = doc;
11552                 }
11553             }
11554             catch(e) {
11555                 // ignore
11556             }
11557
11558             Roo.EventManager.removeListener(frame, 'load', cb, this);
11559
11560             this.fireEvent("requestcomplete", this, r, o);
11561             Roo.callback(o.success, o.scope, [r, o]);
11562             Roo.callback(o.callback, o.scope, [o, true, r]);
11563
11564             setTimeout(function(){document.body.removeChild(frame);}, 100);
11565         }
11566
11567         Roo.EventManager.on(frame, 'load', cb, this);
11568         form.submit();
11569
11570         if(hiddens){ // remove dynamic params
11571             for(var i = 0, len = hiddens.length; i < len; i++){
11572                 form.removeChild(hiddens[i]);
11573             }
11574         }
11575     }
11576 });
11577 /*
11578  * Based on:
11579  * Ext JS Library 1.1.1
11580  * Copyright(c) 2006-2007, Ext JS, LLC.
11581  *
11582  * Originally Released Under LGPL - original licence link has changed is not relivant.
11583  *
11584  * Fork - LGPL
11585  * <script type="text/javascript">
11586  */
11587  
11588 /**
11589  * Global Ajax request class.
11590  * 
11591  * @class Roo.Ajax
11592  * @extends Roo.data.Connection
11593  * @static
11594  * 
11595  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11596  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11597  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11598  * @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)
11599  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11600  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11601  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11602  */
11603 Roo.Ajax = new Roo.data.Connection({
11604     // fix up the docs
11605     /**
11606      * @scope Roo.Ajax
11607      * @type {Boolear} 
11608      */
11609     autoAbort : false,
11610
11611     /**
11612      * Serialize the passed form into a url encoded string
11613      * @scope Roo.Ajax
11614      * @param {String/HTMLElement} form
11615      * @return {String}
11616      */
11617     serializeForm : function(form){
11618         return Roo.lib.Ajax.serializeForm(form);
11619     }
11620 });/*
11621  * Based on:
11622  * Ext JS Library 1.1.1
11623  * Copyright(c) 2006-2007, Ext JS, LLC.
11624  *
11625  * Originally Released Under LGPL - original licence link has changed is not relivant.
11626  *
11627  * Fork - LGPL
11628  * <script type="text/javascript">
11629  */
11630
11631  
11632 /**
11633  * @class Roo.UpdateManager
11634  * @extends Roo.util.Observable
11635  * Provides AJAX-style update for Element object.<br><br>
11636  * Usage:<br>
11637  * <pre><code>
11638  * // Get it from a Roo.Element object
11639  * var el = Roo.get("foo");
11640  * var mgr = el.getUpdateManager();
11641  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11642  * ...
11643  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11644  * <br>
11645  * // or directly (returns the same UpdateManager instance)
11646  * var mgr = new Roo.UpdateManager("myElementId");
11647  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11648  * mgr.on("update", myFcnNeedsToKnow);
11649  * <br>
11650    // short handed call directly from the element object
11651    Roo.get("foo").load({
11652         url: "bar.php",
11653         scripts:true,
11654         params: "for=bar",
11655         text: "Loading Foo..."
11656    });
11657  * </code></pre>
11658  * @constructor
11659  * Create new UpdateManager directly.
11660  * @param {String/HTMLElement/Roo.Element} el The element to update
11661  * @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).
11662  */
11663 Roo.UpdateManager = function(el, forceNew){
11664     el = Roo.get(el);
11665     if(!forceNew && el.updateManager){
11666         return el.updateManager;
11667     }
11668     /**
11669      * The Element object
11670      * @type Roo.Element
11671      */
11672     this.el = el;
11673     /**
11674      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11675      * @type String
11676      */
11677     this.defaultUrl = null;
11678
11679     this.addEvents({
11680         /**
11681          * @event beforeupdate
11682          * Fired before an update is made, return false from your handler and the update is cancelled.
11683          * @param {Roo.Element} el
11684          * @param {String/Object/Function} url
11685          * @param {String/Object} params
11686          */
11687         "beforeupdate": true,
11688         /**
11689          * @event update
11690          * Fired after successful update is made.
11691          * @param {Roo.Element} el
11692          * @param {Object} oResponseObject The response Object
11693          */
11694         "update": true,
11695         /**
11696          * @event failure
11697          * Fired on update failure.
11698          * @param {Roo.Element} el
11699          * @param {Object} oResponseObject The response Object
11700          */
11701         "failure": true
11702     });
11703     var d = Roo.UpdateManager.defaults;
11704     /**
11705      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11706      * @type String
11707      */
11708     this.sslBlankUrl = d.sslBlankUrl;
11709     /**
11710      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11711      * @type Boolean
11712      */
11713     this.disableCaching = d.disableCaching;
11714     /**
11715      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11716      * @type String
11717      */
11718     this.indicatorText = d.indicatorText;
11719     /**
11720      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11721      * @type String
11722      */
11723     this.showLoadIndicator = d.showLoadIndicator;
11724     /**
11725      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11726      * @type Number
11727      */
11728     this.timeout = d.timeout;
11729
11730     /**
11731      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11732      * @type Boolean
11733      */
11734     this.loadScripts = d.loadScripts;
11735
11736     /**
11737      * Transaction object of current executing transaction
11738      */
11739     this.transaction = null;
11740
11741     /**
11742      * @private
11743      */
11744     this.autoRefreshProcId = null;
11745     /**
11746      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11747      * @type Function
11748      */
11749     this.refreshDelegate = this.refresh.createDelegate(this);
11750     /**
11751      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11752      * @type Function
11753      */
11754     this.updateDelegate = this.update.createDelegate(this);
11755     /**
11756      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11757      * @type Function
11758      */
11759     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11760     /**
11761      * @private
11762      */
11763     this.successDelegate = this.processSuccess.createDelegate(this);
11764     /**
11765      * @private
11766      */
11767     this.failureDelegate = this.processFailure.createDelegate(this);
11768
11769     if(!this.renderer){
11770      /**
11771       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11772       */
11773     this.renderer = new Roo.UpdateManager.BasicRenderer();
11774     }
11775     
11776     Roo.UpdateManager.superclass.constructor.call(this);
11777 };
11778
11779 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11780     /**
11781      * Get the Element this UpdateManager is bound to
11782      * @return {Roo.Element} The element
11783      */
11784     getEl : function(){
11785         return this.el;
11786     },
11787     /**
11788      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11789      * @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:
11790 <pre><code>
11791 um.update({<br/>
11792     url: "your-url.php",<br/>
11793     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11794     callback: yourFunction,<br/>
11795     scope: yourObject, //(optional scope)  <br/>
11796     discardUrl: false, <br/>
11797     nocache: false,<br/>
11798     text: "Loading...",<br/>
11799     timeout: 30,<br/>
11800     scripts: false<br/>
11801 });
11802 </code></pre>
11803      * The only required property is url. The optional properties nocache, text and scripts
11804      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11805      * @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}
11806      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11807      * @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.
11808      */
11809     update : function(url, params, callback, discardUrl){
11810         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11811             var method = this.method,
11812                 cfg;
11813             if(typeof url == "object"){ // must be config object
11814                 cfg = url;
11815                 url = cfg.url;
11816                 params = params || cfg.params;
11817                 callback = callback || cfg.callback;
11818                 discardUrl = discardUrl || cfg.discardUrl;
11819                 if(callback && cfg.scope){
11820                     callback = callback.createDelegate(cfg.scope);
11821                 }
11822                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11823                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11824                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11825                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11826                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11827             }
11828             this.showLoading();
11829             if(!discardUrl){
11830                 this.defaultUrl = url;
11831             }
11832             if(typeof url == "function"){
11833                 url = url.call(this);
11834             }
11835
11836             method = method || (params ? "POST" : "GET");
11837             if(method == "GET"){
11838                 url = this.prepareUrl(url);
11839             }
11840
11841             var o = Roo.apply(cfg ||{}, {
11842                 url : url,
11843                 params: params,
11844                 success: this.successDelegate,
11845                 failure: this.failureDelegate,
11846                 callback: undefined,
11847                 timeout: (this.timeout*1000),
11848                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11849             });
11850             Roo.log("updated manager called with timeout of " + o.timeout);
11851             this.transaction = Roo.Ajax.request(o);
11852         }
11853     },
11854
11855     /**
11856      * 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.
11857      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11858      * @param {String/HTMLElement} form The form Id or form element
11859      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11860      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11861      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11862      */
11863     formUpdate : function(form, url, reset, callback){
11864         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11865             if(typeof url == "function"){
11866                 url = url.call(this);
11867             }
11868             form = Roo.getDom(form);
11869             this.transaction = Roo.Ajax.request({
11870                 form: form,
11871                 url:url,
11872                 success: this.successDelegate,
11873                 failure: this.failureDelegate,
11874                 timeout: (this.timeout*1000),
11875                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11876             });
11877             this.showLoading.defer(1, this);
11878         }
11879     },
11880
11881     /**
11882      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11883      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11884      */
11885     refresh : function(callback){
11886         if(this.defaultUrl == null){
11887             return;
11888         }
11889         this.update(this.defaultUrl, null, callback, true);
11890     },
11891
11892     /**
11893      * Set this element to auto refresh.
11894      * @param {Number} interval How often to update (in seconds).
11895      * @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)
11896      * @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}
11897      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11898      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11899      */
11900     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11901         if(refreshNow){
11902             this.update(url || this.defaultUrl, params, callback, true);
11903         }
11904         if(this.autoRefreshProcId){
11905             clearInterval(this.autoRefreshProcId);
11906         }
11907         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11908     },
11909
11910     /**
11911      * Stop auto refresh on this element.
11912      */
11913      stopAutoRefresh : function(){
11914         if(this.autoRefreshProcId){
11915             clearInterval(this.autoRefreshProcId);
11916             delete this.autoRefreshProcId;
11917         }
11918     },
11919
11920     isAutoRefreshing : function(){
11921        return this.autoRefreshProcId ? true : false;
11922     },
11923     /**
11924      * Called to update the element to "Loading" state. Override to perform custom action.
11925      */
11926     showLoading : function(){
11927         if(this.showLoadIndicator){
11928             this.el.update(this.indicatorText);
11929         }
11930     },
11931
11932     /**
11933      * Adds unique parameter to query string if disableCaching = true
11934      * @private
11935      */
11936     prepareUrl : function(url){
11937         if(this.disableCaching){
11938             var append = "_dc=" + (new Date().getTime());
11939             if(url.indexOf("?") !== -1){
11940                 url += "&" + append;
11941             }else{
11942                 url += "?" + append;
11943             }
11944         }
11945         return url;
11946     },
11947
11948     /**
11949      * @private
11950      */
11951     processSuccess : function(response){
11952         this.transaction = null;
11953         if(response.argument.form && response.argument.reset){
11954             try{ // put in try/catch since some older FF releases had problems with this
11955                 response.argument.form.reset();
11956             }catch(e){}
11957         }
11958         if(this.loadScripts){
11959             this.renderer.render(this.el, response, this,
11960                 this.updateComplete.createDelegate(this, [response]));
11961         }else{
11962             this.renderer.render(this.el, response, this);
11963             this.updateComplete(response);
11964         }
11965     },
11966
11967     updateComplete : function(response){
11968         this.fireEvent("update", this.el, response);
11969         if(typeof response.argument.callback == "function"){
11970             response.argument.callback(this.el, true, response);
11971         }
11972     },
11973
11974     /**
11975      * @private
11976      */
11977     processFailure : function(response){
11978         this.transaction = null;
11979         this.fireEvent("failure", this.el, response);
11980         if(typeof response.argument.callback == "function"){
11981             response.argument.callback(this.el, false, response);
11982         }
11983     },
11984
11985     /**
11986      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11987      * @param {Object} renderer The object implementing the render() method
11988      */
11989     setRenderer : function(renderer){
11990         this.renderer = renderer;
11991     },
11992
11993     getRenderer : function(){
11994        return this.renderer;
11995     },
11996
11997     /**
11998      * Set the defaultUrl used for updates
11999      * @param {String/Function} defaultUrl The url or a function to call to get the url
12000      */
12001     setDefaultUrl : function(defaultUrl){
12002         this.defaultUrl = defaultUrl;
12003     },
12004
12005     /**
12006      * Aborts the executing transaction
12007      */
12008     abort : function(){
12009         if(this.transaction){
12010             Roo.Ajax.abort(this.transaction);
12011         }
12012     },
12013
12014     /**
12015      * Returns true if an update is in progress
12016      * @return {Boolean}
12017      */
12018     isUpdating : function(){
12019         if(this.transaction){
12020             return Roo.Ajax.isLoading(this.transaction);
12021         }
12022         return false;
12023     }
12024 });
12025
12026 /**
12027  * @class Roo.UpdateManager.defaults
12028  * @static (not really - but it helps the doc tool)
12029  * The defaults collection enables customizing the default properties of UpdateManager
12030  */
12031    Roo.UpdateManager.defaults = {
12032        /**
12033          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12034          * @type Number
12035          */
12036          timeout : 30,
12037
12038          /**
12039          * True to process scripts by default (Defaults to false).
12040          * @type Boolean
12041          */
12042         loadScripts : false,
12043
12044         /**
12045         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12046         * @type String
12047         */
12048         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12049         /**
12050          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12051          * @type Boolean
12052          */
12053         disableCaching : false,
12054         /**
12055          * Whether to show indicatorText when loading (Defaults to true).
12056          * @type Boolean
12057          */
12058         showLoadIndicator : true,
12059         /**
12060          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12061          * @type String
12062          */
12063         indicatorText : '<div class="loading-indicator">Loading...</div>'
12064    };
12065
12066 /**
12067  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12068  *Usage:
12069  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12070  * @param {String/HTMLElement/Roo.Element} el The element to update
12071  * @param {String} url The url
12072  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12073  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12074  * @static
12075  * @deprecated
12076  * @member Roo.UpdateManager
12077  */
12078 Roo.UpdateManager.updateElement = function(el, url, params, options){
12079     var um = Roo.get(el, true).getUpdateManager();
12080     Roo.apply(um, options);
12081     um.update(url, params, options ? options.callback : null);
12082 };
12083 // alias for backwards compat
12084 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12085 /**
12086  * @class Roo.UpdateManager.BasicRenderer
12087  * Default Content renderer. Updates the elements innerHTML with the responseText.
12088  */
12089 Roo.UpdateManager.BasicRenderer = function(){};
12090
12091 Roo.UpdateManager.BasicRenderer.prototype = {
12092     /**
12093      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12094      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12095      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12096      * @param {Roo.Element} el The element being rendered
12097      * @param {Object} response The YUI Connect response object
12098      * @param {UpdateManager} updateManager The calling update manager
12099      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12100      */
12101      render : function(el, response, updateManager, callback){
12102         el.update(response.responseText, updateManager.loadScripts, callback);
12103     }
12104 };
12105 /*
12106  * Based on:
12107  * Roo JS
12108  * (c)) Alan Knowles
12109  * Licence : LGPL
12110  */
12111
12112
12113 /**
12114  * @class Roo.DomTemplate
12115  * @extends Roo.Template
12116  * An effort at a dom based template engine..
12117  *
12118  * Similar to XTemplate, except it uses dom parsing to create the template..
12119  *
12120  * Supported features:
12121  *
12122  *  Tags:
12123
12124 <pre><code>
12125       {a_variable} - output encoded.
12126       {a_variable.format:("Y-m-d")} - call a method on the variable
12127       {a_variable:raw} - unencoded output
12128       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12129       {a_variable:this.method_on_template(...)} - call a method on the template object.
12130  
12131 </code></pre>
12132  *  The tpl tag:
12133 <pre><code>
12134         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12135         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12136         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12137         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12138   
12139 </code></pre>
12140  *      
12141  */
12142 Roo.DomTemplate = function()
12143 {
12144      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12145      if (this.html) {
12146         this.compile();
12147      }
12148 };
12149
12150
12151 Roo.extend(Roo.DomTemplate, Roo.Template, {
12152     /**
12153      * id counter for sub templates.
12154      */
12155     id : 0,
12156     /**
12157      * flag to indicate if dom parser is inside a pre,
12158      * it will strip whitespace if not.
12159      */
12160     inPre : false,
12161     
12162     /**
12163      * The various sub templates
12164      */
12165     tpls : false,
12166     
12167     
12168     
12169     /**
12170      *
12171      * basic tag replacing syntax
12172      * WORD:WORD()
12173      *
12174      * // you can fake an object call by doing this
12175      *  x.t:(test,tesT) 
12176      * 
12177      */
12178     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12179     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12180     
12181     iterChild : function (node, method) {
12182         
12183         var oldPre = this.inPre;
12184         if (node.tagName == 'PRE') {
12185             this.inPre = true;
12186         }
12187         for( var i = 0; i < node.childNodes.length; i++) {
12188             method.call(this, node.childNodes[i]);
12189         }
12190         this.inPre = oldPre;
12191     },
12192     
12193     
12194     
12195     /**
12196      * compile the template
12197      *
12198      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12199      *
12200      */
12201     compile: function()
12202     {
12203         var s = this.html;
12204         
12205         // covert the html into DOM...
12206         var doc = false;
12207         var div =false;
12208         try {
12209             doc = document.implementation.createHTMLDocument("");
12210             doc.documentElement.innerHTML =   this.html  ;
12211             div = doc.documentElement;
12212         } catch (e) {
12213             // old IE... - nasty -- it causes all sorts of issues.. with
12214             // images getting pulled from server..
12215             div = document.createElement('div');
12216             div.innerHTML = this.html;
12217         }
12218         //doc.documentElement.innerHTML = htmlBody
12219          
12220         
12221         
12222         this.tpls = [];
12223         var _t = this;
12224         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12225         
12226         var tpls = this.tpls;
12227         
12228         // create a top level template from the snippet..
12229         
12230         //Roo.log(div.innerHTML);
12231         
12232         var tpl = {
12233             uid : 'master',
12234             id : this.id++,
12235             attr : false,
12236             value : false,
12237             body : div.innerHTML,
12238             
12239             forCall : false,
12240             execCall : false,
12241             dom : div,
12242             isTop : true
12243             
12244         };
12245         tpls.unshift(tpl);
12246         
12247         
12248         // compile them...
12249         this.tpls = [];
12250         Roo.each(tpls, function(tp){
12251             this.compileTpl(tp);
12252             this.tpls[tp.id] = tp;
12253         }, this);
12254         
12255         this.master = tpls[0];
12256         return this;
12257         
12258         
12259     },
12260     
12261     compileNode : function(node, istop) {
12262         // test for
12263         //Roo.log(node);
12264         
12265         
12266         // skip anything not a tag..
12267         if (node.nodeType != 1) {
12268             if (node.nodeType == 3 && !this.inPre) {
12269                 // reduce white space..
12270                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12271                 
12272             }
12273             return;
12274         }
12275         
12276         var tpl = {
12277             uid : false,
12278             id : false,
12279             attr : false,
12280             value : false,
12281             body : '',
12282             
12283             forCall : false,
12284             execCall : false,
12285             dom : false,
12286             isTop : istop
12287             
12288             
12289         };
12290         
12291         
12292         switch(true) {
12293             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12294             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12295             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12296             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12297             // no default..
12298         }
12299         
12300         
12301         if (!tpl.attr) {
12302             // just itterate children..
12303             this.iterChild(node,this.compileNode);
12304             return;
12305         }
12306         tpl.uid = this.id++;
12307         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12308         node.removeAttribute('roo-'+ tpl.attr);
12309         if (tpl.attr != 'name') {
12310             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12311             node.parentNode.replaceChild(placeholder,  node);
12312         } else {
12313             
12314             var placeholder =  document.createElement('span');
12315             placeholder.className = 'roo-tpl-' + tpl.value;
12316             node.parentNode.replaceChild(placeholder,  node);
12317         }
12318         
12319         // parent now sees '{domtplXXXX}
12320         this.iterChild(node,this.compileNode);
12321         
12322         // we should now have node body...
12323         var div = document.createElement('div');
12324         div.appendChild(node);
12325         tpl.dom = node;
12326         // this has the unfortunate side effect of converting tagged attributes
12327         // eg. href="{...}" into %7C...%7D
12328         // this has been fixed by searching for those combo's although it's a bit hacky..
12329         
12330         
12331         tpl.body = div.innerHTML;
12332         
12333         
12334          
12335         tpl.id = tpl.uid;
12336         switch(tpl.attr) {
12337             case 'for' :
12338                 switch (tpl.value) {
12339                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12340                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12341                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12342                 }
12343                 break;
12344             
12345             case 'exec':
12346                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12347                 break;
12348             
12349             case 'if':     
12350                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12351                 break;
12352             
12353             case 'name':
12354                 tpl.id  = tpl.value; // replace non characters???
12355                 break;
12356             
12357         }
12358         
12359         
12360         this.tpls.push(tpl);
12361         
12362         
12363         
12364     },
12365     
12366     
12367     
12368     
12369     /**
12370      * Compile a segment of the template into a 'sub-template'
12371      *
12372      * 
12373      * 
12374      *
12375      */
12376     compileTpl : function(tpl)
12377     {
12378         var fm = Roo.util.Format;
12379         var useF = this.disableFormats !== true;
12380         
12381         var sep = Roo.isGecko ? "+\n" : ",\n";
12382         
12383         var undef = function(str) {
12384             Roo.debug && Roo.log("Property not found :"  + str);
12385             return '';
12386         };
12387           
12388         //Roo.log(tpl.body);
12389         
12390         
12391         
12392         var fn = function(m, lbrace, name, format, args)
12393         {
12394             //Roo.log("ARGS");
12395             //Roo.log(arguments);
12396             args = args ? args.replace(/\\'/g,"'") : args;
12397             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12398             if (typeof(format) == 'undefined') {
12399                 format =  'htmlEncode'; 
12400             }
12401             if (format == 'raw' ) {
12402                 format = false;
12403             }
12404             
12405             if(name.substr(0, 6) == 'domtpl'){
12406                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12407             }
12408             
12409             // build an array of options to determine if value is undefined..
12410             
12411             // basically get 'xxxx.yyyy' then do
12412             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12413             //    (function () { Roo.log("Property not found"); return ''; })() :
12414             //    ......
12415             
12416             var udef_ar = [];
12417             var lookfor = '';
12418             Roo.each(name.split('.'), function(st) {
12419                 lookfor += (lookfor.length ? '.': '') + st;
12420                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12421             });
12422             
12423             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12424             
12425             
12426             if(format && useF){
12427                 
12428                 args = args ? ',' + args : "";
12429                  
12430                 if(format.substr(0, 5) != "this."){
12431                     format = "fm." + format + '(';
12432                 }else{
12433                     format = 'this.call("'+ format.substr(5) + '", ';
12434                     args = ", values";
12435                 }
12436                 
12437                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12438             }
12439              
12440             if (args && args.length) {
12441                 // called with xxyx.yuu:(test,test)
12442                 // change to ()
12443                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12444             }
12445             // raw.. - :raw modifier..
12446             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12447             
12448         };
12449         var body;
12450         // branched to use + in gecko and [].join() in others
12451         if(Roo.isGecko){
12452             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12453                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12454                     "';};};";
12455         }else{
12456             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12457             body.push(tpl.body.replace(/(\r\n|\n)/g,
12458                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12459             body.push("'].join('');};};");
12460             body = body.join('');
12461         }
12462         
12463         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12464        
12465         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12466         eval(body);
12467         
12468         return this;
12469     },
12470      
12471     /**
12472      * same as applyTemplate, except it's done to one of the subTemplates
12473      * when using named templates, you can do:
12474      *
12475      * var str = pl.applySubTemplate('your-name', values);
12476      *
12477      * 
12478      * @param {Number} id of the template
12479      * @param {Object} values to apply to template
12480      * @param {Object} parent (normaly the instance of this object)
12481      */
12482     applySubTemplate : function(id, values, parent)
12483     {
12484         
12485         
12486         var t = this.tpls[id];
12487         
12488         
12489         try { 
12490             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12491                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12492                 return '';
12493             }
12494         } catch(e) {
12495             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12496             Roo.log(values);
12497           
12498             return '';
12499         }
12500         try { 
12501             
12502             if(t.execCall && t.execCall.call(this, values, parent)){
12503                 return '';
12504             }
12505         } catch(e) {
12506             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12507             Roo.log(values);
12508             return '';
12509         }
12510         
12511         try {
12512             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12513             parent = t.target ? values : parent;
12514             if(t.forCall && vs instanceof Array){
12515                 var buf = [];
12516                 for(var i = 0, len = vs.length; i < len; i++){
12517                     try {
12518                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12519                     } catch (e) {
12520                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12521                         Roo.log(e.body);
12522                         //Roo.log(t.compiled);
12523                         Roo.log(vs[i]);
12524                     }   
12525                 }
12526                 return buf.join('');
12527             }
12528         } catch (e) {
12529             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12530             Roo.log(values);
12531             return '';
12532         }
12533         try {
12534             return t.compiled.call(this, vs, parent);
12535         } catch (e) {
12536             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12537             Roo.log(e.body);
12538             //Roo.log(t.compiled);
12539             Roo.log(values);
12540             return '';
12541         }
12542     },
12543
12544    
12545
12546     applyTemplate : function(values){
12547         return this.master.compiled.call(this, values, {});
12548         //var s = this.subs;
12549     },
12550
12551     apply : function(){
12552         return this.applyTemplate.apply(this, arguments);
12553     }
12554
12555  });
12556
12557 Roo.DomTemplate.from = function(el){
12558     el = Roo.getDom(el);
12559     return new Roo.Domtemplate(el.value || el.innerHTML);
12560 };/*
12561  * Based on:
12562  * Ext JS Library 1.1.1
12563  * Copyright(c) 2006-2007, Ext JS, LLC.
12564  *
12565  * Originally Released Under LGPL - original licence link has changed is not relivant.
12566  *
12567  * Fork - LGPL
12568  * <script type="text/javascript">
12569  */
12570
12571 /**
12572  * @class Roo.util.DelayedTask
12573  * Provides a convenient method of performing setTimeout where a new
12574  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12575  * You can use this class to buffer
12576  * the keypress events for a certain number of milliseconds, and perform only if they stop
12577  * for that amount of time.
12578  * @constructor The parameters to this constructor serve as defaults and are not required.
12579  * @param {Function} fn (optional) The default function to timeout
12580  * @param {Object} scope (optional) The default scope of that timeout
12581  * @param {Array} args (optional) The default Array of arguments
12582  */
12583 Roo.util.DelayedTask = function(fn, scope, args){
12584     var id = null, d, t;
12585
12586     var call = function(){
12587         var now = new Date().getTime();
12588         if(now - t >= d){
12589             clearInterval(id);
12590             id = null;
12591             fn.apply(scope, args || []);
12592         }
12593     };
12594     /**
12595      * Cancels any pending timeout and queues a new one
12596      * @param {Number} delay The milliseconds to delay
12597      * @param {Function} newFn (optional) Overrides function passed to constructor
12598      * @param {Object} newScope (optional) Overrides scope passed to constructor
12599      * @param {Array} newArgs (optional) Overrides args passed to constructor
12600      */
12601     this.delay = function(delay, newFn, newScope, newArgs){
12602         if(id && delay != d){
12603             this.cancel();
12604         }
12605         d = delay;
12606         t = new Date().getTime();
12607         fn = newFn || fn;
12608         scope = newScope || scope;
12609         args = newArgs || args;
12610         if(!id){
12611             id = setInterval(call, d);
12612         }
12613     };
12614
12615     /**
12616      * Cancel the last queued timeout
12617      */
12618     this.cancel = function(){
12619         if(id){
12620             clearInterval(id);
12621             id = null;
12622         }
12623     };
12624 };/*
12625  * Based on:
12626  * Ext JS Library 1.1.1
12627  * Copyright(c) 2006-2007, Ext JS, LLC.
12628  *
12629  * Originally Released Under LGPL - original licence link has changed is not relivant.
12630  *
12631  * Fork - LGPL
12632  * <script type="text/javascript">
12633  */
12634  
12635  
12636 Roo.util.TaskRunner = function(interval){
12637     interval = interval || 10;
12638     var tasks = [], removeQueue = [];
12639     var id = 0;
12640     var running = false;
12641
12642     var stopThread = function(){
12643         running = false;
12644         clearInterval(id);
12645         id = 0;
12646     };
12647
12648     var startThread = function(){
12649         if(!running){
12650             running = true;
12651             id = setInterval(runTasks, interval);
12652         }
12653     };
12654
12655     var removeTask = function(task){
12656         removeQueue.push(task);
12657         if(task.onStop){
12658             task.onStop();
12659         }
12660     };
12661
12662     var runTasks = function(){
12663         if(removeQueue.length > 0){
12664             for(var i = 0, len = removeQueue.length; i < len; i++){
12665                 tasks.remove(removeQueue[i]);
12666             }
12667             removeQueue = [];
12668             if(tasks.length < 1){
12669                 stopThread();
12670                 return;
12671             }
12672         }
12673         var now = new Date().getTime();
12674         for(var i = 0, len = tasks.length; i < len; ++i){
12675             var t = tasks[i];
12676             var itime = now - t.taskRunTime;
12677             if(t.interval <= itime){
12678                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12679                 t.taskRunTime = now;
12680                 if(rt === false || t.taskRunCount === t.repeat){
12681                     removeTask(t);
12682                     return;
12683                 }
12684             }
12685             if(t.duration && t.duration <= (now - t.taskStartTime)){
12686                 removeTask(t);
12687             }
12688         }
12689     };
12690
12691     /**
12692      * Queues a new task.
12693      * @param {Object} task
12694      */
12695     this.start = function(task){
12696         tasks.push(task);
12697         task.taskStartTime = new Date().getTime();
12698         task.taskRunTime = 0;
12699         task.taskRunCount = 0;
12700         startThread();
12701         return task;
12702     };
12703
12704     this.stop = function(task){
12705         removeTask(task);
12706         return task;
12707     };
12708
12709     this.stopAll = function(){
12710         stopThread();
12711         for(var i = 0, len = tasks.length; i < len; i++){
12712             if(tasks[i].onStop){
12713                 tasks[i].onStop();
12714             }
12715         }
12716         tasks = [];
12717         removeQueue = [];
12718     };
12719 };
12720
12721 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12722  * Based on:
12723  * Ext JS Library 1.1.1
12724  * Copyright(c) 2006-2007, Ext JS, LLC.
12725  *
12726  * Originally Released Under LGPL - original licence link has changed is not relivant.
12727  *
12728  * Fork - LGPL
12729  * <script type="text/javascript">
12730  */
12731
12732  
12733 /**
12734  * @class Roo.util.MixedCollection
12735  * @extends Roo.util.Observable
12736  * A Collection class that maintains both numeric indexes and keys and exposes events.
12737  * @constructor
12738  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12739  * collection (defaults to false)
12740  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12741  * and return the key value for that item.  This is used when available to look up the key on items that
12742  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12743  * equivalent to providing an implementation for the {@link #getKey} method.
12744  */
12745 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12746     this.items = [];
12747     this.map = {};
12748     this.keys = [];
12749     this.length = 0;
12750     this.addEvents({
12751         /**
12752          * @event clear
12753          * Fires when the collection is cleared.
12754          */
12755         "clear" : true,
12756         /**
12757          * @event add
12758          * Fires when an item is added to the collection.
12759          * @param {Number} index The index at which the item was added.
12760          * @param {Object} o The item added.
12761          * @param {String} key The key associated with the added item.
12762          */
12763         "add" : true,
12764         /**
12765          * @event replace
12766          * Fires when an item is replaced in the collection.
12767          * @param {String} key he key associated with the new added.
12768          * @param {Object} old The item being replaced.
12769          * @param {Object} new The new item.
12770          */
12771         "replace" : true,
12772         /**
12773          * @event remove
12774          * Fires when an item is removed from the collection.
12775          * @param {Object} o The item being removed.
12776          * @param {String} key (optional) The key associated with the removed item.
12777          */
12778         "remove" : true,
12779         "sort" : true
12780     });
12781     this.allowFunctions = allowFunctions === true;
12782     if(keyFn){
12783         this.getKey = keyFn;
12784     }
12785     Roo.util.MixedCollection.superclass.constructor.call(this);
12786 };
12787
12788 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12789     allowFunctions : false,
12790     
12791 /**
12792  * Adds an item to the collection.
12793  * @param {String} key The key to associate with the item
12794  * @param {Object} o The item to add.
12795  * @return {Object} The item added.
12796  */
12797     add : function(key, o){
12798         if(arguments.length == 1){
12799             o = arguments[0];
12800             key = this.getKey(o);
12801         }
12802         if(typeof key == "undefined" || key === null){
12803             this.length++;
12804             this.items.push(o);
12805             this.keys.push(null);
12806         }else{
12807             var old = this.map[key];
12808             if(old){
12809                 return this.replace(key, o);
12810             }
12811             this.length++;
12812             this.items.push(o);
12813             this.map[key] = o;
12814             this.keys.push(key);
12815         }
12816         this.fireEvent("add", this.length-1, o, key);
12817         return o;
12818     },
12819        
12820 /**
12821   * MixedCollection has a generic way to fetch keys if you implement getKey.
12822 <pre><code>
12823 // normal way
12824 var mc = new Roo.util.MixedCollection();
12825 mc.add(someEl.dom.id, someEl);
12826 mc.add(otherEl.dom.id, otherEl);
12827 //and so on
12828
12829 // using getKey
12830 var mc = new Roo.util.MixedCollection();
12831 mc.getKey = function(el){
12832    return el.dom.id;
12833 };
12834 mc.add(someEl);
12835 mc.add(otherEl);
12836
12837 // or via the constructor
12838 var mc = new Roo.util.MixedCollection(false, function(el){
12839    return el.dom.id;
12840 });
12841 mc.add(someEl);
12842 mc.add(otherEl);
12843 </code></pre>
12844  * @param o {Object} The item for which to find the key.
12845  * @return {Object} The key for the passed item.
12846  */
12847     getKey : function(o){
12848          return o.id; 
12849     },
12850    
12851 /**
12852  * Replaces an item in the collection.
12853  * @param {String} key The key associated with the item to replace, or the item to replace.
12854  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12855  * @return {Object}  The new item.
12856  */
12857     replace : function(key, o){
12858         if(arguments.length == 1){
12859             o = arguments[0];
12860             key = this.getKey(o);
12861         }
12862         var old = this.item(key);
12863         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12864              return this.add(key, o);
12865         }
12866         var index = this.indexOfKey(key);
12867         this.items[index] = o;
12868         this.map[key] = o;
12869         this.fireEvent("replace", key, old, o);
12870         return o;
12871     },
12872    
12873 /**
12874  * Adds all elements of an Array or an Object to the collection.
12875  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12876  * an Array of values, each of which are added to the collection.
12877  */
12878     addAll : function(objs){
12879         if(arguments.length > 1 || objs instanceof Array){
12880             var args = arguments.length > 1 ? arguments : objs;
12881             for(var i = 0, len = args.length; i < len; i++){
12882                 this.add(args[i]);
12883             }
12884         }else{
12885             for(var key in objs){
12886                 if(this.allowFunctions || typeof objs[key] != "function"){
12887                     this.add(key, objs[key]);
12888                 }
12889             }
12890         }
12891     },
12892    
12893 /**
12894  * Executes the specified function once for every item in the collection, passing each
12895  * item as the first and only parameter. returning false from the function will stop the iteration.
12896  * @param {Function} fn The function to execute for each item.
12897  * @param {Object} scope (optional) The scope in which to execute the function.
12898  */
12899     each : function(fn, scope){
12900         var items = [].concat(this.items); // each safe for removal
12901         for(var i = 0, len = items.length; i < len; i++){
12902             if(fn.call(scope || items[i], items[i], i, len) === false){
12903                 break;
12904             }
12905         }
12906     },
12907    
12908 /**
12909  * Executes the specified function once for every key in the collection, passing each
12910  * key, and its associated item as the first two parameters.
12911  * @param {Function} fn The function to execute for each item.
12912  * @param {Object} scope (optional) The scope in which to execute the function.
12913  */
12914     eachKey : function(fn, scope){
12915         for(var i = 0, len = this.keys.length; i < len; i++){
12916             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12917         }
12918     },
12919    
12920 /**
12921  * Returns the first item in the collection which elicits a true return value from the
12922  * passed selection function.
12923  * @param {Function} fn The selection function to execute for each item.
12924  * @param {Object} scope (optional) The scope in which to execute the function.
12925  * @return {Object} The first item in the collection which returned true from the selection function.
12926  */
12927     find : function(fn, scope){
12928         for(var i = 0, len = this.items.length; i < len; i++){
12929             if(fn.call(scope || window, this.items[i], this.keys[i])){
12930                 return this.items[i];
12931             }
12932         }
12933         return null;
12934     },
12935    
12936 /**
12937  * Inserts an item at the specified index in the collection.
12938  * @param {Number} index The index to insert the item at.
12939  * @param {String} key The key to associate with the new item, or the item itself.
12940  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12941  * @return {Object} The item inserted.
12942  */
12943     insert : function(index, key, o){
12944         if(arguments.length == 2){
12945             o = arguments[1];
12946             key = this.getKey(o);
12947         }
12948         if(index >= this.length){
12949             return this.add(key, o);
12950         }
12951         this.length++;
12952         this.items.splice(index, 0, o);
12953         if(typeof key != "undefined" && key != null){
12954             this.map[key] = o;
12955         }
12956         this.keys.splice(index, 0, key);
12957         this.fireEvent("add", index, o, key);
12958         return o;
12959     },
12960    
12961 /**
12962  * Removed an item from the collection.
12963  * @param {Object} o The item to remove.
12964  * @return {Object} The item removed.
12965  */
12966     remove : function(o){
12967         return this.removeAt(this.indexOf(o));
12968     },
12969    
12970 /**
12971  * Remove an item from a specified index in the collection.
12972  * @param {Number} index The index within the collection of the item to remove.
12973  */
12974     removeAt : function(index){
12975         if(index < this.length && index >= 0){
12976             this.length--;
12977             var o = this.items[index];
12978             this.items.splice(index, 1);
12979             var key = this.keys[index];
12980             if(typeof key != "undefined"){
12981                 delete this.map[key];
12982             }
12983             this.keys.splice(index, 1);
12984             this.fireEvent("remove", o, key);
12985         }
12986     },
12987    
12988 /**
12989  * Removed an item associated with the passed key fom the collection.
12990  * @param {String} key The key of the item to remove.
12991  */
12992     removeKey : function(key){
12993         return this.removeAt(this.indexOfKey(key));
12994     },
12995    
12996 /**
12997  * Returns the number of items in the collection.
12998  * @return {Number} the number of items in the collection.
12999  */
13000     getCount : function(){
13001         return this.length; 
13002     },
13003    
13004 /**
13005  * Returns index within the collection of the passed Object.
13006  * @param {Object} o The item to find the index of.
13007  * @return {Number} index of the item.
13008  */
13009     indexOf : function(o){
13010         if(!this.items.indexOf){
13011             for(var i = 0, len = this.items.length; i < len; i++){
13012                 if(this.items[i] == o) return i;
13013             }
13014             return -1;
13015         }else{
13016             return this.items.indexOf(o);
13017         }
13018     },
13019    
13020 /**
13021  * Returns index within the collection of the passed key.
13022  * @param {String} key The key to find the index of.
13023  * @return {Number} index of the key.
13024  */
13025     indexOfKey : function(key){
13026         if(!this.keys.indexOf){
13027             for(var i = 0, len = this.keys.length; i < len; i++){
13028                 if(this.keys[i] == key) return i;
13029             }
13030             return -1;
13031         }else{
13032             return this.keys.indexOf(key);
13033         }
13034     },
13035    
13036 /**
13037  * Returns the item associated with the passed key OR index. Key has priority over index.
13038  * @param {String/Number} key The key or index of the item.
13039  * @return {Object} The item associated with the passed key.
13040  */
13041     item : function(key){
13042         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13043         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13044     },
13045     
13046 /**
13047  * Returns the item at the specified index.
13048  * @param {Number} index The index of the item.
13049  * @return {Object}
13050  */
13051     itemAt : function(index){
13052         return this.items[index];
13053     },
13054     
13055 /**
13056  * Returns the item associated with the passed key.
13057  * @param {String/Number} key The key of the item.
13058  * @return {Object} The item associated with the passed key.
13059  */
13060     key : function(key){
13061         return this.map[key];
13062     },
13063    
13064 /**
13065  * Returns true if the collection contains the passed Object as an item.
13066  * @param {Object} o  The Object to look for in the collection.
13067  * @return {Boolean} True if the collection contains the Object as an item.
13068  */
13069     contains : function(o){
13070         return this.indexOf(o) != -1;
13071     },
13072    
13073 /**
13074  * Returns true if the collection contains the passed Object as a key.
13075  * @param {String} key The key to look for in the collection.
13076  * @return {Boolean} True if the collection contains the Object as a key.
13077  */
13078     containsKey : function(key){
13079         return typeof this.map[key] != "undefined";
13080     },
13081    
13082 /**
13083  * Removes all items from the collection.
13084  */
13085     clear : function(){
13086         this.length = 0;
13087         this.items = [];
13088         this.keys = [];
13089         this.map = {};
13090         this.fireEvent("clear");
13091     },
13092    
13093 /**
13094  * Returns the first item in the collection.
13095  * @return {Object} the first item in the collection..
13096  */
13097     first : function(){
13098         return this.items[0]; 
13099     },
13100    
13101 /**
13102  * Returns the last item in the collection.
13103  * @return {Object} the last item in the collection..
13104  */
13105     last : function(){
13106         return this.items[this.length-1];   
13107     },
13108     
13109     _sort : function(property, dir, fn){
13110         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13111         fn = fn || function(a, b){
13112             return a-b;
13113         };
13114         var c = [], k = this.keys, items = this.items;
13115         for(var i = 0, len = items.length; i < len; i++){
13116             c[c.length] = {key: k[i], value: items[i], index: i};
13117         }
13118         c.sort(function(a, b){
13119             var v = fn(a[property], b[property]) * dsc;
13120             if(v == 0){
13121                 v = (a.index < b.index ? -1 : 1);
13122             }
13123             return v;
13124         });
13125         for(var i = 0, len = c.length; i < len; i++){
13126             items[i] = c[i].value;
13127             k[i] = c[i].key;
13128         }
13129         this.fireEvent("sort", this);
13130     },
13131     
13132     /**
13133      * Sorts this collection with the passed comparison function
13134      * @param {String} direction (optional) "ASC" or "DESC"
13135      * @param {Function} fn (optional) comparison function
13136      */
13137     sort : function(dir, fn){
13138         this._sort("value", dir, fn);
13139     },
13140     
13141     /**
13142      * Sorts this collection by keys
13143      * @param {String} direction (optional) "ASC" or "DESC"
13144      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13145      */
13146     keySort : function(dir, fn){
13147         this._sort("key", dir, fn || function(a, b){
13148             return String(a).toUpperCase()-String(b).toUpperCase();
13149         });
13150     },
13151     
13152     /**
13153      * Returns a range of items in this collection
13154      * @param {Number} startIndex (optional) defaults to 0
13155      * @param {Number} endIndex (optional) default to the last item
13156      * @return {Array} An array of items
13157      */
13158     getRange : function(start, end){
13159         var items = this.items;
13160         if(items.length < 1){
13161             return [];
13162         }
13163         start = start || 0;
13164         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13165         var r = [];
13166         if(start <= end){
13167             for(var i = start; i <= end; i++) {
13168                     r[r.length] = items[i];
13169             }
13170         }else{
13171             for(var i = start; i >= end; i--) {
13172                     r[r.length] = items[i];
13173             }
13174         }
13175         return r;
13176     },
13177         
13178     /**
13179      * Filter the <i>objects</i> in this collection by a specific property. 
13180      * Returns a new collection that has been filtered.
13181      * @param {String} property A property on your objects
13182      * @param {String/RegExp} value Either string that the property values 
13183      * should start with or a RegExp to test against the property
13184      * @return {MixedCollection} The new filtered collection
13185      */
13186     filter : function(property, value){
13187         if(!value.exec){ // not a regex
13188             value = String(value);
13189             if(value.length == 0){
13190                 return this.clone();
13191             }
13192             value = new RegExp("^" + Roo.escapeRe(value), "i");
13193         }
13194         return this.filterBy(function(o){
13195             return o && value.test(o[property]);
13196         });
13197         },
13198     
13199     /**
13200      * Filter by a function. * Returns a new collection that has been filtered.
13201      * The passed function will be called with each 
13202      * object in the collection. If the function returns true, the value is included 
13203      * otherwise it is filtered.
13204      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13205      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13206      * @return {MixedCollection} The new filtered collection
13207      */
13208     filterBy : function(fn, scope){
13209         var r = new Roo.util.MixedCollection();
13210         r.getKey = this.getKey;
13211         var k = this.keys, it = this.items;
13212         for(var i = 0, len = it.length; i < len; i++){
13213             if(fn.call(scope||this, it[i], k[i])){
13214                                 r.add(k[i], it[i]);
13215                         }
13216         }
13217         return r;
13218     },
13219     
13220     /**
13221      * Creates a duplicate of this collection
13222      * @return {MixedCollection}
13223      */
13224     clone : function(){
13225         var r = new Roo.util.MixedCollection();
13226         var k = this.keys, it = this.items;
13227         for(var i = 0, len = it.length; i < len; i++){
13228             r.add(k[i], it[i]);
13229         }
13230         r.getKey = this.getKey;
13231         return r;
13232     }
13233 });
13234 /**
13235  * Returns the item associated with the passed key or index.
13236  * @method
13237  * @param {String/Number} key The key or index of the item.
13238  * @return {Object} The item associated with the passed key.
13239  */
13240 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13241  * Based on:
13242  * Ext JS Library 1.1.1
13243  * Copyright(c) 2006-2007, Ext JS, LLC.
13244  *
13245  * Originally Released Under LGPL - original licence link has changed is not relivant.
13246  *
13247  * Fork - LGPL
13248  * <script type="text/javascript">
13249  */
13250 /**
13251  * @class Roo.util.JSON
13252  * Modified version of Douglas Crockford"s json.js that doesn"t
13253  * mess with the Object prototype 
13254  * http://www.json.org/js.html
13255  * @singleton
13256  */
13257 Roo.util.JSON = new (function(){
13258     var useHasOwn = {}.hasOwnProperty ? true : false;
13259     
13260     // crashes Safari in some instances
13261     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13262     
13263     var pad = function(n) {
13264         return n < 10 ? "0" + n : n;
13265     };
13266     
13267     var m = {
13268         "\b": '\\b',
13269         "\t": '\\t',
13270         "\n": '\\n',
13271         "\f": '\\f',
13272         "\r": '\\r',
13273         '"' : '\\"',
13274         "\\": '\\\\'
13275     };
13276
13277     var encodeString = function(s){
13278         if (/["\\\x00-\x1f]/.test(s)) {
13279             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13280                 var c = m[b];
13281                 if(c){
13282                     return c;
13283                 }
13284                 c = b.charCodeAt();
13285                 return "\\u00" +
13286                     Math.floor(c / 16).toString(16) +
13287                     (c % 16).toString(16);
13288             }) + '"';
13289         }
13290         return '"' + s + '"';
13291     };
13292     
13293     var encodeArray = function(o){
13294         var a = ["["], b, i, l = o.length, v;
13295             for (i = 0; i < l; i += 1) {
13296                 v = o[i];
13297                 switch (typeof v) {
13298                     case "undefined":
13299                     case "function":
13300                     case "unknown":
13301                         break;
13302                     default:
13303                         if (b) {
13304                             a.push(',');
13305                         }
13306                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13307                         b = true;
13308                 }
13309             }
13310             a.push("]");
13311             return a.join("");
13312     };
13313     
13314     var encodeDate = function(o){
13315         return '"' + o.getFullYear() + "-" +
13316                 pad(o.getMonth() + 1) + "-" +
13317                 pad(o.getDate()) + "T" +
13318                 pad(o.getHours()) + ":" +
13319                 pad(o.getMinutes()) + ":" +
13320                 pad(o.getSeconds()) + '"';
13321     };
13322     
13323     /**
13324      * Encodes an Object, Array or other value
13325      * @param {Mixed} o The variable to encode
13326      * @return {String} The JSON string
13327      */
13328     this.encode = function(o)
13329     {
13330         // should this be extended to fully wrap stringify..
13331         
13332         if(typeof o == "undefined" || o === null){
13333             return "null";
13334         }else if(o instanceof Array){
13335             return encodeArray(o);
13336         }else if(o instanceof Date){
13337             return encodeDate(o);
13338         }else if(typeof o == "string"){
13339             return encodeString(o);
13340         }else if(typeof o == "number"){
13341             return isFinite(o) ? String(o) : "null";
13342         }else if(typeof o == "boolean"){
13343             return String(o);
13344         }else {
13345             var a = ["{"], b, i, v;
13346             for (i in o) {
13347                 if(!useHasOwn || o.hasOwnProperty(i)) {
13348                     v = o[i];
13349                     switch (typeof v) {
13350                     case "undefined":
13351                     case "function":
13352                     case "unknown":
13353                         break;
13354                     default:
13355                         if(b){
13356                             a.push(',');
13357                         }
13358                         a.push(this.encode(i), ":",
13359                                 v === null ? "null" : this.encode(v));
13360                         b = true;
13361                     }
13362                 }
13363             }
13364             a.push("}");
13365             return a.join("");
13366         }
13367     };
13368     
13369     /**
13370      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13371      * @param {String} json The JSON string
13372      * @return {Object} The resulting object
13373      */
13374     this.decode = function(json){
13375         
13376         return  /** eval:var:json */ eval("(" + json + ')');
13377     };
13378 })();
13379 /** 
13380  * Shorthand for {@link Roo.util.JSON#encode}
13381  * @member Roo encode 
13382  * @method */
13383 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13384 /** 
13385  * Shorthand for {@link Roo.util.JSON#decode}
13386  * @member Roo decode 
13387  * @method */
13388 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13389 /*
13390  * Based on:
13391  * Ext JS Library 1.1.1
13392  * Copyright(c) 2006-2007, Ext JS, LLC.
13393  *
13394  * Originally Released Under LGPL - original licence link has changed is not relivant.
13395  *
13396  * Fork - LGPL
13397  * <script type="text/javascript">
13398  */
13399  
13400 /**
13401  * @class Roo.util.Format
13402  * Reusable data formatting functions
13403  * @singleton
13404  */
13405 Roo.util.Format = function(){
13406     var trimRe = /^\s+|\s+$/g;
13407     return {
13408         /**
13409          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13410          * @param {String} value The string to truncate
13411          * @param {Number} length The maximum length to allow before truncating
13412          * @return {String} The converted text
13413          */
13414         ellipsis : function(value, len){
13415             if(value && value.length > len){
13416                 return value.substr(0, len-3)+"...";
13417             }
13418             return value;
13419         },
13420
13421         /**
13422          * Checks a reference and converts it to empty string if it is undefined
13423          * @param {Mixed} value Reference to check
13424          * @return {Mixed} Empty string if converted, otherwise the original value
13425          */
13426         undef : function(value){
13427             return typeof value != "undefined" ? value : "";
13428         },
13429
13430         /**
13431          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13432          * @param {String} value The string to encode
13433          * @return {String} The encoded text
13434          */
13435         htmlEncode : function(value){
13436             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13437         },
13438
13439         /**
13440          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13441          * @param {String} value The string to decode
13442          * @return {String} The decoded text
13443          */
13444         htmlDecode : function(value){
13445             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13446         },
13447
13448         /**
13449          * Trims any whitespace from either side of a string
13450          * @param {String} value The text to trim
13451          * @return {String} The trimmed text
13452          */
13453         trim : function(value){
13454             return String(value).replace(trimRe, "");
13455         },
13456
13457         /**
13458          * Returns a substring from within an original string
13459          * @param {String} value The original text
13460          * @param {Number} start The start index of the substring
13461          * @param {Number} length The length of the substring
13462          * @return {String} The substring
13463          */
13464         substr : function(value, start, length){
13465             return String(value).substr(start, length);
13466         },
13467
13468         /**
13469          * Converts a string to all lower case letters
13470          * @param {String} value The text to convert
13471          * @return {String} The converted text
13472          */
13473         lowercase : function(value){
13474             return String(value).toLowerCase();
13475         },
13476
13477         /**
13478          * Converts a string to all upper case letters
13479          * @param {String} value The text to convert
13480          * @return {String} The converted text
13481          */
13482         uppercase : function(value){
13483             return String(value).toUpperCase();
13484         },
13485
13486         /**
13487          * Converts the first character only of a string to upper case
13488          * @param {String} value The text to convert
13489          * @return {String} The converted text
13490          */
13491         capitalize : function(value){
13492             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13493         },
13494
13495         // private
13496         call : function(value, fn){
13497             if(arguments.length > 2){
13498                 var args = Array.prototype.slice.call(arguments, 2);
13499                 args.unshift(value);
13500                  
13501                 return /** eval:var:value */  eval(fn).apply(window, args);
13502             }else{
13503                 /** eval:var:value */
13504                 return /** eval:var:value */ eval(fn).call(window, value);
13505             }
13506         },
13507
13508        
13509         /**
13510          * safer version of Math.toFixed..??/
13511          * @param {Number/String} value The numeric value to format
13512          * @param {Number/String} value Decimal places 
13513          * @return {String} The formatted currency string
13514          */
13515         toFixed : function(v, n)
13516         {
13517             // why not use to fixed - precision is buggered???
13518             if (!n) {
13519                 return Math.round(v-0);
13520             }
13521             var fact = Math.pow(10,n+1);
13522             v = (Math.round((v-0)*fact))/fact;
13523             var z = (''+fact).substring(2);
13524             if (v == Math.floor(v)) {
13525                 return Math.floor(v) + '.' + z;
13526             }
13527             
13528             // now just padd decimals..
13529             var ps = String(v).split('.');
13530             var fd = (ps[1] + z);
13531             var r = fd.substring(0,n); 
13532             var rm = fd.substring(n); 
13533             if (rm < 5) {
13534                 return ps[0] + '.' + r;
13535             }
13536             r*=1; // turn it into a number;
13537             r++;
13538             if (String(r).length != n) {
13539                 ps[0]*=1;
13540                 ps[0]++;
13541                 r = String(r).substring(1); // chop the end off.
13542             }
13543             
13544             return ps[0] + '.' + r;
13545              
13546         },
13547         
13548         /**
13549          * Format a number as US currency
13550          * @param {Number/String} value The numeric value to format
13551          * @return {String} The formatted currency string
13552          */
13553         usMoney : function(v){
13554             return '$' + Roo.util.Format.number(v);
13555         },
13556         
13557         /**
13558          * Format a number
13559          * eventually this should probably emulate php's number_format
13560          * @param {Number/String} value The numeric value to format
13561          * @param {Number} decimals number of decimal places
13562          * @return {String} The formatted currency string
13563          */
13564         number : function(v,decimals)
13565         {
13566             // multiply and round.
13567             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13568             var mul = Math.pow(10, decimals);
13569             var zero = String(mul).substring(1);
13570             v = (Math.round((v-0)*mul))/mul;
13571             
13572             // if it's '0' number.. then
13573             
13574             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13575             v = String(v);
13576             var ps = v.split('.');
13577             var whole = ps[0];
13578             
13579             
13580             var r = /(\d+)(\d{3})/;
13581             // add comma's
13582             while (r.test(whole)) {
13583                 whole = whole.replace(r, '$1' + ',' + '$2');
13584             }
13585             
13586             
13587             var sub = ps[1] ?
13588                     // has decimals..
13589                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13590                     // does not have decimals
13591                     (decimals ? ('.' + zero) : '');
13592             
13593             
13594             return whole + sub ;
13595         },
13596         
13597         /**
13598          * Parse a value into a formatted date using the specified format pattern.
13599          * @param {Mixed} value The value to format
13600          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13601          * @return {String} The formatted date string
13602          */
13603         date : function(v, format){
13604             if(!v){
13605                 return "";
13606             }
13607             if(!(v instanceof Date)){
13608                 v = new Date(Date.parse(v));
13609             }
13610             return v.dateFormat(format || Roo.util.Format.defaults.date);
13611         },
13612
13613         /**
13614          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13615          * @param {String} format Any valid date format string
13616          * @return {Function} The date formatting function
13617          */
13618         dateRenderer : function(format){
13619             return function(v){
13620                 return Roo.util.Format.date(v, format);  
13621             };
13622         },
13623
13624         // private
13625         stripTagsRE : /<\/?[^>]+>/gi,
13626         
13627         /**
13628          * Strips all HTML tags
13629          * @param {Mixed} value The text from which to strip tags
13630          * @return {String} The stripped text
13631          */
13632         stripTags : function(v){
13633             return !v ? v : String(v).replace(this.stripTagsRE, "");
13634         }
13635     };
13636 }();
13637 Roo.util.Format.defaults = {
13638     date : 'd/M/Y'
13639 };/*
13640  * Based on:
13641  * Ext JS Library 1.1.1
13642  * Copyright(c) 2006-2007, Ext JS, LLC.
13643  *
13644  * Originally Released Under LGPL - original licence link has changed is not relivant.
13645  *
13646  * Fork - LGPL
13647  * <script type="text/javascript">
13648  */
13649
13650
13651  
13652
13653 /**
13654  * @class Roo.MasterTemplate
13655  * @extends Roo.Template
13656  * Provides a template that can have child templates. The syntax is:
13657 <pre><code>
13658 var t = new Roo.MasterTemplate(
13659         '&lt;select name="{name}"&gt;',
13660                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13661         '&lt;/select&gt;'
13662 );
13663 t.add('options', {value: 'foo', text: 'bar'});
13664 // or you can add multiple child elements in one shot
13665 t.addAll('options', [
13666     {value: 'foo', text: 'bar'},
13667     {value: 'foo2', text: 'bar2'},
13668     {value: 'foo3', text: 'bar3'}
13669 ]);
13670 // then append, applying the master template values
13671 t.append('my-form', {name: 'my-select'});
13672 </code></pre>
13673 * A name attribute for the child template is not required if you have only one child
13674 * template or you want to refer to them by index.
13675  */
13676 Roo.MasterTemplate = function(){
13677     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13678     this.originalHtml = this.html;
13679     var st = {};
13680     var m, re = this.subTemplateRe;
13681     re.lastIndex = 0;
13682     var subIndex = 0;
13683     while(m = re.exec(this.html)){
13684         var name = m[1], content = m[2];
13685         st[subIndex] = {
13686             name: name,
13687             index: subIndex,
13688             buffer: [],
13689             tpl : new Roo.Template(content)
13690         };
13691         if(name){
13692             st[name] = st[subIndex];
13693         }
13694         st[subIndex].tpl.compile();
13695         st[subIndex].tpl.call = this.call.createDelegate(this);
13696         subIndex++;
13697     }
13698     this.subCount = subIndex;
13699     this.subs = st;
13700 };
13701 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13702     /**
13703     * The regular expression used to match sub templates
13704     * @type RegExp
13705     * @property
13706     */
13707     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13708
13709     /**
13710      * Applies the passed values to a child template.
13711      * @param {String/Number} name (optional) The name or index of the child template
13712      * @param {Array/Object} values The values to be applied to the template
13713      * @return {MasterTemplate} this
13714      */
13715      add : function(name, values){
13716         if(arguments.length == 1){
13717             values = arguments[0];
13718             name = 0;
13719         }
13720         var s = this.subs[name];
13721         s.buffer[s.buffer.length] = s.tpl.apply(values);
13722         return this;
13723     },
13724
13725     /**
13726      * Applies all the passed values to a child template.
13727      * @param {String/Number} name (optional) The name or index of the child template
13728      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13729      * @param {Boolean} reset (optional) True to reset the template first
13730      * @return {MasterTemplate} this
13731      */
13732     fill : function(name, values, reset){
13733         var a = arguments;
13734         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13735             values = a[0];
13736             name = 0;
13737             reset = a[1];
13738         }
13739         if(reset){
13740             this.reset();
13741         }
13742         for(var i = 0, len = values.length; i < len; i++){
13743             this.add(name, values[i]);
13744         }
13745         return this;
13746     },
13747
13748     /**
13749      * Resets the template for reuse
13750      * @return {MasterTemplate} this
13751      */
13752      reset : function(){
13753         var s = this.subs;
13754         for(var i = 0; i < this.subCount; i++){
13755             s[i].buffer = [];
13756         }
13757         return this;
13758     },
13759
13760     applyTemplate : function(values){
13761         var s = this.subs;
13762         var replaceIndex = -1;
13763         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13764             return s[++replaceIndex].buffer.join("");
13765         });
13766         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13767     },
13768
13769     apply : function(){
13770         return this.applyTemplate.apply(this, arguments);
13771     },
13772
13773     compile : function(){return this;}
13774 });
13775
13776 /**
13777  * Alias for fill().
13778  * @method
13779  */
13780 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13781  /**
13782  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13783  * var tpl = Roo.MasterTemplate.from('element-id');
13784  * @param {String/HTMLElement} el
13785  * @param {Object} config
13786  * @static
13787  */
13788 Roo.MasterTemplate.from = function(el, config){
13789     el = Roo.getDom(el);
13790     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13791 };/*
13792  * Based on:
13793  * Ext JS Library 1.1.1
13794  * Copyright(c) 2006-2007, Ext JS, LLC.
13795  *
13796  * Originally Released Under LGPL - original licence link has changed is not relivant.
13797  *
13798  * Fork - LGPL
13799  * <script type="text/javascript">
13800  */
13801
13802  
13803 /**
13804  * @class Roo.util.CSS
13805  * Utility class for manipulating CSS rules
13806  * @singleton
13807  */
13808 Roo.util.CSS = function(){
13809         var rules = null;
13810         var doc = document;
13811
13812     var camelRe = /(-[a-z])/gi;
13813     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13814
13815    return {
13816    /**
13817     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13818     * tag and appended to the HEAD of the document.
13819     * @param {String|Object} cssText The text containing the css rules
13820     * @param {String} id An id to add to the stylesheet for later removal
13821     * @return {StyleSheet}
13822     */
13823     createStyleSheet : function(cssText, id){
13824         var ss;
13825         var head = doc.getElementsByTagName("head")[0];
13826         var nrules = doc.createElement("style");
13827         nrules.setAttribute("type", "text/css");
13828         if(id){
13829             nrules.setAttribute("id", id);
13830         }
13831         if (typeof(cssText) != 'string') {
13832             // support object maps..
13833             // not sure if this a good idea.. 
13834             // perhaps it should be merged with the general css handling
13835             // and handle js style props.
13836             var cssTextNew = [];
13837             for(var n in cssText) {
13838                 var citems = [];
13839                 for(var k in cssText[n]) {
13840                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13841                 }
13842                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13843                 
13844             }
13845             cssText = cssTextNew.join("\n");
13846             
13847         }
13848        
13849        
13850        if(Roo.isIE){
13851            head.appendChild(nrules);
13852            ss = nrules.styleSheet;
13853            ss.cssText = cssText;
13854        }else{
13855            try{
13856                 nrules.appendChild(doc.createTextNode(cssText));
13857            }catch(e){
13858                nrules.cssText = cssText; 
13859            }
13860            head.appendChild(nrules);
13861            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13862        }
13863        this.cacheStyleSheet(ss);
13864        return ss;
13865    },
13866
13867    /**
13868     * Removes a style or link tag by id
13869     * @param {String} id The id of the tag
13870     */
13871    removeStyleSheet : function(id){
13872        var existing = doc.getElementById(id);
13873        if(existing){
13874            existing.parentNode.removeChild(existing);
13875        }
13876    },
13877
13878    /**
13879     * Dynamically swaps an existing stylesheet reference for a new one
13880     * @param {String} id The id of an existing link tag to remove
13881     * @param {String} url The href of the new stylesheet to include
13882     */
13883    swapStyleSheet : function(id, url){
13884        this.removeStyleSheet(id);
13885        var ss = doc.createElement("link");
13886        ss.setAttribute("rel", "stylesheet");
13887        ss.setAttribute("type", "text/css");
13888        ss.setAttribute("id", id);
13889        ss.setAttribute("href", url);
13890        doc.getElementsByTagName("head")[0].appendChild(ss);
13891    },
13892    
13893    /**
13894     * Refresh the rule cache if you have dynamically added stylesheets
13895     * @return {Object} An object (hash) of rules indexed by selector
13896     */
13897    refreshCache : function(){
13898        return this.getRules(true);
13899    },
13900
13901    // private
13902    cacheStyleSheet : function(stylesheet){
13903        if(!rules){
13904            rules = {};
13905        }
13906        try{// try catch for cross domain access issue
13907            var ssRules = stylesheet.cssRules || stylesheet.rules;
13908            for(var j = ssRules.length-1; j >= 0; --j){
13909                rules[ssRules[j].selectorText] = ssRules[j];
13910            }
13911        }catch(e){}
13912    },
13913    
13914    /**
13915     * Gets all css rules for the document
13916     * @param {Boolean} refreshCache true to refresh the internal cache
13917     * @return {Object} An object (hash) of rules indexed by selector
13918     */
13919    getRules : function(refreshCache){
13920                 if(rules == null || refreshCache){
13921                         rules = {};
13922                         var ds = doc.styleSheets;
13923                         for(var i =0, len = ds.length; i < len; i++){
13924                             try{
13925                         this.cacheStyleSheet(ds[i]);
13926                     }catch(e){} 
13927                 }
13928                 }
13929                 return rules;
13930         },
13931         
13932         /**
13933     * Gets an an individual CSS rule by selector(s)
13934     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13935     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13936     * @return {CSSRule} The CSS rule or null if one is not found
13937     */
13938    getRule : function(selector, refreshCache){
13939                 var rs = this.getRules(refreshCache);
13940                 if(!(selector instanceof Array)){
13941                     return rs[selector];
13942                 }
13943                 for(var i = 0; i < selector.length; i++){
13944                         if(rs[selector[i]]){
13945                                 return rs[selector[i]];
13946                         }
13947                 }
13948                 return null;
13949         },
13950         
13951         
13952         /**
13953     * Updates a rule property
13954     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13955     * @param {String} property The css property
13956     * @param {String} value The new value for the property
13957     * @return {Boolean} true If a rule was found and updated
13958     */
13959    updateRule : function(selector, property, value){
13960                 if(!(selector instanceof Array)){
13961                         var rule = this.getRule(selector);
13962                         if(rule){
13963                                 rule.style[property.replace(camelRe, camelFn)] = value;
13964                                 return true;
13965                         }
13966                 }else{
13967                         for(var i = 0; i < selector.length; i++){
13968                                 if(this.updateRule(selector[i], property, value)){
13969                                         return true;
13970                                 }
13971                         }
13972                 }
13973                 return false;
13974         }
13975    };   
13976 }();/*
13977  * Based on:
13978  * Ext JS Library 1.1.1
13979  * Copyright(c) 2006-2007, Ext JS, LLC.
13980  *
13981  * Originally Released Under LGPL - original licence link has changed is not relivant.
13982  *
13983  * Fork - LGPL
13984  * <script type="text/javascript">
13985  */
13986
13987  
13988
13989 /**
13990  * @class Roo.util.ClickRepeater
13991  * @extends Roo.util.Observable
13992  * 
13993  * A wrapper class which can be applied to any element. Fires a "click" event while the
13994  * mouse is pressed. The interval between firings may be specified in the config but
13995  * defaults to 10 milliseconds.
13996  * 
13997  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13998  * 
13999  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14000  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14001  * Similar to an autorepeat key delay.
14002  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14003  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14004  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14005  *           "interval" and "delay" are ignored. "immediate" is honored.
14006  * @cfg {Boolean} preventDefault True to prevent the default click event
14007  * @cfg {Boolean} stopDefault True to stop the default click event
14008  * 
14009  * @history
14010  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14011  *     2007-02-02 jvs Renamed to ClickRepeater
14012  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14013  *
14014  *  @constructor
14015  * @param {String/HTMLElement/Element} el The element to listen on
14016  * @param {Object} config
14017  **/
14018 Roo.util.ClickRepeater = function(el, config)
14019 {
14020     this.el = Roo.get(el);
14021     this.el.unselectable();
14022
14023     Roo.apply(this, config);
14024
14025     this.addEvents({
14026     /**
14027      * @event mousedown
14028      * Fires when the mouse button is depressed.
14029      * @param {Roo.util.ClickRepeater} this
14030      */
14031         "mousedown" : true,
14032     /**
14033      * @event click
14034      * Fires on a specified interval during the time the element is pressed.
14035      * @param {Roo.util.ClickRepeater} this
14036      */
14037         "click" : true,
14038     /**
14039      * @event mouseup
14040      * Fires when the mouse key is released.
14041      * @param {Roo.util.ClickRepeater} this
14042      */
14043         "mouseup" : true
14044     });
14045
14046     this.el.on("mousedown", this.handleMouseDown, this);
14047     if(this.preventDefault || this.stopDefault){
14048         this.el.on("click", function(e){
14049             if(this.preventDefault){
14050                 e.preventDefault();
14051             }
14052             if(this.stopDefault){
14053                 e.stopEvent();
14054             }
14055         }, this);
14056     }
14057
14058     // allow inline handler
14059     if(this.handler){
14060         this.on("click", this.handler,  this.scope || this);
14061     }
14062
14063     Roo.util.ClickRepeater.superclass.constructor.call(this);
14064 };
14065
14066 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14067     interval : 20,
14068     delay: 250,
14069     preventDefault : true,
14070     stopDefault : false,
14071     timer : 0,
14072
14073     // private
14074     handleMouseDown : function(){
14075         clearTimeout(this.timer);
14076         this.el.blur();
14077         if(this.pressClass){
14078             this.el.addClass(this.pressClass);
14079         }
14080         this.mousedownTime = new Date();
14081
14082         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14083         this.el.on("mouseout", this.handleMouseOut, this);
14084
14085         this.fireEvent("mousedown", this);
14086         this.fireEvent("click", this);
14087         
14088         this.timer = this.click.defer(this.delay || this.interval, this);
14089     },
14090
14091     // private
14092     click : function(){
14093         this.fireEvent("click", this);
14094         this.timer = this.click.defer(this.getInterval(), this);
14095     },
14096
14097     // private
14098     getInterval: function(){
14099         if(!this.accelerate){
14100             return this.interval;
14101         }
14102         var pressTime = this.mousedownTime.getElapsed();
14103         if(pressTime < 500){
14104             return 400;
14105         }else if(pressTime < 1700){
14106             return 320;
14107         }else if(pressTime < 2600){
14108             return 250;
14109         }else if(pressTime < 3500){
14110             return 180;
14111         }else if(pressTime < 4400){
14112             return 140;
14113         }else if(pressTime < 5300){
14114             return 80;
14115         }else if(pressTime < 6200){
14116             return 50;
14117         }else{
14118             return 10;
14119         }
14120     },
14121
14122     // private
14123     handleMouseOut : function(){
14124         clearTimeout(this.timer);
14125         if(this.pressClass){
14126             this.el.removeClass(this.pressClass);
14127         }
14128         this.el.on("mouseover", this.handleMouseReturn, this);
14129     },
14130
14131     // private
14132     handleMouseReturn : function(){
14133         this.el.un("mouseover", this.handleMouseReturn);
14134         if(this.pressClass){
14135             this.el.addClass(this.pressClass);
14136         }
14137         this.click();
14138     },
14139
14140     // private
14141     handleMouseUp : function(){
14142         clearTimeout(this.timer);
14143         this.el.un("mouseover", this.handleMouseReturn);
14144         this.el.un("mouseout", this.handleMouseOut);
14145         Roo.get(document).un("mouseup", this.handleMouseUp);
14146         this.el.removeClass(this.pressClass);
14147         this.fireEvent("mouseup", this);
14148     }
14149 });/*
14150  * Based on:
14151  * Ext JS Library 1.1.1
14152  * Copyright(c) 2006-2007, Ext JS, LLC.
14153  *
14154  * Originally Released Under LGPL - original licence link has changed is not relivant.
14155  *
14156  * Fork - LGPL
14157  * <script type="text/javascript">
14158  */
14159
14160  
14161 /**
14162  * @class Roo.KeyNav
14163  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14164  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14165  * way to implement custom navigation schemes for any UI component.</p>
14166  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14167  * pageUp, pageDown, del, home, end.  Usage:</p>
14168  <pre><code>
14169 var nav = new Roo.KeyNav("my-element", {
14170     "left" : function(e){
14171         this.moveLeft(e.ctrlKey);
14172     },
14173     "right" : function(e){
14174         this.moveRight(e.ctrlKey);
14175     },
14176     "enter" : function(e){
14177         this.save();
14178     },
14179     scope : this
14180 });
14181 </code></pre>
14182  * @constructor
14183  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14184  * @param {Object} config The config
14185  */
14186 Roo.KeyNav = function(el, config){
14187     this.el = Roo.get(el);
14188     Roo.apply(this, config);
14189     if(!this.disabled){
14190         this.disabled = true;
14191         this.enable();
14192     }
14193 };
14194
14195 Roo.KeyNav.prototype = {
14196     /**
14197      * @cfg {Boolean} disabled
14198      * True to disable this KeyNav instance (defaults to false)
14199      */
14200     disabled : false,
14201     /**
14202      * @cfg {String} defaultEventAction
14203      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14204      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14205      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14206      */
14207     defaultEventAction: "stopEvent",
14208     /**
14209      * @cfg {Boolean} forceKeyDown
14210      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14211      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14212      * handle keydown instead of keypress.
14213      */
14214     forceKeyDown : false,
14215
14216     // private
14217     prepareEvent : function(e){
14218         var k = e.getKey();
14219         var h = this.keyToHandler[k];
14220         //if(h && this[h]){
14221         //    e.stopPropagation();
14222         //}
14223         if(Roo.isSafari && h && k >= 37 && k <= 40){
14224             e.stopEvent();
14225         }
14226     },
14227
14228     // private
14229     relay : function(e){
14230         var k = e.getKey();
14231         var h = this.keyToHandler[k];
14232         if(h && this[h]){
14233             if(this.doRelay(e, this[h], h) !== true){
14234                 e[this.defaultEventAction]();
14235             }
14236         }
14237     },
14238
14239     // private
14240     doRelay : function(e, h, hname){
14241         return h.call(this.scope || this, e);
14242     },
14243
14244     // possible handlers
14245     enter : false,
14246     left : false,
14247     right : false,
14248     up : false,
14249     down : false,
14250     tab : false,
14251     esc : false,
14252     pageUp : false,
14253     pageDown : false,
14254     del : false,
14255     home : false,
14256     end : false,
14257
14258     // quick lookup hash
14259     keyToHandler : {
14260         37 : "left",
14261         39 : "right",
14262         38 : "up",
14263         40 : "down",
14264         33 : "pageUp",
14265         34 : "pageDown",
14266         46 : "del",
14267         36 : "home",
14268         35 : "end",
14269         13 : "enter",
14270         27 : "esc",
14271         9  : "tab"
14272     },
14273
14274         /**
14275          * Enable this KeyNav
14276          */
14277         enable: function(){
14278                 if(this.disabled){
14279             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14280             // the EventObject will normalize Safari automatically
14281             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14282                 this.el.on("keydown", this.relay,  this);
14283             }else{
14284                 this.el.on("keydown", this.prepareEvent,  this);
14285                 this.el.on("keypress", this.relay,  this);
14286             }
14287                     this.disabled = false;
14288                 }
14289         },
14290
14291         /**
14292          * Disable this KeyNav
14293          */
14294         disable: function(){
14295                 if(!this.disabled){
14296                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14297                 this.el.un("keydown", this.relay);
14298             }else{
14299                 this.el.un("keydown", this.prepareEvent);
14300                 this.el.un("keypress", this.relay);
14301             }
14302                     this.disabled = true;
14303                 }
14304         }
14305 };/*
14306  * Based on:
14307  * Ext JS Library 1.1.1
14308  * Copyright(c) 2006-2007, Ext JS, LLC.
14309  *
14310  * Originally Released Under LGPL - original licence link has changed is not relivant.
14311  *
14312  * Fork - LGPL
14313  * <script type="text/javascript">
14314  */
14315
14316  
14317 /**
14318  * @class Roo.KeyMap
14319  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14320  * The constructor accepts the same config object as defined by {@link #addBinding}.
14321  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14322  * combination it will call the function with this signature (if the match is a multi-key
14323  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14324  * A KeyMap can also handle a string representation of keys.<br />
14325  * Usage:
14326  <pre><code>
14327 // map one key by key code
14328 var map = new Roo.KeyMap("my-element", {
14329     key: 13, // or Roo.EventObject.ENTER
14330     fn: myHandler,
14331     scope: myObject
14332 });
14333
14334 // map multiple keys to one action by string
14335 var map = new Roo.KeyMap("my-element", {
14336     key: "a\r\n\t",
14337     fn: myHandler,
14338     scope: myObject
14339 });
14340
14341 // map multiple keys to multiple actions by strings and array of codes
14342 var map = new Roo.KeyMap("my-element", [
14343     {
14344         key: [10,13],
14345         fn: function(){ alert("Return was pressed"); }
14346     }, {
14347         key: "abc",
14348         fn: function(){ alert('a, b or c was pressed'); }
14349     }, {
14350         key: "\t",
14351         ctrl:true,
14352         shift:true,
14353         fn: function(){ alert('Control + shift + tab was pressed.'); }
14354     }
14355 ]);
14356 </code></pre>
14357  * <b>Note: A KeyMap starts enabled</b>
14358  * @constructor
14359  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14360  * @param {Object} config The config (see {@link #addBinding})
14361  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14362  */
14363 Roo.KeyMap = function(el, config, eventName){
14364     this.el  = Roo.get(el);
14365     this.eventName = eventName || "keydown";
14366     this.bindings = [];
14367     if(config){
14368         this.addBinding(config);
14369     }
14370     this.enable();
14371 };
14372
14373 Roo.KeyMap.prototype = {
14374     /**
14375      * True to stop the event from bubbling and prevent the default browser action if the
14376      * key was handled by the KeyMap (defaults to false)
14377      * @type Boolean
14378      */
14379     stopEvent : false,
14380
14381     /**
14382      * Add a new binding to this KeyMap. The following config object properties are supported:
14383      * <pre>
14384 Property    Type             Description
14385 ----------  ---------------  ----------------------------------------------------------------------
14386 key         String/Array     A single keycode or an array of keycodes to handle
14387 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14388 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14389 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14390 fn          Function         The function to call when KeyMap finds the expected key combination
14391 scope       Object           The scope of the callback function
14392 </pre>
14393      *
14394      * Usage:
14395      * <pre><code>
14396 // Create a KeyMap
14397 var map = new Roo.KeyMap(document, {
14398     key: Roo.EventObject.ENTER,
14399     fn: handleKey,
14400     scope: this
14401 });
14402
14403 //Add a new binding to the existing KeyMap later
14404 map.addBinding({
14405     key: 'abc',
14406     shift: true,
14407     fn: handleKey,
14408     scope: this
14409 });
14410 </code></pre>
14411      * @param {Object/Array} config A single KeyMap config or an array of configs
14412      */
14413         addBinding : function(config){
14414         if(config instanceof Array){
14415             for(var i = 0, len = config.length; i < len; i++){
14416                 this.addBinding(config[i]);
14417             }
14418             return;
14419         }
14420         var keyCode = config.key,
14421             shift = config.shift, 
14422             ctrl = config.ctrl, 
14423             alt = config.alt,
14424             fn = config.fn,
14425             scope = config.scope;
14426         if(typeof keyCode == "string"){
14427             var ks = [];
14428             var keyString = keyCode.toUpperCase();
14429             for(var j = 0, len = keyString.length; j < len; j++){
14430                 ks.push(keyString.charCodeAt(j));
14431             }
14432             keyCode = ks;
14433         }
14434         var keyArray = keyCode instanceof Array;
14435         var handler = function(e){
14436             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14437                 var k = e.getKey();
14438                 if(keyArray){
14439                     for(var i = 0, len = keyCode.length; i < len; i++){
14440                         if(keyCode[i] == k){
14441                           if(this.stopEvent){
14442                               e.stopEvent();
14443                           }
14444                           fn.call(scope || window, k, e);
14445                           return;
14446                         }
14447                     }
14448                 }else{
14449                     if(k == keyCode){
14450                         if(this.stopEvent){
14451                            e.stopEvent();
14452                         }
14453                         fn.call(scope || window, k, e);
14454                     }
14455                 }
14456             }
14457         };
14458         this.bindings.push(handler);  
14459         },
14460
14461     /**
14462      * Shorthand for adding a single key listener
14463      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14464      * following options:
14465      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14466      * @param {Function} fn The function to call
14467      * @param {Object} scope (optional) The scope of the function
14468      */
14469     on : function(key, fn, scope){
14470         var keyCode, shift, ctrl, alt;
14471         if(typeof key == "object" && !(key instanceof Array)){
14472             keyCode = key.key;
14473             shift = key.shift;
14474             ctrl = key.ctrl;
14475             alt = key.alt;
14476         }else{
14477             keyCode = key;
14478         }
14479         this.addBinding({
14480             key: keyCode,
14481             shift: shift,
14482             ctrl: ctrl,
14483             alt: alt,
14484             fn: fn,
14485             scope: scope
14486         })
14487     },
14488
14489     // private
14490     handleKeyDown : function(e){
14491             if(this.enabled){ //just in case
14492             var b = this.bindings;
14493             for(var i = 0, len = b.length; i < len; i++){
14494                 b[i].call(this, e);
14495             }
14496             }
14497         },
14498         
14499         /**
14500          * Returns true if this KeyMap is enabled
14501          * @return {Boolean} 
14502          */
14503         isEnabled : function(){
14504             return this.enabled;  
14505         },
14506         
14507         /**
14508          * Enables this KeyMap
14509          */
14510         enable: function(){
14511                 if(!this.enabled){
14512                     this.el.on(this.eventName, this.handleKeyDown, this);
14513                     this.enabled = true;
14514                 }
14515         },
14516
14517         /**
14518          * Disable this KeyMap
14519          */
14520         disable: function(){
14521                 if(this.enabled){
14522                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14523                     this.enabled = false;
14524                 }
14525         }
14526 };/*
14527  * Based on:
14528  * Ext JS Library 1.1.1
14529  * Copyright(c) 2006-2007, Ext JS, LLC.
14530  *
14531  * Originally Released Under LGPL - original licence link has changed is not relivant.
14532  *
14533  * Fork - LGPL
14534  * <script type="text/javascript">
14535  */
14536
14537  
14538 /**
14539  * @class Roo.util.TextMetrics
14540  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14541  * wide, in pixels, a given block of text will be.
14542  * @singleton
14543  */
14544 Roo.util.TextMetrics = function(){
14545     var shared;
14546     return {
14547         /**
14548          * Measures the size of the specified text
14549          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14550          * that can affect the size of the rendered text
14551          * @param {String} text The text to measure
14552          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14553          * in order to accurately measure the text height
14554          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14555          */
14556         measure : function(el, text, fixedWidth){
14557             if(!shared){
14558                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14559             }
14560             shared.bind(el);
14561             shared.setFixedWidth(fixedWidth || 'auto');
14562             return shared.getSize(text);
14563         },
14564
14565         /**
14566          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14567          * the overhead of multiple calls to initialize the style properties on each measurement.
14568          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14569          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14570          * in order to accurately measure the text height
14571          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14572          */
14573         createInstance : function(el, fixedWidth){
14574             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14575         }
14576     };
14577 }();
14578
14579  
14580
14581 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14582     var ml = new Roo.Element(document.createElement('div'));
14583     document.body.appendChild(ml.dom);
14584     ml.position('absolute');
14585     ml.setLeftTop(-1000, -1000);
14586     ml.hide();
14587
14588     if(fixedWidth){
14589         ml.setWidth(fixedWidth);
14590     }
14591      
14592     var instance = {
14593         /**
14594          * Returns the size of the specified text based on the internal element's style and width properties
14595          * @memberOf Roo.util.TextMetrics.Instance#
14596          * @param {String} text The text to measure
14597          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14598          */
14599         getSize : function(text){
14600             ml.update(text);
14601             var s = ml.getSize();
14602             ml.update('');
14603             return s;
14604         },
14605
14606         /**
14607          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14608          * that can affect the size of the rendered text
14609          * @memberOf Roo.util.TextMetrics.Instance#
14610          * @param {String/HTMLElement} el The element, dom node or id
14611          */
14612         bind : function(el){
14613             ml.setStyle(
14614                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14615             );
14616         },
14617
14618         /**
14619          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14620          * to set a fixed width in order to accurately measure the text height.
14621          * @memberOf Roo.util.TextMetrics.Instance#
14622          * @param {Number} width The width to set on the element
14623          */
14624         setFixedWidth : function(width){
14625             ml.setWidth(width);
14626         },
14627
14628         /**
14629          * Returns the measured width of the specified text
14630          * @memberOf Roo.util.TextMetrics.Instance#
14631          * @param {String} text The text to measure
14632          * @return {Number} width The width in pixels
14633          */
14634         getWidth : function(text){
14635             ml.dom.style.width = 'auto';
14636             return this.getSize(text).width;
14637         },
14638
14639         /**
14640          * Returns the measured height of the specified text.  For multiline text, be sure to call
14641          * {@link #setFixedWidth} if necessary.
14642          * @memberOf Roo.util.TextMetrics.Instance#
14643          * @param {String} text The text to measure
14644          * @return {Number} height The height in pixels
14645          */
14646         getHeight : function(text){
14647             return this.getSize(text).height;
14648         }
14649     };
14650
14651     instance.bind(bindTo);
14652
14653     return instance;
14654 };
14655
14656 // backwards compat
14657 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14658  * Based on:
14659  * Ext JS Library 1.1.1
14660  * Copyright(c) 2006-2007, Ext JS, LLC.
14661  *
14662  * Originally Released Under LGPL - original licence link has changed is not relivant.
14663  *
14664  * Fork - LGPL
14665  * <script type="text/javascript">
14666  */
14667
14668 /**
14669  * @class Roo.state.Provider
14670  * Abstract base class for state provider implementations. This class provides methods
14671  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14672  * Provider interface.
14673  */
14674 Roo.state.Provider = function(){
14675     /**
14676      * @event statechange
14677      * Fires when a state change occurs.
14678      * @param {Provider} this This state provider
14679      * @param {String} key The state key which was changed
14680      * @param {String} value The encoded value for the state
14681      */
14682     this.addEvents({
14683         "statechange": true
14684     });
14685     this.state = {};
14686     Roo.state.Provider.superclass.constructor.call(this);
14687 };
14688 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14689     /**
14690      * Returns the current value for a key
14691      * @param {String} name The key name
14692      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14693      * @return {Mixed} The state data
14694      */
14695     get : function(name, defaultValue){
14696         return typeof this.state[name] == "undefined" ?
14697             defaultValue : this.state[name];
14698     },
14699     
14700     /**
14701      * Clears a value from the state
14702      * @param {String} name The key name
14703      */
14704     clear : function(name){
14705         delete this.state[name];
14706         this.fireEvent("statechange", this, name, null);
14707     },
14708     
14709     /**
14710      * Sets the value for a key
14711      * @param {String} name The key name
14712      * @param {Mixed} value The value to set
14713      */
14714     set : function(name, value){
14715         this.state[name] = value;
14716         this.fireEvent("statechange", this, name, value);
14717     },
14718     
14719     /**
14720      * Decodes a string previously encoded with {@link #encodeValue}.
14721      * @param {String} value The value to decode
14722      * @return {Mixed} The decoded value
14723      */
14724     decodeValue : function(cookie){
14725         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14726         var matches = re.exec(unescape(cookie));
14727         if(!matches || !matches[1]) return; // non state cookie
14728         var type = matches[1];
14729         var v = matches[2];
14730         switch(type){
14731             case "n":
14732                 return parseFloat(v);
14733             case "d":
14734                 return new Date(Date.parse(v));
14735             case "b":
14736                 return (v == "1");
14737             case "a":
14738                 var all = [];
14739                 var values = v.split("^");
14740                 for(var i = 0, len = values.length; i < len; i++){
14741                     all.push(this.decodeValue(values[i]));
14742                 }
14743                 return all;
14744            case "o":
14745                 var all = {};
14746                 var values = v.split("^");
14747                 for(var i = 0, len = values.length; i < len; i++){
14748                     var kv = values[i].split("=");
14749                     all[kv[0]] = this.decodeValue(kv[1]);
14750                 }
14751                 return all;
14752            default:
14753                 return v;
14754         }
14755     },
14756     
14757     /**
14758      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14759      * @param {Mixed} value The value to encode
14760      * @return {String} The encoded value
14761      */
14762     encodeValue : function(v){
14763         var enc;
14764         if(typeof v == "number"){
14765             enc = "n:" + v;
14766         }else if(typeof v == "boolean"){
14767             enc = "b:" + (v ? "1" : "0");
14768         }else if(v instanceof Date){
14769             enc = "d:" + v.toGMTString();
14770         }else if(v instanceof Array){
14771             var flat = "";
14772             for(var i = 0, len = v.length; i < len; i++){
14773                 flat += this.encodeValue(v[i]);
14774                 if(i != len-1) flat += "^";
14775             }
14776             enc = "a:" + flat;
14777         }else if(typeof v == "object"){
14778             var flat = "";
14779             for(var key in v){
14780                 if(typeof v[key] != "function"){
14781                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14782                 }
14783             }
14784             enc = "o:" + flat.substring(0, flat.length-1);
14785         }else{
14786             enc = "s:" + v;
14787         }
14788         return escape(enc);        
14789     }
14790 });
14791
14792 /*
14793  * Based on:
14794  * Ext JS Library 1.1.1
14795  * Copyright(c) 2006-2007, Ext JS, LLC.
14796  *
14797  * Originally Released Under LGPL - original licence link has changed is not relivant.
14798  *
14799  * Fork - LGPL
14800  * <script type="text/javascript">
14801  */
14802 /**
14803  * @class Roo.state.Manager
14804  * This is the global state manager. By default all components that are "state aware" check this class
14805  * for state information if you don't pass them a custom state provider. In order for this class
14806  * to be useful, it must be initialized with a provider when your application initializes.
14807  <pre><code>
14808 // in your initialization function
14809 init : function(){
14810    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14811    ...
14812    // supposed you have a {@link Roo.BorderLayout}
14813    var layout = new Roo.BorderLayout(...);
14814    layout.restoreState();
14815    // or a {Roo.BasicDialog}
14816    var dialog = new Roo.BasicDialog(...);
14817    dialog.restoreState();
14818  </code></pre>
14819  * @singleton
14820  */
14821 Roo.state.Manager = function(){
14822     var provider = new Roo.state.Provider();
14823     
14824     return {
14825         /**
14826          * Configures the default state provider for your application
14827          * @param {Provider} stateProvider The state provider to set
14828          */
14829         setProvider : function(stateProvider){
14830             provider = stateProvider;
14831         },
14832         
14833         /**
14834          * Returns the current value for a key
14835          * @param {String} name The key name
14836          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14837          * @return {Mixed} The state data
14838          */
14839         get : function(key, defaultValue){
14840             return provider.get(key, defaultValue);
14841         },
14842         
14843         /**
14844          * Sets the value for a key
14845          * @param {String} name The key name
14846          * @param {Mixed} value The state data
14847          */
14848          set : function(key, value){
14849             provider.set(key, value);
14850         },
14851         
14852         /**
14853          * Clears a value from the state
14854          * @param {String} name The key name
14855          */
14856         clear : function(key){
14857             provider.clear(key);
14858         },
14859         
14860         /**
14861          * Gets the currently configured state provider
14862          * @return {Provider} The state provider
14863          */
14864         getProvider : function(){
14865             return provider;
14866         }
14867     };
14868 }();
14869 /*
14870  * Based on:
14871  * Ext JS Library 1.1.1
14872  * Copyright(c) 2006-2007, Ext JS, LLC.
14873  *
14874  * Originally Released Under LGPL - original licence link has changed is not relivant.
14875  *
14876  * Fork - LGPL
14877  * <script type="text/javascript">
14878  */
14879 /**
14880  * @class Roo.state.CookieProvider
14881  * @extends Roo.state.Provider
14882  * The default Provider implementation which saves state via cookies.
14883  * <br />Usage:
14884  <pre><code>
14885    var cp = new Roo.state.CookieProvider({
14886        path: "/cgi-bin/",
14887        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14888        domain: "roojs.com"
14889    })
14890    Roo.state.Manager.setProvider(cp);
14891  </code></pre>
14892  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14893  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14894  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14895  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14896  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14897  * domain the page is running on including the 'www' like 'www.roojs.com')
14898  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14899  * @constructor
14900  * Create a new CookieProvider
14901  * @param {Object} config The configuration object
14902  */
14903 Roo.state.CookieProvider = function(config){
14904     Roo.state.CookieProvider.superclass.constructor.call(this);
14905     this.path = "/";
14906     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14907     this.domain = null;
14908     this.secure = false;
14909     Roo.apply(this, config);
14910     this.state = this.readCookies();
14911 };
14912
14913 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14914     // private
14915     set : function(name, value){
14916         if(typeof value == "undefined" || value === null){
14917             this.clear(name);
14918             return;
14919         }
14920         this.setCookie(name, value);
14921         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14922     },
14923
14924     // private
14925     clear : function(name){
14926         this.clearCookie(name);
14927         Roo.state.CookieProvider.superclass.clear.call(this, name);
14928     },
14929
14930     // private
14931     readCookies : function(){
14932         var cookies = {};
14933         var c = document.cookie + ";";
14934         var re = /\s?(.*?)=(.*?);/g;
14935         var matches;
14936         while((matches = re.exec(c)) != null){
14937             var name = matches[1];
14938             var value = matches[2];
14939             if(name && name.substring(0,3) == "ys-"){
14940                 cookies[name.substr(3)] = this.decodeValue(value);
14941             }
14942         }
14943         return cookies;
14944     },
14945
14946     // private
14947     setCookie : function(name, value){
14948         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14949            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14950            ((this.path == null) ? "" : ("; path=" + this.path)) +
14951            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14952            ((this.secure == true) ? "; secure" : "");
14953     },
14954
14955     // private
14956     clearCookie : function(name){
14957         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14958            ((this.path == null) ? "" : ("; path=" + this.path)) +
14959            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14960            ((this.secure == true) ? "; secure" : "");
14961     }
14962 });/*
14963  * Based on:
14964  * Ext JS Library 1.1.1
14965  * Copyright(c) 2006-2007, Ext JS, LLC.
14966  *
14967  * Originally Released Under LGPL - original licence link has changed is not relivant.
14968  *
14969  * Fork - LGPL
14970  * <script type="text/javascript">
14971  */
14972  
14973
14974 /**
14975  * @class Roo.ComponentMgr
14976  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14977  * @singleton
14978  */
14979 Roo.ComponentMgr = function(){
14980     var all = new Roo.util.MixedCollection();
14981
14982     return {
14983         /**
14984          * Registers a component.
14985          * @param {Roo.Component} c The component
14986          */
14987         register : function(c){
14988             all.add(c);
14989         },
14990
14991         /**
14992          * Unregisters a component.
14993          * @param {Roo.Component} c The component
14994          */
14995         unregister : function(c){
14996             all.remove(c);
14997         },
14998
14999         /**
15000          * Returns a component by id
15001          * @param {String} id The component id
15002          */
15003         get : function(id){
15004             return all.get(id);
15005         },
15006
15007         /**
15008          * Registers a function that will be called when a specified component is added to ComponentMgr
15009          * @param {String} id The component id
15010          * @param {Funtction} fn The callback function
15011          * @param {Object} scope The scope of the callback
15012          */
15013         onAvailable : function(id, fn, scope){
15014             all.on("add", function(index, o){
15015                 if(o.id == id){
15016                     fn.call(scope || o, o);
15017                     all.un("add", fn, scope);
15018                 }
15019             });
15020         }
15021     };
15022 }();/*
15023  * Based on:
15024  * Ext JS Library 1.1.1
15025  * Copyright(c) 2006-2007, Ext JS, LLC.
15026  *
15027  * Originally Released Under LGPL - original licence link has changed is not relivant.
15028  *
15029  * Fork - LGPL
15030  * <script type="text/javascript">
15031  */
15032  
15033 /**
15034  * @class Roo.Component
15035  * @extends Roo.util.Observable
15036  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15037  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15038  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15039  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15040  * All visual components (widgets) that require rendering into a layout should subclass Component.
15041  * @constructor
15042  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15043  * 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
15044  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15045  */
15046 Roo.Component = function(config){
15047     config = config || {};
15048     if(config.tagName || config.dom || typeof config == "string"){ // element object
15049         config = {el: config, id: config.id || config};
15050     }
15051     this.initialConfig = config;
15052
15053     Roo.apply(this, config);
15054     this.addEvents({
15055         /**
15056          * @event disable
15057          * Fires after the component is disabled.
15058              * @param {Roo.Component} this
15059              */
15060         disable : true,
15061         /**
15062          * @event enable
15063          * Fires after the component is enabled.
15064              * @param {Roo.Component} this
15065              */
15066         enable : true,
15067         /**
15068          * @event beforeshow
15069          * Fires before the component is shown.  Return false to stop the show.
15070              * @param {Roo.Component} this
15071              */
15072         beforeshow : true,
15073         /**
15074          * @event show
15075          * Fires after the component is shown.
15076              * @param {Roo.Component} this
15077              */
15078         show : true,
15079         /**
15080          * @event beforehide
15081          * Fires before the component is hidden. Return false to stop the hide.
15082              * @param {Roo.Component} this
15083              */
15084         beforehide : true,
15085         /**
15086          * @event hide
15087          * Fires after the component is hidden.
15088              * @param {Roo.Component} this
15089              */
15090         hide : true,
15091         /**
15092          * @event beforerender
15093          * Fires before the component is rendered. Return false to stop the render.
15094              * @param {Roo.Component} this
15095              */
15096         beforerender : true,
15097         /**
15098          * @event render
15099          * Fires after the component is rendered.
15100              * @param {Roo.Component} this
15101              */
15102         render : true,
15103         /**
15104          * @event beforedestroy
15105          * Fires before the component is destroyed. Return false to stop the destroy.
15106              * @param {Roo.Component} this
15107              */
15108         beforedestroy : true,
15109         /**
15110          * @event destroy
15111          * Fires after the component is destroyed.
15112              * @param {Roo.Component} this
15113              */
15114         destroy : true
15115     });
15116     if(!this.id){
15117         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15118     }
15119     Roo.ComponentMgr.register(this);
15120     Roo.Component.superclass.constructor.call(this);
15121     this.initComponent();
15122     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15123         this.render(this.renderTo);
15124         delete this.renderTo;
15125     }
15126 };
15127
15128 /** @private */
15129 Roo.Component.AUTO_ID = 1000;
15130
15131 Roo.extend(Roo.Component, Roo.util.Observable, {
15132     /**
15133      * @scope Roo.Component.prototype
15134      * @type {Boolean}
15135      * true if this component is hidden. Read-only.
15136      */
15137     hidden : false,
15138     /**
15139      * @type {Boolean}
15140      * true if this component is disabled. Read-only.
15141      */
15142     disabled : false,
15143     /**
15144      * @type {Boolean}
15145      * true if this component has been rendered. Read-only.
15146      */
15147     rendered : false,
15148     
15149     /** @cfg {String} disableClass
15150      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15151      */
15152     disabledClass : "x-item-disabled",
15153         /** @cfg {Boolean} allowDomMove
15154          * Whether the component can move the Dom node when rendering (defaults to true).
15155          */
15156     allowDomMove : true,
15157     /** @cfg {String} hideMode
15158      * How this component should hidden. Supported values are
15159      * "visibility" (css visibility), "offsets" (negative offset position) and
15160      * "display" (css display) - defaults to "display".
15161      */
15162     hideMode: 'display',
15163
15164     /** @private */
15165     ctype : "Roo.Component",
15166
15167     /**
15168      * @cfg {String} actionMode 
15169      * which property holds the element that used for  hide() / show() / disable() / enable()
15170      * default is 'el' 
15171      */
15172     actionMode : "el",
15173
15174     /** @private */
15175     getActionEl : function(){
15176         return this[this.actionMode];
15177     },
15178
15179     initComponent : Roo.emptyFn,
15180     /**
15181      * If this is a lazy rendering component, render it to its container element.
15182      * @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.
15183      */
15184     render : function(container, position){
15185         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15186             if(!container && this.el){
15187                 this.el = Roo.get(this.el);
15188                 container = this.el.dom.parentNode;
15189                 this.allowDomMove = false;
15190             }
15191             this.container = Roo.get(container);
15192             this.rendered = true;
15193             if(position !== undefined){
15194                 if(typeof position == 'number'){
15195                     position = this.container.dom.childNodes[position];
15196                 }else{
15197                     position = Roo.getDom(position);
15198                 }
15199             }
15200             this.onRender(this.container, position || null);
15201             if(this.cls){
15202                 this.el.addClass(this.cls);
15203                 delete this.cls;
15204             }
15205             if(this.style){
15206                 this.el.applyStyles(this.style);
15207                 delete this.style;
15208             }
15209             this.fireEvent("render", this);
15210             this.afterRender(this.container);
15211             if(this.hidden){
15212                 this.hide();
15213             }
15214             if(this.disabled){
15215                 this.disable();
15216             }
15217         }
15218         return this;
15219     },
15220
15221     /** @private */
15222     // default function is not really useful
15223     onRender : function(ct, position){
15224         if(this.el){
15225             this.el = Roo.get(this.el);
15226             if(this.allowDomMove !== false){
15227                 ct.dom.insertBefore(this.el.dom, position);
15228             }
15229         }
15230     },
15231
15232     /** @private */
15233     getAutoCreate : function(){
15234         var cfg = typeof this.autoCreate == "object" ?
15235                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15236         if(this.id && !cfg.id){
15237             cfg.id = this.id;
15238         }
15239         return cfg;
15240     },
15241
15242     /** @private */
15243     afterRender : Roo.emptyFn,
15244
15245     /**
15246      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15247      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15248      */
15249     destroy : function(){
15250         if(this.fireEvent("beforedestroy", this) !== false){
15251             this.purgeListeners();
15252             this.beforeDestroy();
15253             if(this.rendered){
15254                 this.el.removeAllListeners();
15255                 this.el.remove();
15256                 if(this.actionMode == "container"){
15257                     this.container.remove();
15258                 }
15259             }
15260             this.onDestroy();
15261             Roo.ComponentMgr.unregister(this);
15262             this.fireEvent("destroy", this);
15263         }
15264     },
15265
15266         /** @private */
15267     beforeDestroy : function(){
15268
15269     },
15270
15271         /** @private */
15272         onDestroy : function(){
15273
15274     },
15275
15276     /**
15277      * Returns the underlying {@link Roo.Element}.
15278      * @return {Roo.Element} The element
15279      */
15280     getEl : function(){
15281         return this.el;
15282     },
15283
15284     /**
15285      * Returns the id of this component.
15286      * @return {String}
15287      */
15288     getId : function(){
15289         return this.id;
15290     },
15291
15292     /**
15293      * Try to focus this component.
15294      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15295      * @return {Roo.Component} this
15296      */
15297     focus : function(selectText){
15298         if(this.rendered){
15299             this.el.focus();
15300             if(selectText === true){
15301                 this.el.dom.select();
15302             }
15303         }
15304         return this;
15305     },
15306
15307     /** @private */
15308     blur : function(){
15309         if(this.rendered){
15310             this.el.blur();
15311         }
15312         return this;
15313     },
15314
15315     /**
15316      * Disable this component.
15317      * @return {Roo.Component} this
15318      */
15319     disable : function(){
15320         if(this.rendered){
15321             this.onDisable();
15322         }
15323         this.disabled = true;
15324         this.fireEvent("disable", this);
15325         return this;
15326     },
15327
15328         // private
15329     onDisable : function(){
15330         this.getActionEl().addClass(this.disabledClass);
15331         this.el.dom.disabled = true;
15332     },
15333
15334     /**
15335      * Enable this component.
15336      * @return {Roo.Component} this
15337      */
15338     enable : function(){
15339         if(this.rendered){
15340             this.onEnable();
15341         }
15342         this.disabled = false;
15343         this.fireEvent("enable", this);
15344         return this;
15345     },
15346
15347         // private
15348     onEnable : function(){
15349         this.getActionEl().removeClass(this.disabledClass);
15350         this.el.dom.disabled = false;
15351     },
15352
15353     /**
15354      * Convenience function for setting disabled/enabled by boolean.
15355      * @param {Boolean} disabled
15356      */
15357     setDisabled : function(disabled){
15358         this[disabled ? "disable" : "enable"]();
15359     },
15360
15361     /**
15362      * Show this component.
15363      * @return {Roo.Component} this
15364      */
15365     show: function(){
15366         if(this.fireEvent("beforeshow", this) !== false){
15367             this.hidden = false;
15368             if(this.rendered){
15369                 this.onShow();
15370             }
15371             this.fireEvent("show", this);
15372         }
15373         return this;
15374     },
15375
15376     // private
15377     onShow : function(){
15378         var ae = this.getActionEl();
15379         if(this.hideMode == 'visibility'){
15380             ae.dom.style.visibility = "visible";
15381         }else if(this.hideMode == 'offsets'){
15382             ae.removeClass('x-hidden');
15383         }else{
15384             ae.dom.style.display = "";
15385         }
15386     },
15387
15388     /**
15389      * Hide this component.
15390      * @return {Roo.Component} this
15391      */
15392     hide: function(){
15393         if(this.fireEvent("beforehide", this) !== false){
15394             this.hidden = true;
15395             if(this.rendered){
15396                 this.onHide();
15397             }
15398             this.fireEvent("hide", this);
15399         }
15400         return this;
15401     },
15402
15403     // private
15404     onHide : function(){
15405         var ae = this.getActionEl();
15406         if(this.hideMode == 'visibility'){
15407             ae.dom.style.visibility = "hidden";
15408         }else if(this.hideMode == 'offsets'){
15409             ae.addClass('x-hidden');
15410         }else{
15411             ae.dom.style.display = "none";
15412         }
15413     },
15414
15415     /**
15416      * Convenience function to hide or show this component by boolean.
15417      * @param {Boolean} visible True to show, false to hide
15418      * @return {Roo.Component} this
15419      */
15420     setVisible: function(visible){
15421         if(visible) {
15422             this.show();
15423         }else{
15424             this.hide();
15425         }
15426         return this;
15427     },
15428
15429     /**
15430      * Returns true if this component is visible.
15431      */
15432     isVisible : function(){
15433         return this.getActionEl().isVisible();
15434     },
15435
15436     cloneConfig : function(overrides){
15437         overrides = overrides || {};
15438         var id = overrides.id || Roo.id();
15439         var cfg = Roo.applyIf(overrides, this.initialConfig);
15440         cfg.id = id; // prevent dup id
15441         return new this.constructor(cfg);
15442     }
15443 });/*
15444  * Based on:
15445  * Ext JS Library 1.1.1
15446  * Copyright(c) 2006-2007, Ext JS, LLC.
15447  *
15448  * Originally Released Under LGPL - original licence link has changed is not relivant.
15449  *
15450  * Fork - LGPL
15451  * <script type="text/javascript">
15452  */
15453
15454 /**
15455  * @class Roo.BoxComponent
15456  * @extends Roo.Component
15457  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15458  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15459  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15460  * layout containers.
15461  * @constructor
15462  * @param {Roo.Element/String/Object} config The configuration options.
15463  */
15464 Roo.BoxComponent = function(config){
15465     Roo.Component.call(this, config);
15466     this.addEvents({
15467         /**
15468          * @event resize
15469          * Fires after the component is resized.
15470              * @param {Roo.Component} this
15471              * @param {Number} adjWidth The box-adjusted width that was set
15472              * @param {Number} adjHeight The box-adjusted height that was set
15473              * @param {Number} rawWidth The width that was originally specified
15474              * @param {Number} rawHeight The height that was originally specified
15475              */
15476         resize : true,
15477         /**
15478          * @event move
15479          * Fires after the component is moved.
15480              * @param {Roo.Component} this
15481              * @param {Number} x The new x position
15482              * @param {Number} y The new y position
15483              */
15484         move : true
15485     });
15486 };
15487
15488 Roo.extend(Roo.BoxComponent, Roo.Component, {
15489     // private, set in afterRender to signify that the component has been rendered
15490     boxReady : false,
15491     // private, used to defer height settings to subclasses
15492     deferHeight: false,
15493     /** @cfg {Number} width
15494      * width (optional) size of component
15495      */
15496      /** @cfg {Number} height
15497      * height (optional) size of component
15498      */
15499      
15500     /**
15501      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15502      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15503      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15504      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15505      * @return {Roo.BoxComponent} this
15506      */
15507     setSize : function(w, h){
15508         // support for standard size objects
15509         if(typeof w == 'object'){
15510             h = w.height;
15511             w = w.width;
15512         }
15513         // not rendered
15514         if(!this.boxReady){
15515             this.width = w;
15516             this.height = h;
15517             return this;
15518         }
15519
15520         // prevent recalcs when not needed
15521         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15522             return this;
15523         }
15524         this.lastSize = {width: w, height: h};
15525
15526         var adj = this.adjustSize(w, h);
15527         var aw = adj.width, ah = adj.height;
15528         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15529             var rz = this.getResizeEl();
15530             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15531                 rz.setSize(aw, ah);
15532             }else if(!this.deferHeight && ah !== undefined){
15533                 rz.setHeight(ah);
15534             }else if(aw !== undefined){
15535                 rz.setWidth(aw);
15536             }
15537             this.onResize(aw, ah, w, h);
15538             this.fireEvent('resize', this, aw, ah, w, h);
15539         }
15540         return this;
15541     },
15542
15543     /**
15544      * Gets the current size of the component's underlying element.
15545      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15546      */
15547     getSize : function(){
15548         return this.el.getSize();
15549     },
15550
15551     /**
15552      * Gets the current XY position of the component's underlying element.
15553      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15554      * @return {Array} The XY position of the element (e.g., [100, 200])
15555      */
15556     getPosition : function(local){
15557         if(local === true){
15558             return [this.el.getLeft(true), this.el.getTop(true)];
15559         }
15560         return this.xy || this.el.getXY();
15561     },
15562
15563     /**
15564      * Gets the current box measurements of the component's underlying element.
15565      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15566      * @returns {Object} box An object in the format {x, y, width, height}
15567      */
15568     getBox : function(local){
15569         var s = this.el.getSize();
15570         if(local){
15571             s.x = this.el.getLeft(true);
15572             s.y = this.el.getTop(true);
15573         }else{
15574             var xy = this.xy || this.el.getXY();
15575             s.x = xy[0];
15576             s.y = xy[1];
15577         }
15578         return s;
15579     },
15580
15581     /**
15582      * Sets the current box measurements of the component's underlying element.
15583      * @param {Object} box An object in the format {x, y, width, height}
15584      * @returns {Roo.BoxComponent} this
15585      */
15586     updateBox : function(box){
15587         this.setSize(box.width, box.height);
15588         this.setPagePosition(box.x, box.y);
15589         return this;
15590     },
15591
15592     // protected
15593     getResizeEl : function(){
15594         return this.resizeEl || this.el;
15595     },
15596
15597     // protected
15598     getPositionEl : function(){
15599         return this.positionEl || this.el;
15600     },
15601
15602     /**
15603      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15604      * This method fires the move event.
15605      * @param {Number} left The new left
15606      * @param {Number} top The new top
15607      * @returns {Roo.BoxComponent} this
15608      */
15609     setPosition : function(x, y){
15610         this.x = x;
15611         this.y = y;
15612         if(!this.boxReady){
15613             return this;
15614         }
15615         var adj = this.adjustPosition(x, y);
15616         var ax = adj.x, ay = adj.y;
15617
15618         var el = this.getPositionEl();
15619         if(ax !== undefined || ay !== undefined){
15620             if(ax !== undefined && ay !== undefined){
15621                 el.setLeftTop(ax, ay);
15622             }else if(ax !== undefined){
15623                 el.setLeft(ax);
15624             }else if(ay !== undefined){
15625                 el.setTop(ay);
15626             }
15627             this.onPosition(ax, ay);
15628             this.fireEvent('move', this, ax, ay);
15629         }
15630         return this;
15631     },
15632
15633     /**
15634      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15635      * This method fires the move event.
15636      * @param {Number} x The new x position
15637      * @param {Number} y The new y position
15638      * @returns {Roo.BoxComponent} this
15639      */
15640     setPagePosition : function(x, y){
15641         this.pageX = x;
15642         this.pageY = y;
15643         if(!this.boxReady){
15644             return;
15645         }
15646         if(x === undefined || y === undefined){ // cannot translate undefined points
15647             return;
15648         }
15649         var p = this.el.translatePoints(x, y);
15650         this.setPosition(p.left, p.top);
15651         return this;
15652     },
15653
15654     // private
15655     onRender : function(ct, position){
15656         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15657         if(this.resizeEl){
15658             this.resizeEl = Roo.get(this.resizeEl);
15659         }
15660         if(this.positionEl){
15661             this.positionEl = Roo.get(this.positionEl);
15662         }
15663     },
15664
15665     // private
15666     afterRender : function(){
15667         Roo.BoxComponent.superclass.afterRender.call(this);
15668         this.boxReady = true;
15669         this.setSize(this.width, this.height);
15670         if(this.x || this.y){
15671             this.setPosition(this.x, this.y);
15672         }
15673         if(this.pageX || this.pageY){
15674             this.setPagePosition(this.pageX, this.pageY);
15675         }
15676     },
15677
15678     /**
15679      * Force the component's size to recalculate based on the underlying element's current height and width.
15680      * @returns {Roo.BoxComponent} this
15681      */
15682     syncSize : function(){
15683         delete this.lastSize;
15684         this.setSize(this.el.getWidth(), this.el.getHeight());
15685         return this;
15686     },
15687
15688     /**
15689      * Called after the component is resized, this method is empty by default but can be implemented by any
15690      * subclass that needs to perform custom logic after a resize occurs.
15691      * @param {Number} adjWidth The box-adjusted width that was set
15692      * @param {Number} adjHeight The box-adjusted height that was set
15693      * @param {Number} rawWidth The width that was originally specified
15694      * @param {Number} rawHeight The height that was originally specified
15695      */
15696     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15697
15698     },
15699
15700     /**
15701      * Called after the component is moved, this method is empty by default but can be implemented by any
15702      * subclass that needs to perform custom logic after a move occurs.
15703      * @param {Number} x The new x position
15704      * @param {Number} y The new y position
15705      */
15706     onPosition : function(x, y){
15707
15708     },
15709
15710     // private
15711     adjustSize : function(w, h){
15712         if(this.autoWidth){
15713             w = 'auto';
15714         }
15715         if(this.autoHeight){
15716             h = 'auto';
15717         }
15718         return {width : w, height: h};
15719     },
15720
15721     // private
15722     adjustPosition : function(x, y){
15723         return {x : x, y: y};
15724     }
15725 });/*
15726  * Original code for Roojs - LGPL
15727  * <script type="text/javascript">
15728  */
15729  
15730 /**
15731  * @class Roo.XComponent
15732  * A delayed Element creator...
15733  * Or a way to group chunks of interface together.
15734  * 
15735  * Mypart.xyx = new Roo.XComponent({
15736
15737     parent : 'Mypart.xyz', // empty == document.element.!!
15738     order : '001',
15739     name : 'xxxx'
15740     region : 'xxxx'
15741     disabled : function() {} 
15742      
15743     tree : function() { // return an tree of xtype declared components
15744         var MODULE = this;
15745         return 
15746         {
15747             xtype : 'NestedLayoutPanel',
15748             // technicall
15749         }
15750      ]
15751  *})
15752  *
15753  *
15754  * It can be used to build a big heiracy, with parent etc.
15755  * or you can just use this to render a single compoent to a dom element
15756  * MYPART.render(Roo.Element | String(id) | dom_element )
15757  * 
15758  * @extends Roo.util.Observable
15759  * @constructor
15760  * @param cfg {Object} configuration of component
15761  * 
15762  */
15763 Roo.XComponent = function(cfg) {
15764     Roo.apply(this, cfg);
15765     this.addEvents({ 
15766         /**
15767              * @event built
15768              * Fires when this the componnt is built
15769              * @param {Roo.XComponent} c the component
15770              */
15771         'built' : true
15772         
15773     });
15774     this.region = this.region || 'center'; // default..
15775     Roo.XComponent.register(this);
15776     this.modules = false;
15777     this.el = false; // where the layout goes..
15778     
15779     
15780 }
15781 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15782     /**
15783      * @property el
15784      * The created element (with Roo.factory())
15785      * @type {Roo.Layout}
15786      */
15787     el  : false,
15788     
15789     /**
15790      * @property el
15791      * for BC  - use el in new code
15792      * @type {Roo.Layout}
15793      */
15794     panel : false,
15795     
15796     /**
15797      * @property layout
15798      * for BC  - use el in new code
15799      * @type {Roo.Layout}
15800      */
15801     layout : false,
15802     
15803      /**
15804      * @cfg {Function|boolean} disabled
15805      * If this module is disabled by some rule, return true from the funtion
15806      */
15807     disabled : false,
15808     
15809     /**
15810      * @cfg {String} parent 
15811      * Name of parent element which it get xtype added to..
15812      */
15813     parent: false,
15814     
15815     /**
15816      * @cfg {String} order
15817      * Used to set the order in which elements are created (usefull for multiple tabs)
15818      */
15819     
15820     order : false,
15821     /**
15822      * @cfg {String} name
15823      * String to display while loading.
15824      */
15825     name : false,
15826     /**
15827      * @cfg {String} region
15828      * Region to render component to (defaults to center)
15829      */
15830     region : 'center',
15831     
15832     /**
15833      * @cfg {Array} items
15834      * A single item array - the first element is the root of the tree..
15835      * It's done this way to stay compatible with the Xtype system...
15836      */
15837     items : false,
15838     
15839     /**
15840      * @property _tree
15841      * The method that retuns the tree of parts that make up this compoennt 
15842      * @type {function}
15843      */
15844     _tree  : false,
15845     
15846      /**
15847      * render
15848      * render element to dom or tree
15849      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15850      */
15851     
15852     render : function(el)
15853     {
15854         
15855         el = el || false;
15856         var hp = this.parent ? 1 : 0;
15857         
15858         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15859             // if parent is a '#.....' string, then let's use that..
15860             var ename = this.parent.substr(1)
15861             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15862             el = Roo.get(ename);
15863             if (!el && !this.parent) {
15864                 Roo.log("Warning - element can not be found :#" + ename );
15865                 return;
15866             }
15867         }
15868         var tree = this._tree ? this._tree() : this.tree();
15869
15870         
15871         if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15872             //el = Roo.get(document.body);
15873             this.parent = { el : true };
15874         }
15875             
15876             
15877         
15878         if (!this.parent) {
15879             
15880             Roo.log("no parent - creating one");
15881             
15882             el = el ? Roo.get(el) : false;      
15883             
15884             // it's a top level one..
15885             this.parent =  {
15886                 el : new Roo.BorderLayout(el || document.body, {
15887                 
15888                      center: {
15889                          titlebar: false,
15890                          autoScroll:false,
15891                          closeOnTab: true,
15892                          tabPosition: 'top',
15893                           //resizeTabs: true,
15894                          alwaysShowTabs: el && hp? false :  true,
15895                          hideTabs: el || !hp ? true :  false,
15896                          minTabWidth: 140
15897                      }
15898                  })
15899             }
15900         }
15901         
15902                 if (!this.parent.el) {
15903                         // probably an old style ctor, which has been disabled.
15904                         return;
15905                         
15906                 }
15907                 // The 'tree' method is  '_tree now' 
15908             
15909         tree.region = tree.region || this.region;
15910         
15911         if (this.parent.el === true) {
15912             // bootstrap... - body..
15913             this.parent.el = Roo.factory(tree);
15914         }
15915         
15916         this.el = this.parent.el.addxtype(tree);
15917         this.fireEvent('built', this);
15918         
15919         this.panel = this.el;
15920         this.layout = this.panel.layout;
15921                 this.parentLayout = this.parent.layout  || false;  
15922          
15923     }
15924     
15925 });
15926
15927 Roo.apply(Roo.XComponent, {
15928     /**
15929      * @property  hideProgress
15930      * true to disable the building progress bar.. usefull on single page renders.
15931      * @type Boolean
15932      */
15933     hideProgress : false,
15934     /**
15935      * @property  buildCompleted
15936      * True when the builder has completed building the interface.
15937      * @type Boolean
15938      */
15939     buildCompleted : false,
15940      
15941     /**
15942      * @property  topModule
15943      * the upper most module - uses document.element as it's constructor.
15944      * @type Object
15945      */
15946      
15947     topModule  : false,
15948       
15949     /**
15950      * @property  modules
15951      * array of modules to be created by registration system.
15952      * @type {Array} of Roo.XComponent
15953      */
15954     
15955     modules : [],
15956     /**
15957      * @property  elmodules
15958      * array of modules to be created by which use #ID 
15959      * @type {Array} of Roo.XComponent
15960      */
15961      
15962     elmodules : [],
15963
15964      /**
15965      * @property  build_from_html
15966      * Build elements from html - used by bootstrap HTML stuff 
15967      *    - this is cleared after build is completed
15968      * @type {boolean} true  (default false)
15969      */
15970      
15971     build_from_html : false,
15972
15973     /**
15974      * Register components to be built later.
15975      *
15976      * This solves the following issues
15977      * - Building is not done on page load, but after an authentication process has occured.
15978      * - Interface elements are registered on page load
15979      * - Parent Interface elements may not be loaded before child, so this handles that..
15980      * 
15981      *
15982      * example:
15983      * 
15984      * MyApp.register({
15985           order : '000001',
15986           module : 'Pman.Tab.projectMgr',
15987           region : 'center',
15988           parent : 'Pman.layout',
15989           disabled : false,  // or use a function..
15990         })
15991      
15992      * * @param {Object} details about module
15993      */
15994     register : function(obj) {
15995                 
15996         Roo.XComponent.event.fireEvent('register', obj);
15997         switch(typeof(obj.disabled) ) {
15998                 
15999             case 'undefined':
16000                 break;
16001             
16002             case 'function':
16003                 if ( obj.disabled() ) {
16004                         return;
16005                 }
16006                 break;
16007             
16008             default:
16009                 if (obj.disabled) {
16010                         return;
16011                 }
16012                 break;
16013         }
16014                 
16015         this.modules.push(obj);
16016          
16017     },
16018     /**
16019      * convert a string to an object..
16020      * eg. 'AAA.BBB' -> finds AAA.BBB
16021
16022      */
16023     
16024     toObject : function(str)
16025     {
16026         if (!str || typeof(str) == 'object') {
16027             return str;
16028         }
16029         if (str.substring(0,1) == '#') {
16030             return str;
16031         }
16032
16033         var ar = str.split('.');
16034         var rt, o;
16035         rt = ar.shift();
16036             /** eval:var:o */
16037         try {
16038             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16039         } catch (e) {
16040             throw "Module not found : " + str;
16041         }
16042         
16043         if (o === false) {
16044             throw "Module not found : " + str;
16045         }
16046         Roo.each(ar, function(e) {
16047             if (typeof(o[e]) == 'undefined') {
16048                 throw "Module not found : " + str;
16049             }
16050             o = o[e];
16051         });
16052         
16053         return o;
16054         
16055     },
16056     
16057     
16058     /**
16059      * move modules into their correct place in the tree..
16060      * 
16061      */
16062     preBuild : function ()
16063     {
16064         var _t = this;
16065         Roo.each(this.modules , function (obj)
16066         {
16067             Roo.XComponent.event.fireEvent('beforebuild', obj);
16068             
16069             var opar = obj.parent;
16070             try { 
16071                 obj.parent = this.toObject(opar);
16072             } catch(e) {
16073                 Roo.log("parent:toObject failed: " + e.toString());
16074                 return;
16075             }
16076             
16077             if (!obj.parent) {
16078                 Roo.debug && Roo.log("GOT top level module");
16079                 Roo.debug && Roo.log(obj);
16080                 obj.modules = new Roo.util.MixedCollection(false, 
16081                     function(o) { return o.order + '' }
16082                 );
16083                 this.topModule = obj;
16084                 return;
16085             }
16086                         // parent is a string (usually a dom element name..)
16087             if (typeof(obj.parent) == 'string') {
16088                 this.elmodules.push(obj);
16089                 return;
16090             }
16091             if (obj.parent.constructor != Roo.XComponent) {
16092                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16093             }
16094             if (!obj.parent.modules) {
16095                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16096                     function(o) { return o.order + '' }
16097                 );
16098             }
16099             if (obj.parent.disabled) {
16100                 obj.disabled = true;
16101             }
16102             obj.parent.modules.add(obj);
16103         }, this);
16104     },
16105     
16106      /**
16107      * make a list of modules to build.
16108      * @return {Array} list of modules. 
16109      */ 
16110     
16111     buildOrder : function()
16112     {
16113         var _this = this;
16114         var cmp = function(a,b) {   
16115             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16116         };
16117         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16118             throw "No top level modules to build";
16119         }
16120         
16121         // make a flat list in order of modules to build.
16122         var mods = this.topModule ? [ this.topModule ] : [];
16123                 
16124         
16125         // elmodules (is a list of DOM based modules )
16126         Roo.each(this.elmodules, function(e) {
16127             mods.push(e);
16128             if (!this.topModule &&
16129                 typeof(e.parent) == 'string' &&
16130                 e.parent.substring(0,1) == '#' &&
16131                 Roo.get(e.parent.substr(1))
16132                ) {
16133                 
16134                 _this.topModule = e;
16135             }
16136             
16137         });
16138
16139         
16140         // add modules to their parents..
16141         var addMod = function(m) {
16142             Roo.debug && Roo.log("build Order: add: " + m.name);
16143                 
16144             mods.push(m);
16145             if (m.modules && !m.disabled) {
16146                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16147                 m.modules.keySort('ASC',  cmp );
16148                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16149     
16150                 m.modules.each(addMod);
16151             } else {
16152                 Roo.debug && Roo.log("build Order: no child modules");
16153             }
16154             // not sure if this is used any more..
16155             if (m.finalize) {
16156                 m.finalize.name = m.name + " (clean up) ";
16157                 mods.push(m.finalize);
16158             }
16159             
16160         }
16161         if (this.topModule && this.topModule.modules) { 
16162             this.topModule.modules.keySort('ASC',  cmp );
16163             this.topModule.modules.each(addMod);
16164         } 
16165         return mods;
16166     },
16167     
16168      /**
16169      * Build the registered modules.
16170      * @param {Object} parent element.
16171      * @param {Function} optional method to call after module has been added.
16172      * 
16173      */ 
16174    
16175     build : function(opts) 
16176     {
16177         
16178         if (typeof(opts) != 'undefined') {
16179             Roo.apply(this,opts);
16180         }
16181         
16182         this.preBuild();
16183         var mods = this.buildOrder();
16184       
16185         //this.allmods = mods;
16186         //Roo.debug && Roo.log(mods);
16187         //return;
16188         if (!mods.length) { // should not happen
16189             throw "NO modules!!!";
16190         }
16191         
16192         
16193         var msg = "Building Interface...";
16194         // flash it up as modal - so we store the mask!?
16195         if (!this.hideProgress && Roo.MessageBox) {
16196             Roo.MessageBox.show({ title: 'loading' });
16197             Roo.MessageBox.show({
16198                title: "Please wait...",
16199                msg: msg,
16200                width:450,
16201                progress:true,
16202                closable:false,
16203                modal: false
16204               
16205             });
16206         }
16207         var total = mods.length;
16208         
16209         var _this = this;
16210         var progressRun = function() {
16211             if (!mods.length) {
16212                 Roo.debug && Roo.log('hide?');
16213                 if (!this.hideProgress && Roo.MessageBox) {
16214                     Roo.MessageBox.hide();
16215                 }
16216                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16217                 
16218                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16219                 
16220                 // THE END...
16221                 return false;   
16222             }
16223             
16224             var m = mods.shift();
16225             
16226             
16227             Roo.debug && Roo.log(m);
16228             // not sure if this is supported any more.. - modules that are are just function
16229             if (typeof(m) == 'function') { 
16230                 m.call(this);
16231                 return progressRun.defer(10, _this);
16232             } 
16233             
16234             
16235             msg = "Building Interface " + (total  - mods.length) + 
16236                     " of " + total + 
16237                     (m.name ? (' - ' + m.name) : '');
16238                         Roo.debug && Roo.log(msg);
16239             if (!this.hideProgress &&  Roo.MessageBox) { 
16240                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16241             }
16242             
16243          
16244             // is the module disabled?
16245             var disabled = (typeof(m.disabled) == 'function') ?
16246                 m.disabled.call(m.module.disabled) : m.disabled;    
16247             
16248             
16249             if (disabled) {
16250                 return progressRun(); // we do not update the display!
16251             }
16252             
16253             // now build 
16254             
16255                         
16256                         
16257             m.render();
16258             // it's 10 on top level, and 1 on others??? why...
16259             return progressRun.defer(10, _this);
16260              
16261         }
16262         progressRun.defer(1, _this);
16263      
16264         
16265         
16266     },
16267         
16268         
16269         /**
16270          * Event Object.
16271          *
16272          *
16273          */
16274         event: false, 
16275     /**
16276          * wrapper for event.on - aliased later..  
16277          * Typically use to register a event handler for register:
16278          *
16279          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16280          *
16281          */
16282     on : false
16283    
16284     
16285     
16286 });
16287
16288 Roo.XComponent.event = new Roo.util.Observable({
16289                 events : { 
16290                         /**
16291                          * @event register
16292                          * Fires when an Component is registered,
16293                          * set the disable property on the Component to stop registration.
16294                          * @param {Roo.XComponent} c the component being registerd.
16295                          * 
16296                          */
16297                         'register' : true,
16298             /**
16299                          * @event beforebuild
16300                          * Fires before each Component is built
16301                          * can be used to apply permissions.
16302                          * @param {Roo.XComponent} c the component being registerd.
16303                          * 
16304                          */
16305                         'beforebuild' : true,
16306                         /**
16307                          * @event buildcomplete
16308                          * Fires on the top level element when all elements have been built
16309                          * @param {Roo.XComponent} the top level component.
16310                          */
16311                         'buildcomplete' : true
16312                         
16313                 }
16314 });
16315
16316 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16317