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             Roo.log('factory');
298             Roo.log(c);
299             // no xtype, no ns or c.xns - or forced off by c.xns
300             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
301                 return c;
302             }
303             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
304             if (c.constructor == ns[c.xtype]) {// already created...
305                 return c;
306             }
307             if (ns[c.xtype]) {
308                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
309                 var ret = new ns[c.xtype](c);
310                 ret.xns = false;
311                 return ret;
312             }
313             c.xns = false; // prevent recursion..
314             return c;
315         },
316          /**
317          * Logs to console if it can.
318          *
319          * @param {String|Object} string
320          * @method log
321          */
322         log : function(s)
323         {
324             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
325                 return; // alerT?
326             }
327             console.log(s);
328             
329         },
330         /**
331          * 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.
332          * @param {Object} o
333          * @return {String}
334          */
335         urlEncode : function(o){
336             if(!o){
337                 return "";
338             }
339             var buf = [];
340             for(var key in o){
341                 var ov = o[key], k = Roo.encodeURIComponent(key);
342                 var type = typeof ov;
343                 if(type == 'undefined'){
344                     buf.push(k, "=&");
345                 }else if(type != "function" && type != "object"){
346                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
347                 }else if(ov instanceof Array){
348                     if (ov.length) {
349                             for(var i = 0, len = ov.length; i < len; i++) {
350                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
351                             }
352                         } else {
353                             buf.push(k, "=&");
354                         }
355                 }
356             }
357             buf.pop();
358             return buf.join("");
359         },
360          /**
361          * Safe version of encodeURIComponent
362          * @param {String} data 
363          * @return {String} 
364          */
365         
366         encodeURIComponent : function (data)
367         {
368             try {
369                 return encodeURIComponent(data);
370             } catch(e) {} // should be an uri encode error.
371             
372             if (data == '' || data == null){
373                return '';
374             }
375             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
376             function nibble_to_hex(nibble){
377                 var chars = '0123456789ABCDEF';
378                 return chars.charAt(nibble);
379             }
380             data = data.toString();
381             var buffer = '';
382             for(var i=0; i<data.length; i++){
383                 var c = data.charCodeAt(i);
384                 var bs = new Array();
385                 if (c > 0x10000){
386                         // 4 bytes
387                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
388                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
389                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
390                     bs[3] = 0x80 | (c & 0x3F);
391                 }else if (c > 0x800){
392                          // 3 bytes
393                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
394                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
395                     bs[2] = 0x80 | (c & 0x3F);
396                 }else if (c > 0x80){
397                        // 2 bytes
398                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
399                     bs[1] = 0x80 | (c & 0x3F);
400                 }else{
401                         // 1 byte
402                     bs[0] = c;
403                 }
404                 for(var j=0; j<bs.length; j++){
405                     var b = bs[j];
406                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
407                             + nibble_to_hex(b &0x0F);
408                     buffer += '%'+hex;
409                }
410             }
411             return buffer;    
412              
413         },
414
415         /**
416          * 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]}.
417          * @param {String} string
418          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
419          * @return {Object} A literal with members
420          */
421         urlDecode : function(string, overwrite){
422             if(!string || !string.length){
423                 return {};
424             }
425             var obj = {};
426             var pairs = string.split('&');
427             var pair, name, value;
428             for(var i = 0, len = pairs.length; i < len; i++){
429                 pair = pairs[i].split('=');
430                 name = decodeURIComponent(pair[0]);
431                 value = decodeURIComponent(pair[1]);
432                 if(overwrite !== true){
433                     if(typeof obj[name] == "undefined"){
434                         obj[name] = value;
435                     }else if(typeof obj[name] == "string"){
436                         obj[name] = [obj[name]];
437                         obj[name].push(value);
438                     }else{
439                         obj[name].push(value);
440                     }
441                 }else{
442                     obj[name] = value;
443                 }
444             }
445             return obj;
446         },
447
448         /**
449          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
450          * passed array is not really an array, your function is called once with it.
451          * The supplied function is called with (Object item, Number index, Array allItems).
452          * @param {Array/NodeList/Mixed} array
453          * @param {Function} fn
454          * @param {Object} scope
455          */
456         each : function(array, fn, scope){
457             if(typeof array.length == "undefined" || typeof array == "string"){
458                 array = [array];
459             }
460             for(var i = 0, len = array.length; i < len; i++){
461                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
462             }
463         },
464
465         // deprecated
466         combine : function(){
467             var as = arguments, l = as.length, r = [];
468             for(var i = 0; i < l; i++){
469                 var a = as[i];
470                 if(a instanceof Array){
471                     r = r.concat(a);
472                 }else if(a.length !== undefined && !a.substr){
473                     r = r.concat(Array.prototype.slice.call(a, 0));
474                 }else{
475                     r.push(a);
476                 }
477             }
478             return r;
479         },
480
481         /**
482          * Escapes the passed string for use in a regular expression
483          * @param {String} str
484          * @return {String}
485          */
486         escapeRe : function(s) {
487             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
488         },
489
490         // internal
491         callback : function(cb, scope, args, delay){
492             if(typeof cb == "function"){
493                 if(delay){
494                     cb.defer(delay, scope, args || []);
495                 }else{
496                     cb.apply(scope, args || []);
497                 }
498             }
499         },
500
501         /**
502          * Return the dom node for the passed string (id), dom node, or Roo.Element
503          * @param {String/HTMLElement/Roo.Element} el
504          * @return HTMLElement
505          */
506         getDom : function(el){
507             if(!el){
508                 return null;
509             }
510             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
511         },
512
513         /**
514         * Shorthand for {@link Roo.ComponentMgr#get}
515         * @param {String} id
516         * @return Roo.Component
517         */
518         getCmp : function(id){
519             return Roo.ComponentMgr.get(id);
520         },
521          
522         num : function(v, defaultValue){
523             if(typeof v != 'number'){
524                 return defaultValue;
525             }
526             return v;
527         },
528
529         destroy : function(){
530             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
531                 var as = a[i];
532                 if(as){
533                     if(as.dom){
534                         as.removeAllListeners();
535                         as.remove();
536                         continue;
537                     }
538                     if(typeof as.purgeListeners == 'function'){
539                         as.purgeListeners();
540                     }
541                     if(typeof as.destroy == 'function'){
542                         as.destroy();
543                     }
544                 }
545             }
546         },
547
548         // inpired by a similar function in mootools library
549         /**
550          * Returns the type of object that is passed in. If the object passed in is null or undefined it
551          * return false otherwise it returns one of the following values:<ul>
552          * <li><b>string</b>: If the object passed is a string</li>
553          * <li><b>number</b>: If the object passed is a number</li>
554          * <li><b>boolean</b>: If the object passed is a boolean value</li>
555          * <li><b>function</b>: If the object passed is a function reference</li>
556          * <li><b>object</b>: If the object passed is an object</li>
557          * <li><b>array</b>: If the object passed is an array</li>
558          * <li><b>regexp</b>: If the object passed is a regular expression</li>
559          * <li><b>element</b>: If the object passed is a DOM Element</li>
560          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
561          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
562          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
563          * @param {Mixed} object
564          * @return {String}
565          */
566         type : function(o){
567             if(o === undefined || o === null){
568                 return false;
569             }
570             if(o.htmlElement){
571                 return 'element';
572             }
573             var t = typeof o;
574             if(t == 'object' && o.nodeName) {
575                 switch(o.nodeType) {
576                     case 1: return 'element';
577                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578                 }
579             }
580             if(t == 'object' || t == 'function') {
581                 switch(o.constructor) {
582                     case Array: return 'array';
583                     case RegExp: return 'regexp';
584                 }
585                 if(typeof o.length == 'number' && typeof o.item == 'function') {
586                     return 'nodelist';
587                 }
588             }
589             return t;
590         },
591
592         /**
593          * Returns true if the passed value is null, undefined or an empty string (optional).
594          * @param {Mixed} value The value to test
595          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596          * @return {Boolean}
597          */
598         isEmpty : function(v, allowBlank){
599             return v === null || v === undefined || (!allowBlank ? v === '' : false);
600         },
601         
602         /** @type Boolean */
603         isOpera : isOpera,
604         /** @type Boolean */
605         isSafari : isSafari,
606         /** @type Boolean */
607         isIE : isIE,
608         /** @type Boolean */
609         isIE7 : isIE7,
610         /** @type Boolean */
611         isGecko : isGecko,
612         /** @type Boolean */
613         isBorderBox : isBorderBox,
614         /** @type Boolean */
615         isWindows : isWindows,
616         /** @type Boolean */
617         isLinux : isLinux,
618         /** @type Boolean */
619         isMac : isMac,
620         /** @type Boolean */
621         isTouch : isTouch,
622
623         /**
624          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
625          * you may want to set this to true.
626          * @type Boolean
627          */
628         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629         
630         
631                 
632         /**
633          * Selects a single element as a Roo Element
634          * This is about as close as you can get to jQuery's $('do crazy stuff')
635          * @param {String} selector The selector/xpath query
636          * @param {Node} root (optional) The start of the query (defaults to document).
637          * @return {Roo.Element}
638          */
639         selectNode : function(selector, root) 
640         {
641             var node = Roo.DomQuery.selectNode(selector,root);
642             return node ? Roo.get(node) : new Roo.Element(false);
643         }
644         
645     });
646
647
648 })();
649
650 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
651                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
652 /*
653  * Based on:
654  * Ext JS Library 1.1.1
655  * Copyright(c) 2006-2007, Ext JS, LLC.
656  *
657  * Originally Released Under LGPL - original licence link has changed is not relivant.
658  *
659  * Fork - LGPL
660  * <script type="text/javascript">
661  */
662
663 (function() {    
664     // wrappedn so fnCleanup is not in global scope...
665     if(Roo.isIE) {
666         function fnCleanUp() {
667             var p = Function.prototype;
668             delete p.createSequence;
669             delete p.defer;
670             delete p.createDelegate;
671             delete p.createCallback;
672             delete p.createInterceptor;
673
674             window.detachEvent("onunload", fnCleanUp);
675         }
676         window.attachEvent("onunload", fnCleanUp);
677     }
678 })();
679
680
681 /**
682  * @class Function
683  * These functions are available on every Function object (any JavaScript function).
684  */
685 Roo.apply(Function.prototype, {
686      /**
687      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
688      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
689      * Will create a function that is bound to those 2 args.
690      * @return {Function} The new function
691     */
692     createCallback : function(/*args...*/){
693         // make args available, in function below
694         var args = arguments;
695         var method = this;
696         return function() {
697             return method.apply(window, args);
698         };
699     },
700
701     /**
702      * Creates a delegate (callback) that sets the scope to obj.
703      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
704      * Will create a function that is automatically scoped to this.
705      * @param {Object} obj (optional) The object for which the scope is set
706      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
707      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
708      *                                             if a number the args are inserted at the specified position
709      * @return {Function} The new function
710      */
711     createDelegate : function(obj, args, appendArgs){
712         var method = this;
713         return function() {
714             var callArgs = args || arguments;
715             if(appendArgs === true){
716                 callArgs = Array.prototype.slice.call(arguments, 0);
717                 callArgs = callArgs.concat(args);
718             }else if(typeof appendArgs == "number"){
719                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
720                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
721                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
722             }
723             return method.apply(obj || window, callArgs);
724         };
725     },
726
727     /**
728      * Calls this function after the number of millseconds specified.
729      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
730      * @param {Object} obj (optional) The object for which the scope is set
731      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733      *                                             if a number the args are inserted at the specified position
734      * @return {Number} The timeout id that can be used with clearTimeout
735      */
736     defer : function(millis, obj, args, appendArgs){
737         var fn = this.createDelegate(obj, args, appendArgs);
738         if(millis){
739             return setTimeout(fn, millis);
740         }
741         fn();
742         return 0;
743     },
744     /**
745      * Create a combined function call sequence of the original function + the passed function.
746      * The resulting function returns the results of the original function.
747      * The passed fcn is called with the parameters of the original function
748      * @param {Function} fcn The function to sequence
749      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
750      * @return {Function} The new function
751      */
752     createSequence : function(fcn, scope){
753         if(typeof fcn != "function"){
754             return this;
755         }
756         var method = this;
757         return function() {
758             var retval = method.apply(this || window, arguments);
759             fcn.apply(scope || this || window, arguments);
760             return retval;
761         };
762     },
763
764     /**
765      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
766      * The resulting function returns the results of the original function.
767      * The passed fcn is called with the parameters of the original function.
768      * @addon
769      * @param {Function} fcn The function to call before the original
770      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
771      * @return {Function} The new function
772      */
773     createInterceptor : function(fcn, scope){
774         if(typeof fcn != "function"){
775             return this;
776         }
777         var method = this;
778         return function() {
779             fcn.target = this;
780             fcn.method = method;
781             if(fcn.apply(scope || this || window, arguments) === false){
782                 return;
783             }
784             return method.apply(this || window, arguments);
785         };
786     }
787 });
788 /*
789  * Based on:
790  * Ext JS Library 1.1.1
791  * Copyright(c) 2006-2007, Ext JS, LLC.
792  *
793  * Originally Released Under LGPL - original licence link has changed is not relivant.
794  *
795  * Fork - LGPL
796  * <script type="text/javascript">
797  */
798
799 Roo.applyIf(String, {
800     
801     /** @scope String */
802     
803     /**
804      * Escapes the passed string for ' and \
805      * @param {String} string The string to escape
806      * @return {String} The escaped string
807      * @static
808      */
809     escape : function(string) {
810         return string.replace(/('|\\)/g, "\\$1");
811     },
812
813     /**
814      * Pads the left side of a string with a specified character.  This is especially useful
815      * for normalizing number and date strings.  Example usage:
816      * <pre><code>
817 var s = String.leftPad('123', 5, '0');
818 // s now contains the string: '00123'
819 </code></pre>
820      * @param {String} string The original string
821      * @param {Number} size The total length of the output string
822      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
823      * @return {String} The padded string
824      * @static
825      */
826     leftPad : function (val, size, ch) {
827         var result = new String(val);
828         if(ch === null || ch === undefined || ch === '') {
829             ch = " ";
830         }
831         while (result.length < size) {
832             result = ch + result;
833         }
834         return result;
835     },
836
837     /**
838      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
839      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
840      * <pre><code>
841 var cls = 'my-class', text = 'Some text';
842 var s = String.format('<div class="{0}">{1}</div>', cls, text);
843 // s now contains the string: '<div class="my-class">Some text</div>'
844 </code></pre>
845      * @param {String} string The tokenized string to be formatted
846      * @param {String} value1 The value to replace token {0}
847      * @param {String} value2 Etc...
848      * @return {String} The formatted string
849      * @static
850      */
851     format : function(format){
852         var args = Array.prototype.slice.call(arguments, 1);
853         return format.replace(/\{(\d+)\}/g, function(m, i){
854             return Roo.util.Format.htmlEncode(args[i]);
855         });
856     }
857 });
858
859 /**
860  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
861  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
862  * they are already different, the first value passed in is returned.  Note that this method returns the new value
863  * but does not change the current string.
864  * <pre><code>
865 // alternate sort directions
866 sort = sort.toggle('ASC', 'DESC');
867
868 // instead of conditional logic:
869 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
870 </code></pre>
871  * @param {String} value The value to compare to the current string
872  * @param {String} other The new value to use if the string already equals the first value passed in
873  * @return {String} The new value
874  */
875  
876 String.prototype.toggle = function(value, other){
877     return this == value ? other : value;
878 };/*
879  * Based on:
880  * Ext JS Library 1.1.1
881  * Copyright(c) 2006-2007, Ext JS, LLC.
882  *
883  * Originally Released Under LGPL - original licence link has changed is not relivant.
884  *
885  * Fork - LGPL
886  * <script type="text/javascript">
887  */
888
889  /**
890  * @class Number
891  */
892 Roo.applyIf(Number.prototype, {
893     /**
894      * Checks whether or not the current number is within a desired range.  If the number is already within the
895      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
896      * exceeded.  Note that this method returns the constrained value but does not change the current number.
897      * @param {Number} min The minimum number in the range
898      * @param {Number} max The maximum number in the range
899      * @return {Number} The constrained value if outside the range, otherwise the current value
900      */
901     constrain : function(min, max){
902         return Math.min(Math.max(this, min), max);
903     }
904 });/*
905  * Based on:
906  * Ext JS Library 1.1.1
907  * Copyright(c) 2006-2007, Ext JS, LLC.
908  *
909  * Originally Released Under LGPL - original licence link has changed is not relivant.
910  *
911  * Fork - LGPL
912  * <script type="text/javascript">
913  */
914  /**
915  * @class Array
916  */
917 Roo.applyIf(Array.prototype, {
918     /**
919      * Checks whether or not the specified object exists in the array.
920      * @param {Object} o The object to check for
921      * @return {Number} The index of o in the array (or -1 if it is not found)
922      */
923     indexOf : function(o){
924        for (var i = 0, len = this.length; i < len; i++){
925               if(this[i] == o) return i;
926        }
927            return -1;
928     },
929
930     /**
931      * Removes the specified object from the array.  If the object is not found nothing happens.
932      * @param {Object} o The object to remove
933      */
934     remove : function(o){
935        var index = this.indexOf(o);
936        if(index != -1){
937            this.splice(index, 1);
938        }
939     },
940     /**
941      * Map (JS 1.6 compatibility)
942      * @param {Function} function  to call
943      */
944     map : function(fun )
945     {
946         var len = this.length >>> 0;
947         if (typeof fun != "function")
948             throw new TypeError();
949
950         var res = new Array(len);
951         var thisp = arguments[1];
952         for (var i = 0; i < len; i++)
953         {
954             if (i in this)
955                 res[i] = fun.call(thisp, this[i], i, this);
956         }
957
958         return res;
959     }
960     
961 });
962
963
964  /*
965  * Based on:
966  * Ext JS Library 1.1.1
967  * Copyright(c) 2006-2007, Ext JS, LLC.
968  *
969  * Originally Released Under LGPL - original licence link has changed is not relivant.
970  *
971  * Fork - LGPL
972  * <script type="text/javascript">
973  */
974
975 /**
976  * @class Date
977  *
978  * The date parsing and format syntax is a subset of
979  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
980  * supported will provide results equivalent to their PHP versions.
981  *
982  * Following is the list of all currently supported formats:
983  *<pre>
984 Sample date:
985 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
986
987 Format  Output      Description
988 ------  ----------  --------------------------------------------------------------
989   d      10         Day of the month, 2 digits with leading zeros
990   D      Wed        A textual representation of a day, three letters
991   j      10         Day of the month without leading zeros
992   l      Wednesday  A full textual representation of the day of the week
993   S      th         English ordinal day of month suffix, 2 chars (use with j)
994   w      3          Numeric representation of the day of the week
995   z      9          The julian date, or day of the year (0-365)
996   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
997   F      January    A full textual representation of the month
998   m      01         Numeric representation of a month, with leading zeros
999   M      Jan        Month name abbreviation, three letters
1000   n      1          Numeric representation of a month, without leading zeros
1001   t      31         Number of days in the given month
1002   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1003   Y      2007       A full numeric representation of a year, 4 digits
1004   y      07         A two digit representation of a year
1005   a      pm         Lowercase Ante meridiem and Post meridiem
1006   A      PM         Uppercase Ante meridiem and Post meridiem
1007   g      3          12-hour format of an hour without leading zeros
1008   G      15         24-hour format of an hour without leading zeros
1009   h      03         12-hour format of an hour with leading zeros
1010   H      15         24-hour format of an hour with leading zeros
1011   i      05         Minutes with leading zeros
1012   s      01         Seconds, with leading zeros
1013   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1014   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1015   T      CST        Timezone setting of the machine running the code
1016   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1017 </pre>
1018  *
1019  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1020  * <pre><code>
1021 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1022 document.write(dt.format('Y-m-d'));                         //2007-01-10
1023 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1024 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
1025  </code></pre>
1026  *
1027  * Here are some standard date/time patterns that you might find helpful.  They
1028  * are not part of the source of Date.js, but to use them you can simply copy this
1029  * block of code into any script that is included after Date.js and they will also become
1030  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1031  * <pre><code>
1032 Date.patterns = {
1033     ISO8601Long:"Y-m-d H:i:s",
1034     ISO8601Short:"Y-m-d",
1035     ShortDate: "n/j/Y",
1036     LongDate: "l, F d, Y",
1037     FullDateTime: "l, F d, Y g:i:s A",
1038     MonthDay: "F d",
1039     ShortTime: "g:i A",
1040     LongTime: "g:i:s A",
1041     SortableDateTime: "Y-m-d\\TH:i:s",
1042     UniversalSortableDateTime: "Y-m-d H:i:sO",
1043     YearMonth: "F, Y"
1044 };
1045 </code></pre>
1046  *
1047  * Example usage:
1048  * <pre><code>
1049 var dt = new Date();
1050 document.write(dt.format(Date.patterns.ShortDate));
1051  </code></pre>
1052  */
1053
1054 /*
1055  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1056  * They generate precompiled functions from date formats instead of parsing and
1057  * processing the pattern every time you format a date.  These functions are available
1058  * on every Date object (any javascript function).
1059  *
1060  * The original article and download are here:
1061  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1062  *
1063  */
1064  
1065  
1066  // was in core
1067 /**
1068  Returns the number of milliseconds between this date and date
1069  @param {Date} date (optional) Defaults to now
1070  @return {Number} The diff in milliseconds
1071  @member Date getElapsed
1072  */
1073 Date.prototype.getElapsed = function(date) {
1074         return Math.abs((date || new Date()).getTime()-this.getTime());
1075 };
1076 // was in date file..
1077
1078
1079 // private
1080 Date.parseFunctions = {count:0};
1081 // private
1082 Date.parseRegexes = [];
1083 // private
1084 Date.formatFunctions = {count:0};
1085
1086 // private
1087 Date.prototype.dateFormat = function(format) {
1088     if (Date.formatFunctions[format] == null) {
1089         Date.createNewFormat(format);
1090     }
1091     var func = Date.formatFunctions[format];
1092     return this[func]();
1093 };
1094
1095
1096 /**
1097  * Formats a date given the supplied format string
1098  * @param {String} format The format string
1099  * @return {String} The formatted date
1100  * @method
1101  */
1102 Date.prototype.format = Date.prototype.dateFormat;
1103
1104 // private
1105 Date.createNewFormat = function(format) {
1106     var funcName = "format" + Date.formatFunctions.count++;
1107     Date.formatFunctions[format] = funcName;
1108     var code = "Date.prototype." + funcName + " = function(){return ";
1109     var special = false;
1110     var ch = '';
1111     for (var i = 0; i < format.length; ++i) {
1112         ch = format.charAt(i);
1113         if (!special && ch == "\\") {
1114             special = true;
1115         }
1116         else if (special) {
1117             special = false;
1118             code += "'" + String.escape(ch) + "' + ";
1119         }
1120         else {
1121             code += Date.getFormatCode(ch);
1122         }
1123     }
1124     /** eval:var:zzzzzzzzzzzzz */
1125     eval(code.substring(0, code.length - 3) + ";}");
1126 };
1127
1128 // private
1129 Date.getFormatCode = function(character) {
1130     switch (character) {
1131     case "d":
1132         return "String.leftPad(this.getDate(), 2, '0') + ";
1133     case "D":
1134         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1135     case "j":
1136         return "this.getDate() + ";
1137     case "l":
1138         return "Date.dayNames[this.getDay()] + ";
1139     case "S":
1140         return "this.getSuffix() + ";
1141     case "w":
1142         return "this.getDay() + ";
1143     case "z":
1144         return "this.getDayOfYear() + ";
1145     case "W":
1146         return "this.getWeekOfYear() + ";
1147     case "F":
1148         return "Date.monthNames[this.getMonth()] + ";
1149     case "m":
1150         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1151     case "M":
1152         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1153     case "n":
1154         return "(this.getMonth() + 1) + ";
1155     case "t":
1156         return "this.getDaysInMonth() + ";
1157     case "L":
1158         return "(this.isLeapYear() ? 1 : 0) + ";
1159     case "Y":
1160         return "this.getFullYear() + ";
1161     case "y":
1162         return "('' + this.getFullYear()).substring(2, 4) + ";
1163     case "a":
1164         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1165     case "A":
1166         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1167     case "g":
1168         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1169     case "G":
1170         return "this.getHours() + ";
1171     case "h":
1172         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1173     case "H":
1174         return "String.leftPad(this.getHours(), 2, '0') + ";
1175     case "i":
1176         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1177     case "s":
1178         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1179     case "O":
1180         return "this.getGMTOffset() + ";
1181     case "P":
1182         return "this.getGMTColonOffset() + ";
1183     case "T":
1184         return "this.getTimezone() + ";
1185     case "Z":
1186         return "(this.getTimezoneOffset() * -60) + ";
1187     default:
1188         return "'" + String.escape(character) + "' + ";
1189     }
1190 };
1191
1192 /**
1193  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1194  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1195  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1196  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1197  * string or the parse operation will fail.
1198  * Example Usage:
1199 <pre><code>
1200 //dt = Fri May 25 2007 (current date)
1201 var dt = new Date();
1202
1203 //dt = Thu May 25 2006 (today's month/day in 2006)
1204 dt = Date.parseDate("2006", "Y");
1205
1206 //dt = Sun Jan 15 2006 (all date parts specified)
1207 dt = Date.parseDate("2006-1-15", "Y-m-d");
1208
1209 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1210 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1211 </code></pre>
1212  * @param {String} input The unparsed date as a string
1213  * @param {String} format The format the date is in
1214  * @return {Date} The parsed date
1215  * @static
1216  */
1217 Date.parseDate = function(input, format) {
1218     if (Date.parseFunctions[format] == null) {
1219         Date.createParser(format);
1220     }
1221     var func = Date.parseFunctions[format];
1222     return Date[func](input);
1223 };
1224 /**
1225  * @private
1226  */
1227 Date.createParser = function(format) {
1228     var funcName = "parse" + Date.parseFunctions.count++;
1229     var regexNum = Date.parseRegexes.length;
1230     var currentGroup = 1;
1231     Date.parseFunctions[format] = funcName;
1232
1233     var code = "Date." + funcName + " = function(input){\n"
1234         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1235         + "var d = new Date();\n"
1236         + "y = d.getFullYear();\n"
1237         + "m = d.getMonth();\n"
1238         + "d = d.getDate();\n"
1239         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1240         + "if (results && results.length > 0) {";
1241     var regex = "";
1242
1243     var special = false;
1244     var ch = '';
1245     for (var i = 0; i < format.length; ++i) {
1246         ch = format.charAt(i);
1247         if (!special && ch == "\\") {
1248             special = true;
1249         }
1250         else if (special) {
1251             special = false;
1252             regex += String.escape(ch);
1253         }
1254         else {
1255             var obj = Date.formatCodeToRegex(ch, currentGroup);
1256             currentGroup += obj.g;
1257             regex += obj.s;
1258             if (obj.g && obj.c) {
1259                 code += obj.c;
1260             }
1261         }
1262     }
1263
1264     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1265         + "{v = new Date(y, m, d, h, i, s);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1267         + "{v = new Date(y, m, d, h, i);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1269         + "{v = new Date(y, m, d, h);}\n"
1270         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1271         + "{v = new Date(y, m, d);}\n"
1272         + "else if (y >= 0 && m >= 0)\n"
1273         + "{v = new Date(y, m);}\n"
1274         + "else if (y >= 0)\n"
1275         + "{v = new Date(y);}\n"
1276         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1277         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1278         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1279         + ";}";
1280
1281     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1282     /** eval:var:zzzzzzzzzzzzz */
1283     eval(code);
1284 };
1285
1286 // private
1287 Date.formatCodeToRegex = function(character, currentGroup) {
1288     switch (character) {
1289     case "D":
1290         return {g:0,
1291         c:null,
1292         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1293     case "j":
1294         return {g:1,
1295             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296             s:"(\\d{1,2})"}; // day of month without leading zeroes
1297     case "d":
1298         return {g:1,
1299             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1300             s:"(\\d{2})"}; // day of month with leading zeroes
1301     case "l":
1302         return {g:0,
1303             c:null,
1304             s:"(?:" + Date.dayNames.join("|") + ")"};
1305     case "S":
1306         return {g:0,
1307             c:null,
1308             s:"(?:st|nd|rd|th)"};
1309     case "w":
1310         return {g:0,
1311             c:null,
1312             s:"\\d"};
1313     case "z":
1314         return {g:0,
1315             c:null,
1316             s:"(?:\\d{1,3})"};
1317     case "W":
1318         return {g:0,
1319             c:null,
1320             s:"(?:\\d{2})"};
1321     case "F":
1322         return {g:1,
1323             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1324             s:"(" + Date.monthNames.join("|") + ")"};
1325     case "M":
1326         return {g:1,
1327             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1328             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1329     case "n":
1330         return {g:1,
1331             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1333     case "m":
1334         return {g:1,
1335             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1336             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1337     case "t":
1338         return {g:0,
1339             c:null,
1340             s:"\\d{1,2}"};
1341     case "L":
1342         return {g:0,
1343             c:null,
1344             s:"(?:1|0)"};
1345     case "Y":
1346         return {g:1,
1347             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1348             s:"(\\d{4})"};
1349     case "y":
1350         return {g:1,
1351             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1352                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1353             s:"(\\d{1,2})"};
1354     case "a":
1355         return {g:1,
1356             c:"if (results[" + currentGroup + "] == 'am') {\n"
1357                 + "if (h == 12) { h = 0; }\n"
1358                 + "} else { if (h < 12) { h += 12; }}",
1359             s:"(am|pm)"};
1360     case "A":
1361         return {g:1,
1362             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1363                 + "if (h == 12) { h = 0; }\n"
1364                 + "} else { if (h < 12) { h += 12; }}",
1365             s:"(AM|PM)"};
1366     case "g":
1367     case "G":
1368         return {g:1,
1369             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1370             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1371     case "h":
1372     case "H":
1373         return {g:1,
1374             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1375             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1376     case "i":
1377         return {g:1,
1378             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1379             s:"(\\d{2})"};
1380     case "s":
1381         return {g:1,
1382             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1383             s:"(\\d{2})"};
1384     case "O":
1385         return {g:1,
1386             c:[
1387                 "o = results[", currentGroup, "];\n",
1388                 "var sn = o.substring(0,1);\n", // get + / - sign
1389                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1390                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1391                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1392                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1393             ].join(""),
1394             s:"([+\-]\\d{2,4})"};
1395     
1396     
1397     case "P":
1398         return {g:1,
1399                 c:[
1400                    "o = results[", currentGroup, "];\n",
1401                    "var sn = o.substring(0,1);\n",
1402                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1403                    "var mn = o.substring(4,6) % 60;\n",
1404                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1405                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1406             ].join(""),
1407             s:"([+\-]\\d{4})"};
1408     case "T":
1409         return {g:0,
1410             c:null,
1411             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1412     case "Z":
1413         return {g:1,
1414             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1415                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1416             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1417     default:
1418         return {g:0,
1419             c:null,
1420             s:String.escape(character)};
1421     }
1422 };
1423
1424 /**
1425  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1426  * @return {String} The abbreviated timezone name (e.g. 'CST')
1427  */
1428 Date.prototype.getTimezone = function() {
1429     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1430 };
1431
1432 /**
1433  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1434  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1435  */
1436 Date.prototype.getGMTOffset = function() {
1437     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1438         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1439         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1440 };
1441
1442 /**
1443  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1444  * @return {String} 2-characters representing hours and 2-characters representing minutes
1445  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1446  */
1447 Date.prototype.getGMTColonOffset = function() {
1448         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1449                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1450                 + ":"
1451                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1452 }
1453
1454 /**
1455  * Get the numeric day number of the year, adjusted for leap year.
1456  * @return {Number} 0 through 364 (365 in leap years)
1457  */
1458 Date.prototype.getDayOfYear = function() {
1459     var num = 0;
1460     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1461     for (var i = 0; i < this.getMonth(); ++i) {
1462         num += Date.daysInMonth[i];
1463     }
1464     return num + this.getDate() - 1;
1465 };
1466
1467 /**
1468  * Get the string representation of the numeric week number of the year
1469  * (equivalent to the format specifier 'W').
1470  * @return {String} '00' through '52'
1471  */
1472 Date.prototype.getWeekOfYear = function() {
1473     // Skip to Thursday of this week
1474     var now = this.getDayOfYear() + (4 - this.getDay());
1475     // Find the first Thursday of the year
1476     var jan1 = new Date(this.getFullYear(), 0, 1);
1477     var then = (7 - jan1.getDay() + 4);
1478     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1479 };
1480
1481 /**
1482  * Whether or not the current date is in a leap year.
1483  * @return {Boolean} True if the current date is in a leap year, else false
1484  */
1485 Date.prototype.isLeapYear = function() {
1486     var year = this.getFullYear();
1487     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1488 };
1489
1490 /**
1491  * Get the first day of the current month, adjusted for leap year.  The returned value
1492  * is the numeric day index within the week (0-6) which can be used in conjunction with
1493  * the {@link #monthNames} array to retrieve the textual day name.
1494  * Example:
1495  *<pre><code>
1496 var dt = new Date('1/10/2007');
1497 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1498 </code></pre>
1499  * @return {Number} The day number (0-6)
1500  */
1501 Date.prototype.getFirstDayOfMonth = function() {
1502     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1503     return (day < 0) ? (day + 7) : day;
1504 };
1505
1506 /**
1507  * Get the last day of the current month, adjusted for leap year.  The returned value
1508  * is the numeric day index within the week (0-6) which can be used in conjunction with
1509  * the {@link #monthNames} array to retrieve the textual day name.
1510  * Example:
1511  *<pre><code>
1512 var dt = new Date('1/10/2007');
1513 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1514 </code></pre>
1515  * @return {Number} The day number (0-6)
1516  */
1517 Date.prototype.getLastDayOfMonth = function() {
1518     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1519     return (day < 0) ? (day + 7) : day;
1520 };
1521
1522
1523 /**
1524  * Get the first date of this date's month
1525  * @return {Date}
1526  */
1527 Date.prototype.getFirstDateOfMonth = function() {
1528     return new Date(this.getFullYear(), this.getMonth(), 1);
1529 };
1530
1531 /**
1532  * Get the last date of this date's month
1533  * @return {Date}
1534  */
1535 Date.prototype.getLastDateOfMonth = function() {
1536     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1537 };
1538 /**
1539  * Get the number of days in the current month, adjusted for leap year.
1540  * @return {Number} The number of days in the month
1541  */
1542 Date.prototype.getDaysInMonth = function() {
1543     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1544     return Date.daysInMonth[this.getMonth()];
1545 };
1546
1547 /**
1548  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1549  * @return {String} 'st, 'nd', 'rd' or 'th'
1550  */
1551 Date.prototype.getSuffix = function() {
1552     switch (this.getDate()) {
1553         case 1:
1554         case 21:
1555         case 31:
1556             return "st";
1557         case 2:
1558         case 22:
1559             return "nd";
1560         case 3:
1561         case 23:
1562             return "rd";
1563         default:
1564             return "th";
1565     }
1566 };
1567
1568 // private
1569 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1570
1571 /**
1572  * An array of textual month names.
1573  * Override these values for international dates, for example...
1574  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1575  * @type Array
1576  * @static
1577  */
1578 Date.monthNames =
1579    ["January",
1580     "February",
1581     "March",
1582     "April",
1583     "May",
1584     "June",
1585     "July",
1586     "August",
1587     "September",
1588     "October",
1589     "November",
1590     "December"];
1591
1592 /**
1593  * An array of textual day names.
1594  * Override these values for international dates, for example...
1595  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1596  * @type Array
1597  * @static
1598  */
1599 Date.dayNames =
1600    ["Sunday",
1601     "Monday",
1602     "Tuesday",
1603     "Wednesday",
1604     "Thursday",
1605     "Friday",
1606     "Saturday"];
1607
1608 // private
1609 Date.y2kYear = 50;
1610 // private
1611 Date.monthNumbers = {
1612     Jan:0,
1613     Feb:1,
1614     Mar:2,
1615     Apr:3,
1616     May:4,
1617     Jun:5,
1618     Jul:6,
1619     Aug:7,
1620     Sep:8,
1621     Oct:9,
1622     Nov:10,
1623     Dec:11};
1624
1625 /**
1626  * Creates and returns a new Date instance with the exact same date value as the called instance.
1627  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1628  * variable will also be changed.  When the intention is to create a new variable that will not
1629  * modify the original instance, you should create a clone.
1630  *
1631  * Example of correctly cloning a date:
1632  * <pre><code>
1633 //wrong way:
1634 var orig = new Date('10/1/2006');
1635 var copy = orig;
1636 copy.setDate(5);
1637 document.write(orig);  //returns 'Thu Oct 05 2006'!
1638
1639 //correct way:
1640 var orig = new Date('10/1/2006');
1641 var copy = orig.clone();
1642 copy.setDate(5);
1643 document.write(orig);  //returns 'Thu Oct 01 2006'
1644 </code></pre>
1645  * @return {Date} The new Date instance
1646  */
1647 Date.prototype.clone = function() {
1648         return new Date(this.getTime());
1649 };
1650
1651 /**
1652  * Clears any time information from this date
1653  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1654  @return {Date} this or the clone
1655  */
1656 Date.prototype.clearTime = function(clone){
1657     if(clone){
1658         return this.clone().clearTime();
1659     }
1660     this.setHours(0);
1661     this.setMinutes(0);
1662     this.setSeconds(0);
1663     this.setMilliseconds(0);
1664     return this;
1665 };
1666
1667 // private
1668 // safari setMonth is broken
1669 if(Roo.isSafari){
1670     Date.brokenSetMonth = Date.prototype.setMonth;
1671         Date.prototype.setMonth = function(num){
1672                 if(num <= -1){
1673                         var n = Math.ceil(-num);
1674                         var back_year = Math.ceil(n/12);
1675                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1676                         this.setFullYear(this.getFullYear() - back_year);
1677                         return Date.brokenSetMonth.call(this, month);
1678                 } else {
1679                         return Date.brokenSetMonth.apply(this, arguments);
1680                 }
1681         };
1682 }
1683
1684 /** Date interval constant 
1685 * @static 
1686 * @type String */
1687 Date.MILLI = "ms";
1688 /** Date interval constant 
1689 * @static 
1690 * @type String */
1691 Date.SECOND = "s";
1692 /** Date interval constant 
1693 * @static 
1694 * @type String */
1695 Date.MINUTE = "mi";
1696 /** Date interval constant 
1697 * @static 
1698 * @type String */
1699 Date.HOUR = "h";
1700 /** Date interval constant 
1701 * @static 
1702 * @type String */
1703 Date.DAY = "d";
1704 /** Date interval constant 
1705 * @static 
1706 * @type String */
1707 Date.MONTH = "mo";
1708 /** Date interval constant 
1709 * @static 
1710 * @type String */
1711 Date.YEAR = "y";
1712
1713 /**
1714  * Provides a convenient method of performing basic date arithmetic.  This method
1715  * does not modify the Date instance being called - it creates and returns
1716  * a new Date instance containing the resulting date value.
1717  *
1718  * Examples:
1719  * <pre><code>
1720 //Basic usage:
1721 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1722 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1723
1724 //Negative values will subtract correctly:
1725 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1726 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1727
1728 //You can even chain several calls together in one line!
1729 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1730 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1731  </code></pre>
1732  *
1733  * @param {String} interval   A valid date interval enum value
1734  * @param {Number} value      The amount to add to the current date
1735  * @return {Date} The new Date instance
1736  */
1737 Date.prototype.add = function(interval, value){
1738   var d = this.clone();
1739   if (!interval || value === 0) return d;
1740   switch(interval.toLowerCase()){
1741     case Date.MILLI:
1742       d.setMilliseconds(this.getMilliseconds() + value);
1743       break;
1744     case Date.SECOND:
1745       d.setSeconds(this.getSeconds() + value);
1746       break;
1747     case Date.MINUTE:
1748       d.setMinutes(this.getMinutes() + value);
1749       break;
1750     case Date.HOUR:
1751       d.setHours(this.getHours() + value);
1752       break;
1753     case Date.DAY:
1754       d.setDate(this.getDate() + value);
1755       break;
1756     case Date.MONTH:
1757       var day = this.getDate();
1758       if(day > 28){
1759           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1760       }
1761       d.setDate(day);
1762       d.setMonth(this.getMonth() + value);
1763       break;
1764     case Date.YEAR:
1765       d.setFullYear(this.getFullYear() + value);
1766       break;
1767   }
1768   return d;
1769 };
1770 /*
1771  * Based on:
1772  * Ext JS Library 1.1.1
1773  * Copyright(c) 2006-2007, Ext JS, LLC.
1774  *
1775  * Originally Released Under LGPL - original licence link has changed is not relivant.
1776  *
1777  * Fork - LGPL
1778  * <script type="text/javascript">
1779  */
1780
1781 /**
1782  * @class Roo.lib.Dom
1783  * @static
1784  * 
1785  * Dom utils (from YIU afaik)
1786  * 
1787  **/
1788 Roo.lib.Dom = {
1789     /**
1790      * Get the view width
1791      * @param {Boolean} full True will get the full document, otherwise it's the view width
1792      * @return {Number} The width
1793      */
1794      
1795     getViewWidth : function(full) {
1796         return full ? this.getDocumentWidth() : this.getViewportWidth();
1797     },
1798     /**
1799      * Get the view height
1800      * @param {Boolean} full True will get the full document, otherwise it's the view height
1801      * @return {Number} The height
1802      */
1803     getViewHeight : function(full) {
1804         return full ? this.getDocumentHeight() : this.getViewportHeight();
1805     },
1806
1807     getDocumentHeight: function() {
1808         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1809         return Math.max(scrollHeight, this.getViewportHeight());
1810     },
1811
1812     getDocumentWidth: function() {
1813         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1814         return Math.max(scrollWidth, this.getViewportWidth());
1815     },
1816
1817     getViewportHeight: function() {
1818         var height = self.innerHeight;
1819         var mode = document.compatMode;
1820
1821         if ((mode || Roo.isIE) && !Roo.isOpera) {
1822             height = (mode == "CSS1Compat") ?
1823                      document.documentElement.clientHeight :
1824                      document.body.clientHeight;
1825         }
1826
1827         return height;
1828     },
1829
1830     getViewportWidth: function() {
1831         var width = self.innerWidth;
1832         var mode = document.compatMode;
1833
1834         if (mode || Roo.isIE) {
1835             width = (mode == "CSS1Compat") ?
1836                     document.documentElement.clientWidth :
1837                     document.body.clientWidth;
1838         }
1839         return width;
1840     },
1841
1842     isAncestor : function(p, c) {
1843         p = Roo.getDom(p);
1844         c = Roo.getDom(c);
1845         if (!p || !c) {
1846             return false;
1847         }
1848
1849         if (p.contains && !Roo.isSafari) {
1850             return p.contains(c);
1851         } else if (p.compareDocumentPosition) {
1852             return !!(p.compareDocumentPosition(c) & 16);
1853         } else {
1854             var parent = c.parentNode;
1855             while (parent) {
1856                 if (parent == p) {
1857                     return true;
1858                 }
1859                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1860                     return false;
1861                 }
1862                 parent = parent.parentNode;
1863             }
1864             return false;
1865         }
1866     },
1867
1868     getRegion : function(el) {
1869         return Roo.lib.Region.getRegion(el);
1870     },
1871
1872     getY : function(el) {
1873         return this.getXY(el)[1];
1874     },
1875
1876     getX : function(el) {
1877         return this.getXY(el)[0];
1878     },
1879
1880     getXY : function(el) {
1881         var p, pe, b, scroll, bd = document.body;
1882         el = Roo.getDom(el);
1883         var fly = Roo.lib.AnimBase.fly;
1884         if (el.getBoundingClientRect) {
1885             b = el.getBoundingClientRect();
1886             scroll = fly(document).getScroll();
1887             return [b.left + scroll.left, b.top + scroll.top];
1888         }
1889         var x = 0, y = 0;
1890
1891         p = el;
1892
1893         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1894
1895         while (p) {
1896
1897             x += p.offsetLeft;
1898             y += p.offsetTop;
1899
1900             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1901                 hasAbsolute = true;
1902             }
1903
1904             if (Roo.isGecko) {
1905                 pe = fly(p);
1906
1907                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1908                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1909
1910
1911                 x += bl;
1912                 y += bt;
1913
1914
1915                 if (p != el && pe.getStyle('overflow') != 'visible') {
1916                     x += bl;
1917                     y += bt;
1918                 }
1919             }
1920             p = p.offsetParent;
1921         }
1922
1923         if (Roo.isSafari && hasAbsolute) {
1924             x -= bd.offsetLeft;
1925             y -= bd.offsetTop;
1926         }
1927
1928         if (Roo.isGecko && !hasAbsolute) {
1929             var dbd = fly(bd);
1930             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1931             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1932         }
1933
1934         p = el.parentNode;
1935         while (p && p != bd) {
1936             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1937                 x -= p.scrollLeft;
1938                 y -= p.scrollTop;
1939             }
1940             p = p.parentNode;
1941         }
1942         return [x, y];
1943     },
1944  
1945   
1946
1947
1948     setXY : function(el, xy) {
1949         el = Roo.fly(el, '_setXY');
1950         el.position();
1951         var pts = el.translatePoints(xy);
1952         if (xy[0] !== false) {
1953             el.dom.style.left = pts.left + "px";
1954         }
1955         if (xy[1] !== false) {
1956             el.dom.style.top = pts.top + "px";
1957         }
1958     },
1959
1960     setX : function(el, x) {
1961         this.setXY(el, [x, false]);
1962     },
1963
1964     setY : function(el, y) {
1965         this.setXY(el, [false, y]);
1966     }
1967 };
1968 /*
1969  * Portions of this file are based on pieces of Yahoo User Interface Library
1970  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1971  * YUI licensed under the BSD License:
1972  * http://developer.yahoo.net/yui/license.txt
1973  * <script type="text/javascript">
1974  *
1975  */
1976
1977 Roo.lib.Event = function() {
1978     var loadComplete = false;
1979     var listeners = [];
1980     var unloadListeners = [];
1981     var retryCount = 0;
1982     var onAvailStack = [];
1983     var counter = 0;
1984     var lastError = null;
1985
1986     return {
1987         POLL_RETRYS: 200,
1988         POLL_INTERVAL: 20,
1989         EL: 0,
1990         TYPE: 1,
1991         FN: 2,
1992         WFN: 3,
1993         OBJ: 3,
1994         ADJ_SCOPE: 4,
1995         _interval: null,
1996
1997         startInterval: function() {
1998             if (!this._interval) {
1999                 var self = this;
2000                 var callback = function() {
2001                     self._tryPreloadAttach();
2002                 };
2003                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2004
2005             }
2006         },
2007
2008         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2009             onAvailStack.push({ id:         p_id,
2010                 fn:         p_fn,
2011                 obj:        p_obj,
2012                 override:   p_override,
2013                 checkReady: false    });
2014
2015             retryCount = this.POLL_RETRYS;
2016             this.startInterval();
2017         },
2018
2019
2020         addListener: function(el, eventName, fn) {
2021             el = Roo.getDom(el);
2022             if (!el || !fn) {
2023                 return false;
2024             }
2025
2026             if ("unload" == eventName) {
2027                 unloadListeners[unloadListeners.length] =
2028                 [el, eventName, fn];
2029                 return true;
2030             }
2031
2032             var wrappedFn = function(e) {
2033                 return fn(Roo.lib.Event.getEvent(e));
2034             };
2035
2036             var li = [el, eventName, fn, wrappedFn];
2037
2038             var index = listeners.length;
2039             listeners[index] = li;
2040
2041             this.doAdd(el, eventName, wrappedFn, false);
2042             return true;
2043
2044         },
2045
2046
2047         removeListener: function(el, eventName, fn) {
2048             var i, len;
2049
2050             el = Roo.getDom(el);
2051
2052             if(!fn) {
2053                 return this.purgeElement(el, false, eventName);
2054             }
2055
2056
2057             if ("unload" == eventName) {
2058
2059                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2060                     var li = unloadListeners[i];
2061                     if (li &&
2062                         li[0] == el &&
2063                         li[1] == eventName &&
2064                         li[2] == fn) {
2065                         unloadListeners.splice(i, 1);
2066                         return true;
2067                     }
2068                 }
2069
2070                 return false;
2071             }
2072
2073             var cacheItem = null;
2074
2075
2076             var index = arguments[3];
2077
2078             if ("undefined" == typeof index) {
2079                 index = this._getCacheIndex(el, eventName, fn);
2080             }
2081
2082             if (index >= 0) {
2083                 cacheItem = listeners[index];
2084             }
2085
2086             if (!el || !cacheItem) {
2087                 return false;
2088             }
2089
2090             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2091
2092             delete listeners[index][this.WFN];
2093             delete listeners[index][this.FN];
2094             listeners.splice(index, 1);
2095
2096             return true;
2097
2098         },
2099
2100
2101         getTarget: function(ev, resolveTextNode) {
2102             ev = ev.browserEvent || ev;
2103             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2104             var t = ev.target || ev.srcElement;
2105             return this.resolveTextNode(t);
2106         },
2107
2108
2109         resolveTextNode: function(node) {
2110             if (Roo.isSafari && node && 3 == node.nodeType) {
2111                 return node.parentNode;
2112             } else {
2113                 return node;
2114             }
2115         },
2116
2117
2118         getPageX: function(ev) {
2119             ev = ev.browserEvent || ev;
2120             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2121             var x = ev.pageX;
2122             if (!x && 0 !== x) {
2123                 x = ev.clientX || 0;
2124
2125                 if (Roo.isIE) {
2126                     x += this.getScroll()[1];
2127                 }
2128             }
2129
2130             return x;
2131         },
2132
2133
2134         getPageY: function(ev) {
2135             ev = ev.browserEvent || ev;
2136             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2137             var y = ev.pageY;
2138             if (!y && 0 !== y) {
2139                 y = ev.clientY || 0;
2140
2141                 if (Roo.isIE) {
2142                     y += this.getScroll()[0];
2143                 }
2144             }
2145
2146
2147             return y;
2148         },
2149
2150
2151         getXY: function(ev) {
2152             ev = ev.browserEvent || ev;
2153             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2154             return [this.getPageX(ev), this.getPageY(ev)];
2155         },
2156
2157
2158         getRelatedTarget: function(ev) {
2159             ev = ev.browserEvent || ev;
2160             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2161             var t = ev.relatedTarget;
2162             if (!t) {
2163                 if (ev.type == "mouseout") {
2164                     t = ev.toElement;
2165                 } else if (ev.type == "mouseover") {
2166                     t = ev.fromElement;
2167                 }
2168             }
2169
2170             return this.resolveTextNode(t);
2171         },
2172
2173
2174         getTime: function(ev) {
2175             ev = ev.browserEvent || ev;
2176             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2177             if (!ev.time) {
2178                 var t = new Date().getTime();
2179                 try {
2180                     ev.time = t;
2181                 } catch(ex) {
2182                     this.lastError = ex;
2183                     return t;
2184                 }
2185             }
2186
2187             return ev.time;
2188         },
2189
2190
2191         stopEvent: function(ev) {
2192             this.stopPropagation(ev);
2193             this.preventDefault(ev);
2194         },
2195
2196
2197         stopPropagation: function(ev) {
2198             ev = ev.browserEvent || ev;
2199             if (ev.stopPropagation) {
2200                 ev.stopPropagation();
2201             } else {
2202                 ev.cancelBubble = true;
2203             }
2204         },
2205
2206
2207         preventDefault: function(ev) {
2208             ev = ev.browserEvent || ev;
2209             if(ev.preventDefault) {
2210                 ev.preventDefault();
2211             } else {
2212                 ev.returnValue = false;
2213             }
2214         },
2215
2216
2217         getEvent: function(e) {
2218             var ev = e || window.event;
2219             if (!ev) {
2220                 var c = this.getEvent.caller;
2221                 while (c) {
2222                     ev = c.arguments[0];
2223                     if (ev && Event == ev.constructor) {
2224                         break;
2225                     }
2226                     c = c.caller;
2227                 }
2228             }
2229             return ev;
2230         },
2231
2232
2233         getCharCode: function(ev) {
2234             ev = ev.browserEvent || ev;
2235             return ev.charCode || ev.keyCode || 0;
2236         },
2237
2238
2239         _getCacheIndex: function(el, eventName, fn) {
2240             for (var i = 0,len = listeners.length; i < len; ++i) {
2241                 var li = listeners[i];
2242                 if (li &&
2243                     li[this.FN] == fn &&
2244                     li[this.EL] == el &&
2245                     li[this.TYPE] == eventName) {
2246                     return i;
2247                 }
2248             }
2249
2250             return -1;
2251         },
2252
2253
2254         elCache: {},
2255
2256
2257         getEl: function(id) {
2258             return document.getElementById(id);
2259         },
2260
2261
2262         clearCache: function() {
2263         },
2264
2265
2266         _load: function(e) {
2267             loadComplete = true;
2268             var EU = Roo.lib.Event;
2269
2270
2271             if (Roo.isIE) {
2272                 EU.doRemove(window, "load", EU._load);
2273             }
2274         },
2275
2276
2277         _tryPreloadAttach: function() {
2278
2279             if (this.locked) {
2280                 return false;
2281             }
2282
2283             this.locked = true;
2284
2285
2286             var tryAgain = !loadComplete;
2287             if (!tryAgain) {
2288                 tryAgain = (retryCount > 0);
2289             }
2290
2291
2292             var notAvail = [];
2293             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2294                 var item = onAvailStack[i];
2295                 if (item) {
2296                     var el = this.getEl(item.id);
2297
2298                     if (el) {
2299                         if (!item.checkReady ||
2300                             loadComplete ||
2301                             el.nextSibling ||
2302                             (document && document.body)) {
2303
2304                             var scope = el;
2305                             if (item.override) {
2306                                 if (item.override === true) {
2307                                     scope = item.obj;
2308                                 } else {
2309                                     scope = item.override;
2310                                 }
2311                             }
2312                             item.fn.call(scope, item.obj);
2313                             onAvailStack[i] = null;
2314                         }
2315                     } else {
2316                         notAvail.push(item);
2317                     }
2318                 }
2319             }
2320
2321             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2322
2323             if (tryAgain) {
2324
2325                 this.startInterval();
2326             } else {
2327                 clearInterval(this._interval);
2328                 this._interval = null;
2329             }
2330
2331             this.locked = false;
2332
2333             return true;
2334
2335         },
2336
2337
2338         purgeElement: function(el, recurse, eventName) {
2339             var elListeners = this.getListeners(el, eventName);
2340             if (elListeners) {
2341                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2342                     var l = elListeners[i];
2343                     this.removeListener(el, l.type, l.fn);
2344                 }
2345             }
2346
2347             if (recurse && el && el.childNodes) {
2348                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2349                     this.purgeElement(el.childNodes[i], recurse, eventName);
2350                 }
2351             }
2352         },
2353
2354
2355         getListeners: function(el, eventName) {
2356             var results = [], searchLists;
2357             if (!eventName) {
2358                 searchLists = [listeners, unloadListeners];
2359             } else if (eventName == "unload") {
2360                 searchLists = [unloadListeners];
2361             } else {
2362                 searchLists = [listeners];
2363             }
2364
2365             for (var j = 0; j < searchLists.length; ++j) {
2366                 var searchList = searchLists[j];
2367                 if (searchList && searchList.length > 0) {
2368                     for (var i = 0,len = searchList.length; i < len; ++i) {
2369                         var l = searchList[i];
2370                         if (l && l[this.EL] === el &&
2371                             (!eventName || eventName === l[this.TYPE])) {
2372                             results.push({
2373                                 type:   l[this.TYPE],
2374                                 fn:     l[this.FN],
2375                                 obj:    l[this.OBJ],
2376                                 adjust: l[this.ADJ_SCOPE],
2377                                 index:  i
2378                             });
2379                         }
2380                     }
2381                 }
2382             }
2383
2384             return (results.length) ? results : null;
2385         },
2386
2387
2388         _unload: function(e) {
2389
2390             var EU = Roo.lib.Event, i, j, l, len, index;
2391
2392             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2393                 l = unloadListeners[i];
2394                 if (l) {
2395                     var scope = window;
2396                     if (l[EU.ADJ_SCOPE]) {
2397                         if (l[EU.ADJ_SCOPE] === true) {
2398                             scope = l[EU.OBJ];
2399                         } else {
2400                             scope = l[EU.ADJ_SCOPE];
2401                         }
2402                     }
2403                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2404                     unloadListeners[i] = null;
2405                     l = null;
2406                     scope = null;
2407                 }
2408             }
2409
2410             unloadListeners = null;
2411
2412             if (listeners && listeners.length > 0) {
2413                 j = listeners.length;
2414                 while (j) {
2415                     index = j - 1;
2416                     l = listeners[index];
2417                     if (l) {
2418                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2419                                 l[EU.FN], index);
2420                     }
2421                     j = j - 1;
2422                 }
2423                 l = null;
2424
2425                 EU.clearCache();
2426             }
2427
2428             EU.doRemove(window, "unload", EU._unload);
2429
2430         },
2431
2432
2433         getScroll: function() {
2434             var dd = document.documentElement, db = document.body;
2435             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2436                 return [dd.scrollTop, dd.scrollLeft];
2437             } else if (db) {
2438                 return [db.scrollTop, db.scrollLeft];
2439             } else {
2440                 return [0, 0];
2441             }
2442         },
2443
2444
2445         doAdd: function () {
2446             if (window.addEventListener) {
2447                 return function(el, eventName, fn, capture) {
2448                     el.addEventListener(eventName, fn, (capture));
2449                 };
2450             } else if (window.attachEvent) {
2451                 return function(el, eventName, fn, capture) {
2452                     el.attachEvent("on" + eventName, fn);
2453                 };
2454             } else {
2455                 return function() {
2456                 };
2457             }
2458         }(),
2459
2460
2461         doRemove: function() {
2462             if (window.removeEventListener) {
2463                 return function (el, eventName, fn, capture) {
2464                     el.removeEventListener(eventName, fn, (capture));
2465                 };
2466             } else if (window.detachEvent) {
2467                 return function (el, eventName, fn) {
2468                     el.detachEvent("on" + eventName, fn);
2469                 };
2470             } else {
2471                 return function() {
2472                 };
2473             }
2474         }()
2475     };
2476     
2477 }();
2478 (function() {     
2479    
2480     var E = Roo.lib.Event;
2481     E.on = E.addListener;
2482     E.un = E.removeListener;
2483
2484     if (document && document.body) {
2485         E._load();
2486     } else {
2487         E.doAdd(window, "load", E._load);
2488     }
2489     E.doAdd(window, "unload", E._unload);
2490     E._tryPreloadAttach();
2491 })();
2492
2493 /*
2494  * Portions of this file are based on pieces of Yahoo User Interface Library
2495  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2496  * YUI licensed under the BSD License:
2497  * http://developer.yahoo.net/yui/license.txt
2498  * <script type="text/javascript">
2499  *
2500  */
2501
2502 (function() {
2503     /**
2504      * @class Roo.lib.Ajax
2505      *
2506      */
2507     Roo.lib.Ajax = {
2508         /**
2509          * @static 
2510          */
2511         request : function(method, uri, cb, data, options) {
2512             if(options){
2513                 var hs = options.headers;
2514                 if(hs){
2515                     for(var h in hs){
2516                         if(hs.hasOwnProperty(h)){
2517                             this.initHeader(h, hs[h], false);
2518                         }
2519                     }
2520                 }
2521                 if(options.xmlData){
2522                     this.initHeader('Content-Type', 'text/xml', false);
2523                     method = 'POST';
2524                     data = options.xmlData;
2525                 }
2526             }
2527
2528             return this.asyncRequest(method, uri, cb, data);
2529         },
2530
2531         serializeForm : function(form) {
2532             if(typeof form == 'string') {
2533                 form = (document.getElementById(form) || document.forms[form]);
2534             }
2535
2536             var el, name, val, disabled, data = '', hasSubmit = false;
2537             for (var i = 0; i < form.elements.length; i++) {
2538                 el = form.elements[i];
2539                 disabled = form.elements[i].disabled;
2540                 name = form.elements[i].name;
2541                 val = form.elements[i].value;
2542
2543                 if (!disabled && name){
2544                     switch (el.type)
2545                             {
2546                         case 'select-one':
2547                         case 'select-multiple':
2548                             for (var j = 0; j < el.options.length; j++) {
2549                                 if (el.options[j].selected) {
2550                                     if (Roo.isIE) {
2551                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2552                                     }
2553                                     else {
2554                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2555                                     }
2556                                 }
2557                             }
2558                             break;
2559                         case 'radio':
2560                         case 'checkbox':
2561                             if (el.checked) {
2562                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2563                             }
2564                             break;
2565                         case 'file':
2566
2567                         case undefined:
2568
2569                         case 'reset':
2570
2571                         case 'button':
2572
2573                             break;
2574                         case 'submit':
2575                             if(hasSubmit == false) {
2576                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2577                                 hasSubmit = true;
2578                             }
2579                             break;
2580                         default:
2581                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2582                             break;
2583                     }
2584                 }
2585             }
2586             data = data.substr(0, data.length - 1);
2587             return data;
2588         },
2589
2590         headers:{},
2591
2592         hasHeaders:false,
2593
2594         useDefaultHeader:true,
2595
2596         defaultPostHeader:'application/x-www-form-urlencoded',
2597
2598         useDefaultXhrHeader:true,
2599
2600         defaultXhrHeader:'XMLHttpRequest',
2601
2602         hasDefaultHeaders:true,
2603
2604         defaultHeaders:{},
2605
2606         poll:{},
2607
2608         timeout:{},
2609
2610         pollInterval:50,
2611
2612         transactionId:0,
2613
2614         setProgId:function(id)
2615         {
2616             this.activeX.unshift(id);
2617         },
2618
2619         setDefaultPostHeader:function(b)
2620         {
2621             this.useDefaultHeader = b;
2622         },
2623
2624         setDefaultXhrHeader:function(b)
2625         {
2626             this.useDefaultXhrHeader = b;
2627         },
2628
2629         setPollingInterval:function(i)
2630         {
2631             if (typeof i == 'number' && isFinite(i)) {
2632                 this.pollInterval = i;
2633             }
2634         },
2635
2636         createXhrObject:function(transactionId)
2637         {
2638             var obj,http;
2639             try
2640             {
2641
2642                 http = new XMLHttpRequest();
2643
2644                 obj = { conn:http, tId:transactionId };
2645             }
2646             catch(e)
2647             {
2648                 for (var i = 0; i < this.activeX.length; ++i) {
2649                     try
2650                     {
2651
2652                         http = new ActiveXObject(this.activeX[i]);
2653
2654                         obj = { conn:http, tId:transactionId };
2655                         break;
2656                     }
2657                     catch(e) {
2658                     }
2659                 }
2660             }
2661             finally
2662             {
2663                 return obj;
2664             }
2665         },
2666
2667         getConnectionObject:function()
2668         {
2669             var o;
2670             var tId = this.transactionId;
2671
2672             try
2673             {
2674                 o = this.createXhrObject(tId);
2675                 if (o) {
2676                     this.transactionId++;
2677                 }
2678             }
2679             catch(e) {
2680             }
2681             finally
2682             {
2683                 return o;
2684             }
2685         },
2686
2687         asyncRequest:function(method, uri, callback, postData)
2688         {
2689             var o = this.getConnectionObject();
2690
2691             if (!o) {
2692                 return null;
2693             }
2694             else {
2695                 o.conn.open(method, uri, true);
2696
2697                 if (this.useDefaultXhrHeader) {
2698                     if (!this.defaultHeaders['X-Requested-With']) {
2699                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2700                     }
2701                 }
2702
2703                 if(postData && this.useDefaultHeader){
2704                     this.initHeader('Content-Type', this.defaultPostHeader);
2705                 }
2706
2707                  if (this.hasDefaultHeaders || this.hasHeaders) {
2708                     this.setHeader(o);
2709                 }
2710
2711                 this.handleReadyState(o, callback);
2712                 o.conn.send(postData || null);
2713
2714                 return o;
2715             }
2716         },
2717
2718         handleReadyState:function(o, callback)
2719         {
2720             var oConn = this;
2721
2722             if (callback && callback.timeout) {
2723                 
2724                 this.timeout[o.tId] = window.setTimeout(function() {
2725                     oConn.abort(o, callback, true);
2726                 }, callback.timeout);
2727             }
2728
2729             this.poll[o.tId] = window.setInterval(
2730                     function() {
2731                         if (o.conn && o.conn.readyState == 4) {
2732                             window.clearInterval(oConn.poll[o.tId]);
2733                             delete oConn.poll[o.tId];
2734
2735                             if(callback && callback.timeout) {
2736                                 window.clearTimeout(oConn.timeout[o.tId]);
2737                                 delete oConn.timeout[o.tId];
2738                             }
2739
2740                             oConn.handleTransactionResponse(o, callback);
2741                         }
2742                     }
2743                     , this.pollInterval);
2744         },
2745
2746         handleTransactionResponse:function(o, callback, isAbort)
2747         {
2748
2749             if (!callback) {
2750                 this.releaseObject(o);
2751                 return;
2752             }
2753
2754             var httpStatus, responseObject;
2755
2756             try
2757             {
2758                 if (o.conn.status !== undefined && o.conn.status != 0) {
2759                     httpStatus = o.conn.status;
2760                 }
2761                 else {
2762                     httpStatus = 13030;
2763                 }
2764             }
2765             catch(e) {
2766
2767
2768                 httpStatus = 13030;
2769             }
2770
2771             if (httpStatus >= 200 && httpStatus < 300) {
2772                 responseObject = this.createResponseObject(o, callback.argument);
2773                 if (callback.success) {
2774                     if (!callback.scope) {
2775                         callback.success(responseObject);
2776                     }
2777                     else {
2778
2779
2780                         callback.success.apply(callback.scope, [responseObject]);
2781                     }
2782                 }
2783             }
2784             else {
2785                 switch (httpStatus) {
2786
2787                     case 12002:
2788                     case 12029:
2789                     case 12030:
2790                     case 12031:
2791                     case 12152:
2792                     case 13030:
2793                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2794                         if (callback.failure) {
2795                             if (!callback.scope) {
2796                                 callback.failure(responseObject);
2797                             }
2798                             else {
2799                                 callback.failure.apply(callback.scope, [responseObject]);
2800                             }
2801                         }
2802                         break;
2803                     default:
2804                         responseObject = this.createResponseObject(o, callback.argument);
2805                         if (callback.failure) {
2806                             if (!callback.scope) {
2807                                 callback.failure(responseObject);
2808                             }
2809                             else {
2810                                 callback.failure.apply(callback.scope, [responseObject]);
2811                             }
2812                         }
2813                 }
2814             }
2815
2816             this.releaseObject(o);
2817             responseObject = null;
2818         },
2819
2820         createResponseObject:function(o, callbackArg)
2821         {
2822             var obj = {};
2823             var headerObj = {};
2824
2825             try
2826             {
2827                 var headerStr = o.conn.getAllResponseHeaders();
2828                 var header = headerStr.split('\n');
2829                 for (var i = 0; i < header.length; i++) {
2830                     var delimitPos = header[i].indexOf(':');
2831                     if (delimitPos != -1) {
2832                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2833                     }
2834                 }
2835             }
2836             catch(e) {
2837             }
2838
2839             obj.tId = o.tId;
2840             obj.status = o.conn.status;
2841             obj.statusText = o.conn.statusText;
2842             obj.getResponseHeader = headerObj;
2843             obj.getAllResponseHeaders = headerStr;
2844             obj.responseText = o.conn.responseText;
2845             obj.responseXML = o.conn.responseXML;
2846
2847             if (typeof callbackArg !== undefined) {
2848                 obj.argument = callbackArg;
2849             }
2850
2851             return obj;
2852         },
2853
2854         createExceptionObject:function(tId, callbackArg, isAbort)
2855         {
2856             var COMM_CODE = 0;
2857             var COMM_ERROR = 'communication failure';
2858             var ABORT_CODE = -1;
2859             var ABORT_ERROR = 'transaction aborted';
2860
2861             var obj = {};
2862
2863             obj.tId = tId;
2864             if (isAbort) {
2865                 obj.status = ABORT_CODE;
2866                 obj.statusText = ABORT_ERROR;
2867             }
2868             else {
2869                 obj.status = COMM_CODE;
2870                 obj.statusText = COMM_ERROR;
2871             }
2872
2873             if (callbackArg) {
2874                 obj.argument = callbackArg;
2875             }
2876
2877             return obj;
2878         },
2879
2880         initHeader:function(label, value, isDefault)
2881         {
2882             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2883
2884             if (headerObj[label] === undefined) {
2885                 headerObj[label] = value;
2886             }
2887             else {
2888
2889
2890                 headerObj[label] = value + "," + headerObj[label];
2891             }
2892
2893             if (isDefault) {
2894                 this.hasDefaultHeaders = true;
2895             }
2896             else {
2897                 this.hasHeaders = true;
2898             }
2899         },
2900
2901
2902         setHeader:function(o)
2903         {
2904             if (this.hasDefaultHeaders) {
2905                 for (var prop in this.defaultHeaders) {
2906                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2907                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2908                     }
2909                 }
2910             }
2911
2912             if (this.hasHeaders) {
2913                 for (var prop in this.headers) {
2914                     if (this.headers.hasOwnProperty(prop)) {
2915                         o.conn.setRequestHeader(prop, this.headers[prop]);
2916                     }
2917                 }
2918                 this.headers = {};
2919                 this.hasHeaders = false;
2920             }
2921         },
2922
2923         resetDefaultHeaders:function() {
2924             delete this.defaultHeaders;
2925             this.defaultHeaders = {};
2926             this.hasDefaultHeaders = false;
2927         },
2928
2929         abort:function(o, callback, isTimeout)
2930         {
2931             if(this.isCallInProgress(o)) {
2932                 o.conn.abort();
2933                 window.clearInterval(this.poll[o.tId]);
2934                 delete this.poll[o.tId];
2935                 if (isTimeout) {
2936                     delete this.timeout[o.tId];
2937                 }
2938
2939                 this.handleTransactionResponse(o, callback, true);
2940
2941                 return true;
2942             }
2943             else {
2944                 return false;
2945             }
2946         },
2947
2948
2949         isCallInProgress:function(o)
2950         {
2951             if (o && o.conn) {
2952                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2953             }
2954             else {
2955
2956                 return false;
2957             }
2958         },
2959
2960
2961         releaseObject:function(o)
2962         {
2963
2964             o.conn = null;
2965
2966             o = null;
2967         },
2968
2969         activeX:[
2970         'MSXML2.XMLHTTP.3.0',
2971         'MSXML2.XMLHTTP',
2972         'Microsoft.XMLHTTP'
2973         ]
2974
2975
2976     };
2977 })();/*
2978  * Portions of this file are based on pieces of Yahoo User Interface Library
2979  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2980  * YUI licensed under the BSD License:
2981  * http://developer.yahoo.net/yui/license.txt
2982  * <script type="text/javascript">
2983  *
2984  */
2985
2986 Roo.lib.Region = function(t, r, b, l) {
2987     this.top = t;
2988     this[1] = t;
2989     this.right = r;
2990     this.bottom = b;
2991     this.left = l;
2992     this[0] = l;
2993 };
2994
2995
2996 Roo.lib.Region.prototype = {
2997     contains : function(region) {
2998         return ( region.left >= this.left &&
2999                  region.right <= this.right &&
3000                  region.top >= this.top &&
3001                  region.bottom <= this.bottom    );
3002
3003     },
3004
3005     getArea : function() {
3006         return ( (this.bottom - this.top) * (this.right - this.left) );
3007     },
3008
3009     intersect : function(region) {
3010         var t = Math.max(this.top, region.top);
3011         var r = Math.min(this.right, region.right);
3012         var b = Math.min(this.bottom, region.bottom);
3013         var l = Math.max(this.left, region.left);
3014
3015         if (b >= t && r >= l) {
3016             return new Roo.lib.Region(t, r, b, l);
3017         } else {
3018             return null;
3019         }
3020     },
3021     union : function(region) {
3022         var t = Math.min(this.top, region.top);
3023         var r = Math.max(this.right, region.right);
3024         var b = Math.max(this.bottom, region.bottom);
3025         var l = Math.min(this.left, region.left);
3026
3027         return new Roo.lib.Region(t, r, b, l);
3028     },
3029
3030     adjust : function(t, l, b, r) {
3031         this.top += t;
3032         this.left += l;
3033         this.right += r;
3034         this.bottom += b;
3035         return this;
3036     }
3037 };
3038
3039 Roo.lib.Region.getRegion = function(el) {
3040     var p = Roo.lib.Dom.getXY(el);
3041
3042     var t = p[1];
3043     var r = p[0] + el.offsetWidth;
3044     var b = p[1] + el.offsetHeight;
3045     var l = p[0];
3046
3047     return new Roo.lib.Region(t, r, b, l);
3048 };
3049 /*
3050  * Portions of this file are based on pieces of Yahoo User Interface Library
3051  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3052  * YUI licensed under the BSD License:
3053  * http://developer.yahoo.net/yui/license.txt
3054  * <script type="text/javascript">
3055  *
3056  */
3057 //@@dep Roo.lib.Region
3058
3059
3060 Roo.lib.Point = function(x, y) {
3061     if (x instanceof Array) {
3062         y = x[1];
3063         x = x[0];
3064     }
3065     this.x = this.right = this.left = this[0] = x;
3066     this.y = this.top = this.bottom = this[1] = y;
3067 };
3068
3069 Roo.lib.Point.prototype = new Roo.lib.Region();
3070 /*
3071  * Portions of this file are based on pieces of Yahoo User Interface Library
3072  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3073  * YUI licensed under the BSD License:
3074  * http://developer.yahoo.net/yui/license.txt
3075  * <script type="text/javascript">
3076  *
3077  */
3078  
3079 (function() {   
3080
3081     Roo.lib.Anim = {
3082         scroll : function(el, args, duration, easing, cb, scope) {
3083             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3084         },
3085
3086         motion : function(el, args, duration, easing, cb, scope) {
3087             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3088         },
3089
3090         color : function(el, args, duration, easing, cb, scope) {
3091             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3092         },
3093
3094         run : function(el, args, duration, easing, cb, scope, type) {
3095             type = type || Roo.lib.AnimBase;
3096             if (typeof easing == "string") {
3097                 easing = Roo.lib.Easing[easing];
3098             }
3099             var anim = new type(el, args, duration, easing);
3100             anim.animateX(function() {
3101                 Roo.callback(cb, scope);
3102             });
3103             return anim;
3104         }
3105     };
3106 })();/*
3107  * Portions of this file are based on pieces of Yahoo User Interface Library
3108  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3109  * YUI licensed under the BSD License:
3110  * http://developer.yahoo.net/yui/license.txt
3111  * <script type="text/javascript">
3112  *
3113  */
3114
3115 (function() {    
3116     var libFlyweight;
3117     
3118     function fly(el) {
3119         if (!libFlyweight) {
3120             libFlyweight = new Roo.Element.Flyweight();
3121         }
3122         libFlyweight.dom = el;
3123         return libFlyweight;
3124     }
3125
3126     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3127     
3128    
3129     
3130     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3131         if (el) {
3132             this.init(el, attributes, duration, method);
3133         }
3134     };
3135
3136     Roo.lib.AnimBase.fly = fly;
3137     
3138     
3139     
3140     Roo.lib.AnimBase.prototype = {
3141
3142         toString: function() {
3143             var el = this.getEl();
3144             var id = el.id || el.tagName;
3145             return ("Anim " + id);
3146         },
3147
3148         patterns: {
3149             noNegatives:        /width|height|opacity|padding/i,
3150             offsetAttribute:  /^((width|height)|(top|left))$/,
3151             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3152             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3153         },
3154
3155
3156         doMethod: function(attr, start, end) {
3157             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3158         },
3159
3160
3161         setAttribute: function(attr, val, unit) {
3162             if (this.patterns.noNegatives.test(attr)) {
3163                 val = (val > 0) ? val : 0;
3164             }
3165
3166             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3167         },
3168
3169
3170         getAttribute: function(attr) {
3171             var el = this.getEl();
3172             var val = fly(el).getStyle(attr);
3173
3174             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3175                 return parseFloat(val);
3176             }
3177
3178             var a = this.patterns.offsetAttribute.exec(attr) || [];
3179             var pos = !!( a[3] );
3180             var box = !!( a[2] );
3181
3182
3183             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3184                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3185             } else {
3186                 val = 0;
3187             }
3188
3189             return val;
3190         },
3191
3192
3193         getDefaultUnit: function(attr) {
3194             if (this.patterns.defaultUnit.test(attr)) {
3195                 return 'px';
3196             }
3197
3198             return '';
3199         },
3200
3201         animateX : function(callback, scope) {
3202             var f = function() {
3203                 this.onComplete.removeListener(f);
3204                 if (typeof callback == "function") {
3205                     callback.call(scope || this, this);
3206                 }
3207             };
3208             this.onComplete.addListener(f, this);
3209             this.animate();
3210         },
3211
3212
3213         setRuntimeAttribute: function(attr) {
3214             var start;
3215             var end;
3216             var attributes = this.attributes;
3217
3218             this.runtimeAttributes[attr] = {};
3219
3220             var isset = function(prop) {
3221                 return (typeof prop !== 'undefined');
3222             };
3223
3224             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3225                 return false;
3226             }
3227
3228             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3229
3230
3231             if (isset(attributes[attr]['to'])) {
3232                 end = attributes[attr]['to'];
3233             } else if (isset(attributes[attr]['by'])) {
3234                 if (start.constructor == Array) {
3235                     end = [];
3236                     for (var i = 0, len = start.length; i < len; ++i) {
3237                         end[i] = start[i] + attributes[attr]['by'][i];
3238                     }
3239                 } else {
3240                     end = start + attributes[attr]['by'];
3241                 }
3242             }
3243
3244             this.runtimeAttributes[attr].start = start;
3245             this.runtimeAttributes[attr].end = end;
3246
3247
3248             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3249         },
3250
3251
3252         init: function(el, attributes, duration, method) {
3253
3254             var isAnimated = false;
3255
3256
3257             var startTime = null;
3258
3259
3260             var actualFrames = 0;
3261
3262
3263             el = Roo.getDom(el);
3264
3265
3266             this.attributes = attributes || {};
3267
3268
3269             this.duration = duration || 1;
3270
3271
3272             this.method = method || Roo.lib.Easing.easeNone;
3273
3274
3275             this.useSeconds = true;
3276
3277
3278             this.currentFrame = 0;
3279
3280
3281             this.totalFrames = Roo.lib.AnimMgr.fps;
3282
3283
3284             this.getEl = function() {
3285                 return el;
3286             };
3287
3288
3289             this.isAnimated = function() {
3290                 return isAnimated;
3291             };
3292
3293
3294             this.getStartTime = function() {
3295                 return startTime;
3296             };
3297
3298             this.runtimeAttributes = {};
3299
3300
3301             this.animate = function() {
3302                 if (this.isAnimated()) {
3303                     return false;
3304                 }
3305
3306                 this.currentFrame = 0;
3307
3308                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3309
3310                 Roo.lib.AnimMgr.registerElement(this);
3311             };
3312
3313
3314             this.stop = function(finish) {
3315                 if (finish) {
3316                     this.currentFrame = this.totalFrames;
3317                     this._onTween.fire();
3318                 }
3319                 Roo.lib.AnimMgr.stop(this);
3320             };
3321
3322             var onStart = function() {
3323                 this.onStart.fire();
3324
3325                 this.runtimeAttributes = {};
3326                 for (var attr in this.attributes) {
3327                     this.setRuntimeAttribute(attr);
3328                 }
3329
3330                 isAnimated = true;
3331                 actualFrames = 0;
3332                 startTime = new Date();
3333             };
3334
3335
3336             var onTween = function() {
3337                 var data = {
3338                     duration: new Date() - this.getStartTime(),
3339                     currentFrame: this.currentFrame
3340                 };
3341
3342                 data.toString = function() {
3343                     return (
3344                             'duration: ' + data.duration +
3345                             ', currentFrame: ' + data.currentFrame
3346                             );
3347                 };
3348
3349                 this.onTween.fire(data);
3350
3351                 var runtimeAttributes = this.runtimeAttributes;
3352
3353                 for (var attr in runtimeAttributes) {
3354                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3355                 }
3356
3357                 actualFrames += 1;
3358             };
3359
3360             var onComplete = function() {
3361                 var actual_duration = (new Date() - startTime) / 1000 ;
3362
3363                 var data = {
3364                     duration: actual_duration,
3365                     frames: actualFrames,
3366                     fps: actualFrames / actual_duration
3367                 };
3368
3369                 data.toString = function() {
3370                     return (
3371                             'duration: ' + data.duration +
3372                             ', frames: ' + data.frames +
3373                             ', fps: ' + data.fps
3374                             );
3375                 };
3376
3377                 isAnimated = false;
3378                 actualFrames = 0;
3379                 this.onComplete.fire(data);
3380             };
3381
3382
3383             this._onStart = new Roo.util.Event(this);
3384             this.onStart = new Roo.util.Event(this);
3385             this.onTween = new Roo.util.Event(this);
3386             this._onTween = new Roo.util.Event(this);
3387             this.onComplete = new Roo.util.Event(this);
3388             this._onComplete = new Roo.util.Event(this);
3389             this._onStart.addListener(onStart);
3390             this._onTween.addListener(onTween);
3391             this._onComplete.addListener(onComplete);
3392         }
3393     };
3394 })();
3395 /*
3396  * Portions of this file are based on pieces of Yahoo User Interface Library
3397  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3398  * YUI licensed under the BSD License:
3399  * http://developer.yahoo.net/yui/license.txt
3400  * <script type="text/javascript">
3401  *
3402  */
3403
3404 Roo.lib.AnimMgr = new function() {
3405
3406     var thread = null;
3407
3408
3409     var queue = [];
3410
3411
3412     var tweenCount = 0;
3413
3414
3415     this.fps = 1000;
3416
3417
3418     this.delay = 1;
3419
3420
3421     this.registerElement = function(tween) {
3422         queue[queue.length] = tween;
3423         tweenCount += 1;
3424         tween._onStart.fire();
3425         this.start();
3426     };
3427
3428
3429     this.unRegister = function(tween, index) {
3430         tween._onComplete.fire();
3431         index = index || getIndex(tween);
3432         if (index != -1) {
3433             queue.splice(index, 1);
3434         }
3435
3436         tweenCount -= 1;
3437         if (tweenCount <= 0) {
3438             this.stop();
3439         }
3440     };
3441
3442
3443     this.start = function() {
3444         if (thread === null) {
3445             thread = setInterval(this.run, this.delay);
3446         }
3447     };
3448
3449
3450     this.stop = function(tween) {
3451         if (!tween) {
3452             clearInterval(thread);
3453
3454             for (var i = 0, len = queue.length; i < len; ++i) {
3455                 if (queue[0].isAnimated()) {
3456                     this.unRegister(queue[0], 0);
3457                 }
3458             }
3459
3460             queue = [];
3461             thread = null;
3462             tweenCount = 0;
3463         }
3464         else {
3465             this.unRegister(tween);
3466         }
3467     };
3468
3469
3470     this.run = function() {
3471         for (var i = 0, len = queue.length; i < len; ++i) {
3472             var tween = queue[i];
3473             if (!tween || !tween.isAnimated()) {
3474                 continue;
3475             }
3476
3477             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3478             {
3479                 tween.currentFrame += 1;
3480
3481                 if (tween.useSeconds) {
3482                     correctFrame(tween);
3483                 }
3484                 tween._onTween.fire();
3485             }
3486             else {
3487                 Roo.lib.AnimMgr.stop(tween, i);
3488             }
3489         }
3490     };
3491
3492     var getIndex = function(anim) {
3493         for (var i = 0, len = queue.length; i < len; ++i) {
3494             if (queue[i] == anim) {
3495                 return i;
3496             }
3497         }
3498         return -1;
3499     };
3500
3501
3502     var correctFrame = function(tween) {
3503         var frames = tween.totalFrames;
3504         var frame = tween.currentFrame;
3505         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3506         var elapsed = (new Date() - tween.getStartTime());
3507         var tweak = 0;
3508
3509         if (elapsed < tween.duration * 1000) {
3510             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3511         } else {
3512             tweak = frames - (frame + 1);
3513         }
3514         if (tweak > 0 && isFinite(tweak)) {
3515             if (tween.currentFrame + tweak >= frames) {
3516                 tweak = frames - (frame + 1);
3517             }
3518
3519             tween.currentFrame += tweak;
3520         }
3521     };
3522 };
3523
3524     /*
3525  * Portions of this file are based on pieces of Yahoo User Interface Library
3526  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3527  * YUI licensed under the BSD License:
3528  * http://developer.yahoo.net/yui/license.txt
3529  * <script type="text/javascript">
3530  *
3531  */
3532 Roo.lib.Bezier = new function() {
3533
3534         this.getPosition = function(points, t) {
3535             var n = points.length;
3536             var tmp = [];
3537
3538             for (var i = 0; i < n; ++i) {
3539                 tmp[i] = [points[i][0], points[i][1]];
3540             }
3541
3542             for (var j = 1; j < n; ++j) {
3543                 for (i = 0; i < n - j; ++i) {
3544                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3545                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3546                 }
3547             }
3548
3549             return [ tmp[0][0], tmp[0][1] ];
3550
3551         };
3552     };/*
3553  * Portions of this file are based on pieces of Yahoo User Interface Library
3554  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3555  * YUI licensed under the BSD License:
3556  * http://developer.yahoo.net/yui/license.txt
3557  * <script type="text/javascript">
3558  *
3559  */
3560 (function() {
3561
3562     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3563         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3564     };
3565
3566     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3567
3568     var fly = Roo.lib.AnimBase.fly;
3569     var Y = Roo.lib;
3570     var superclass = Y.ColorAnim.superclass;
3571     var proto = Y.ColorAnim.prototype;
3572
3573     proto.toString = function() {
3574         var el = this.getEl();
3575         var id = el.id || el.tagName;
3576         return ("ColorAnim " + id);
3577     };
3578
3579     proto.patterns.color = /color$/i;
3580     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3581     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3582     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3583     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3584
3585
3586     proto.parseColor = function(s) {
3587         if (s.length == 3) {
3588             return s;
3589         }
3590
3591         var c = this.patterns.hex.exec(s);
3592         if (c && c.length == 4) {
3593             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3594         }
3595
3596         c = this.patterns.rgb.exec(s);
3597         if (c && c.length == 4) {
3598             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3599         }
3600
3601         c = this.patterns.hex3.exec(s);
3602         if (c && c.length == 4) {
3603             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3604         }
3605
3606         return null;
3607     };
3608     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3609     proto.getAttribute = function(attr) {
3610         var el = this.getEl();
3611         if (this.patterns.color.test(attr)) {
3612             var val = fly(el).getStyle(attr);
3613
3614             if (this.patterns.transparent.test(val)) {
3615                 var parent = el.parentNode;
3616                 val = fly(parent).getStyle(attr);
3617
3618                 while (parent && this.patterns.transparent.test(val)) {
3619                     parent = parent.parentNode;
3620                     val = fly(parent).getStyle(attr);
3621                     if (parent.tagName.toUpperCase() == 'HTML') {
3622                         val = '#fff';
3623                     }
3624                 }
3625             }
3626         } else {
3627             val = superclass.getAttribute.call(this, attr);
3628         }
3629
3630         return val;
3631     };
3632     proto.getAttribute = function(attr) {
3633         var el = this.getEl();
3634         if (this.patterns.color.test(attr)) {
3635             var val = fly(el).getStyle(attr);
3636
3637             if (this.patterns.transparent.test(val)) {
3638                 var parent = el.parentNode;
3639                 val = fly(parent).getStyle(attr);
3640
3641                 while (parent && this.patterns.transparent.test(val)) {
3642                     parent = parent.parentNode;
3643                     val = fly(parent).getStyle(attr);
3644                     if (parent.tagName.toUpperCase() == 'HTML') {
3645                         val = '#fff';
3646                     }
3647                 }
3648             }
3649         } else {
3650             val = superclass.getAttribute.call(this, attr);
3651         }
3652
3653         return val;
3654     };
3655
3656     proto.doMethod = function(attr, start, end) {
3657         var val;
3658
3659         if (this.patterns.color.test(attr)) {
3660             val = [];
3661             for (var i = 0, len = start.length; i < len; ++i) {
3662                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3663             }
3664
3665             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3666         }
3667         else {
3668             val = superclass.doMethod.call(this, attr, start, end);
3669         }
3670
3671         return val;
3672     };
3673
3674     proto.setRuntimeAttribute = function(attr) {
3675         superclass.setRuntimeAttribute.call(this, attr);
3676
3677         if (this.patterns.color.test(attr)) {
3678             var attributes = this.attributes;
3679             var start = this.parseColor(this.runtimeAttributes[attr].start);
3680             var end = this.parseColor(this.runtimeAttributes[attr].end);
3681
3682             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3683                 end = this.parseColor(attributes[attr].by);
3684
3685                 for (var i = 0, len = start.length; i < len; ++i) {
3686                     end[i] = start[i] + end[i];
3687                 }
3688             }
3689
3690             this.runtimeAttributes[attr].start = start;
3691             this.runtimeAttributes[attr].end = end;
3692         }
3693     };
3694 })();
3695
3696 /*
3697  * Portions of this file are based on pieces of Yahoo User Interface Library
3698  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3699  * YUI licensed under the BSD License:
3700  * http://developer.yahoo.net/yui/license.txt
3701  * <script type="text/javascript">
3702  *
3703  */
3704 Roo.lib.Easing = {
3705
3706
3707     easeNone: function (t, b, c, d) {
3708         return c * t / d + b;
3709     },
3710
3711
3712     easeIn: function (t, b, c, d) {
3713         return c * (t /= d) * t + b;
3714     },
3715
3716
3717     easeOut: function (t, b, c, d) {
3718         return -c * (t /= d) * (t - 2) + b;
3719     },
3720
3721
3722     easeBoth: function (t, b, c, d) {
3723         if ((t /= d / 2) < 1) {
3724             return c / 2 * t * t + b;
3725         }
3726
3727         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3728     },
3729
3730
3731     easeInStrong: function (t, b, c, d) {
3732         return c * (t /= d) * t * t * t + b;
3733     },
3734
3735
3736     easeOutStrong: function (t, b, c, d) {
3737         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3738     },
3739
3740
3741     easeBothStrong: function (t, b, c, d) {
3742         if ((t /= d / 2) < 1) {
3743             return c / 2 * t * t * t * t + b;
3744         }
3745
3746         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3747     },
3748
3749
3750
3751     elasticIn: function (t, b, c, d, a, p) {
3752         if (t == 0) {
3753             return b;
3754         }
3755         if ((t /= d) == 1) {
3756             return b + c;
3757         }
3758         if (!p) {
3759             p = d * .3;
3760         }
3761
3762         if (!a || a < Math.abs(c)) {
3763             a = c;
3764             var s = p / 4;
3765         }
3766         else {
3767             var s = p / (2 * Math.PI) * Math.asin(c / a);
3768         }
3769
3770         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3771     },
3772
3773
3774     elasticOut: function (t, b, c, d, a, p) {
3775         if (t == 0) {
3776             return b;
3777         }
3778         if ((t /= d) == 1) {
3779             return b + c;
3780         }
3781         if (!p) {
3782             p = d * .3;
3783         }
3784
3785         if (!a || a < Math.abs(c)) {
3786             a = c;
3787             var s = p / 4;
3788         }
3789         else {
3790             var s = p / (2 * Math.PI) * Math.asin(c / a);
3791         }
3792
3793         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3794     },
3795
3796
3797     elasticBoth: function (t, b, c, d, a, p) {
3798         if (t == 0) {
3799             return b;
3800         }
3801
3802         if ((t /= d / 2) == 2) {
3803             return b + c;
3804         }
3805
3806         if (!p) {
3807             p = d * (.3 * 1.5);
3808         }
3809
3810         if (!a || a < Math.abs(c)) {
3811             a = c;
3812             var s = p / 4;
3813         }
3814         else {
3815             var s = p / (2 * Math.PI) * Math.asin(c / a);
3816         }
3817
3818         if (t < 1) {
3819             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3820                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3821         }
3822         return a * Math.pow(2, -10 * (t -= 1)) *
3823                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3824     },
3825
3826
3827
3828     backIn: function (t, b, c, d, s) {
3829         if (typeof s == 'undefined') {
3830             s = 1.70158;
3831         }
3832         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3833     },
3834
3835
3836     backOut: function (t, b, c, d, s) {
3837         if (typeof s == 'undefined') {
3838             s = 1.70158;
3839         }
3840         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3841     },
3842
3843
3844     backBoth: function (t, b, c, d, s) {
3845         if (typeof s == 'undefined') {
3846             s = 1.70158;
3847         }
3848
3849         if ((t /= d / 2 ) < 1) {
3850             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3851         }
3852         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3853     },
3854
3855
3856     bounceIn: function (t, b, c, d) {
3857         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3858     },
3859
3860
3861     bounceOut: function (t, b, c, d) {
3862         if ((t /= d) < (1 / 2.75)) {
3863             return c * (7.5625 * t * t) + b;
3864         } else if (t < (2 / 2.75)) {
3865             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3866         } else if (t < (2.5 / 2.75)) {
3867             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3868         }
3869         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3870     },
3871
3872
3873     bounceBoth: function (t, b, c, d) {
3874         if (t < d / 2) {
3875             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3876         }
3877         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3878     }
3879 };/*
3880  * Portions of this file are based on pieces of Yahoo User Interface Library
3881  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3882  * YUI licensed under the BSD License:
3883  * http://developer.yahoo.net/yui/license.txt
3884  * <script type="text/javascript">
3885  *
3886  */
3887     (function() {
3888         Roo.lib.Motion = function(el, attributes, duration, method) {
3889             if (el) {
3890                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3891             }
3892         };
3893
3894         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3895
3896
3897         var Y = Roo.lib;
3898         var superclass = Y.Motion.superclass;
3899         var proto = Y.Motion.prototype;
3900
3901         proto.toString = function() {
3902             var el = this.getEl();
3903             var id = el.id || el.tagName;
3904             return ("Motion " + id);
3905         };
3906
3907         proto.patterns.points = /^points$/i;
3908
3909         proto.setAttribute = function(attr, val, unit) {
3910             if (this.patterns.points.test(attr)) {
3911                 unit = unit || 'px';
3912                 superclass.setAttribute.call(this, 'left', val[0], unit);
3913                 superclass.setAttribute.call(this, 'top', val[1], unit);
3914             } else {
3915                 superclass.setAttribute.call(this, attr, val, unit);
3916             }
3917         };
3918
3919         proto.getAttribute = function(attr) {
3920             if (this.patterns.points.test(attr)) {
3921                 var val = [
3922                         superclass.getAttribute.call(this, 'left'),
3923                         superclass.getAttribute.call(this, 'top')
3924                         ];
3925             } else {
3926                 val = superclass.getAttribute.call(this, attr);
3927             }
3928
3929             return val;
3930         };
3931
3932         proto.doMethod = function(attr, start, end) {
3933             var val = null;
3934
3935             if (this.patterns.points.test(attr)) {
3936                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3937                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3938             } else {
3939                 val = superclass.doMethod.call(this, attr, start, end);
3940             }
3941             return val;
3942         };
3943
3944         proto.setRuntimeAttribute = function(attr) {
3945             if (this.patterns.points.test(attr)) {
3946                 var el = this.getEl();
3947                 var attributes = this.attributes;
3948                 var start;
3949                 var control = attributes['points']['control'] || [];
3950                 var end;
3951                 var i, len;
3952
3953                 if (control.length > 0 && !(control[0] instanceof Array)) {
3954                     control = [control];
3955                 } else {
3956                     var tmp = [];
3957                     for (i = 0,len = control.length; i < len; ++i) {
3958                         tmp[i] = control[i];
3959                     }
3960                     control = tmp;
3961                 }
3962
3963                 Roo.fly(el).position();
3964
3965                 if (isset(attributes['points']['from'])) {
3966                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3967                 }
3968                 else {
3969                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3970                 }
3971
3972                 start = this.getAttribute('points');
3973
3974
3975                 if (isset(attributes['points']['to'])) {
3976                     end = translateValues.call(this, attributes['points']['to'], start);
3977
3978                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3979                     for (i = 0,len = control.length; i < len; ++i) {
3980                         control[i] = translateValues.call(this, control[i], start);
3981                     }
3982
3983
3984                 } else if (isset(attributes['points']['by'])) {
3985                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3986
3987                     for (i = 0,len = control.length; i < len; ++i) {
3988                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3989                     }
3990                 }
3991
3992                 this.runtimeAttributes[attr] = [start];
3993
3994                 if (control.length > 0) {
3995                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3996                 }
3997
3998                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3999             }
4000             else {
4001                 superclass.setRuntimeAttribute.call(this, attr);
4002             }
4003         };
4004
4005         var translateValues = function(val, start) {
4006             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4007             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4008
4009             return val;
4010         };
4011
4012         var isset = function(prop) {
4013             return (typeof prop !== 'undefined');
4014         };
4015     })();
4016 /*
4017  * Portions of this file are based on pieces of Yahoo User Interface Library
4018  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4019  * YUI licensed under the BSD License:
4020  * http://developer.yahoo.net/yui/license.txt
4021  * <script type="text/javascript">
4022  *
4023  */
4024     (function() {
4025         Roo.lib.Scroll = function(el, attributes, duration, method) {
4026             if (el) {
4027                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4028             }
4029         };
4030
4031         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4032
4033
4034         var Y = Roo.lib;
4035         var superclass = Y.Scroll.superclass;
4036         var proto = Y.Scroll.prototype;
4037
4038         proto.toString = function() {
4039             var el = this.getEl();
4040             var id = el.id || el.tagName;
4041             return ("Scroll " + id);
4042         };
4043
4044         proto.doMethod = function(attr, start, end) {
4045             var val = null;
4046
4047             if (attr == 'scroll') {
4048                 val = [
4049                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4050                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4051                         ];
4052
4053             } else {
4054                 val = superclass.doMethod.call(this, attr, start, end);
4055             }
4056             return val;
4057         };
4058
4059         proto.getAttribute = function(attr) {
4060             var val = null;
4061             var el = this.getEl();
4062
4063             if (attr == 'scroll') {
4064                 val = [ el.scrollLeft, el.scrollTop ];
4065             } else {
4066                 val = superclass.getAttribute.call(this, attr);
4067             }
4068
4069             return val;
4070         };
4071
4072         proto.setAttribute = function(attr, val, unit) {
4073             var el = this.getEl();
4074
4075             if (attr == 'scroll') {
4076                 el.scrollLeft = val[0];
4077                 el.scrollTop = val[1];
4078             } else {
4079                 superclass.setAttribute.call(this, attr, val, unit);
4080             }
4081         };
4082     })();
4083 /*
4084  * Based on:
4085  * Ext JS Library 1.1.1
4086  * Copyright(c) 2006-2007, Ext JS, LLC.
4087  *
4088  * Originally Released Under LGPL - original licence link has changed is not relivant.
4089  *
4090  * Fork - LGPL
4091  * <script type="text/javascript">
4092  */
4093
4094
4095 // nasty IE9 hack - what a pile of crap that is..
4096
4097  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4098     Range.prototype.createContextualFragment = function (html) {
4099         var doc = window.document;
4100         var container = doc.createElement("div");
4101         container.innerHTML = html;
4102         var frag = doc.createDocumentFragment(), n;
4103         while ((n = container.firstChild)) {
4104             frag.appendChild(n);
4105         }
4106         return frag;
4107     };
4108 }
4109
4110 /**
4111  * @class Roo.DomHelper
4112  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4113  * 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>.
4114  * @singleton
4115  */
4116 Roo.DomHelper = function(){
4117     var tempTableEl = null;
4118     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4119     var tableRe = /^table|tbody|tr|td$/i;
4120     var xmlns = {};
4121     // build as innerHTML where available
4122     /** @ignore */
4123     var createHtml = function(o){
4124         if(typeof o == 'string'){
4125             return o;
4126         }
4127         var b = "";
4128         if(!o.tag){
4129             o.tag = "div";
4130         }
4131         b += "<" + o.tag;
4132         for(var attr in o){
4133             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4134             if(attr == "style"){
4135                 var s = o["style"];
4136                 if(typeof s == "function"){
4137                     s = s.call();
4138                 }
4139                 if(typeof s == "string"){
4140                     b += ' style="' + s + '"';
4141                 }else if(typeof s == "object"){
4142                     b += ' style="';
4143                     for(var key in s){
4144                         if(typeof s[key] != "function"){
4145                             b += key + ":" + s[key] + ";";
4146                         }
4147                     }
4148                     b += '"';
4149                 }
4150             }else{
4151                 if(attr == "cls"){
4152                     b += ' class="' + o["cls"] + '"';
4153                 }else if(attr == "htmlFor"){
4154                     b += ' for="' + o["htmlFor"] + '"';
4155                 }else{
4156                     b += " " + attr + '="' + o[attr] + '"';
4157                 }
4158             }
4159         }
4160         if(emptyTags.test(o.tag)){
4161             b += "/>";
4162         }else{
4163             b += ">";
4164             var cn = o.children || o.cn;
4165             if(cn){
4166                 //http://bugs.kde.org/show_bug.cgi?id=71506
4167                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4168                     for(var i = 0, len = cn.length; i < len; i++) {
4169                         b += createHtml(cn[i], b);
4170                     }
4171                 }else{
4172                     b += createHtml(cn, b);
4173                 }
4174             }
4175             if(o.html){
4176                 b += o.html;
4177             }
4178             b += "</" + o.tag + ">";
4179         }
4180         return b;
4181     };
4182
4183     // build as dom
4184     /** @ignore */
4185     var createDom = function(o, parentNode){
4186          
4187         // defininition craeted..
4188         var ns = false;
4189         if (o.ns && o.ns != 'html') {
4190                
4191             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4192                 xmlns[o.ns] = o.xmlns;
4193                 ns = o.xmlns;
4194             }
4195             if (typeof(xmlns[o.ns]) == 'undefined') {
4196                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4197             }
4198             ns = xmlns[o.ns];
4199         }
4200         
4201         
4202         if (typeof(o) == 'string') {
4203             return parentNode.appendChild(document.createTextNode(o));
4204         }
4205         o.tag = o.tag || div;
4206         if (o.ns && Roo.isIE) {
4207             ns = false;
4208             o.tag = o.ns + ':' + o.tag;
4209             
4210         }
4211         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4212         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4213         for(var attr in o){
4214             
4215             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4216                     attr == "style" || typeof o[attr] == "function") continue;
4217                     
4218             if(attr=="cls" && Roo.isIE){
4219                 el.className = o["cls"];
4220             }else{
4221                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4222                 else el[attr] = o[attr];
4223             }
4224         }
4225         Roo.DomHelper.applyStyles(el, o.style);
4226         var cn = o.children || o.cn;
4227         if(cn){
4228             //http://bugs.kde.org/show_bug.cgi?id=71506
4229              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4230                 for(var i = 0, len = cn.length; i < len; i++) {
4231                     createDom(cn[i], el);
4232                 }
4233             }else{
4234                 createDom(cn, el);
4235             }
4236         }
4237         if(o.html){
4238             el.innerHTML = o.html;
4239         }
4240         if(parentNode){
4241            parentNode.appendChild(el);
4242         }
4243         return el;
4244     };
4245
4246     var ieTable = function(depth, s, h, e){
4247         tempTableEl.innerHTML = [s, h, e].join('');
4248         var i = -1, el = tempTableEl;
4249         while(++i < depth){
4250             el = el.firstChild;
4251         }
4252         return el;
4253     };
4254
4255     // kill repeat to save bytes
4256     var ts = '<table>',
4257         te = '</table>',
4258         tbs = ts+'<tbody>',
4259         tbe = '</tbody>'+te,
4260         trs = tbs + '<tr>',
4261         tre = '</tr>'+tbe;
4262
4263     /**
4264      * @ignore
4265      * Nasty code for IE's broken table implementation
4266      */
4267     var insertIntoTable = function(tag, where, el, html){
4268         if(!tempTableEl){
4269             tempTableEl = document.createElement('div');
4270         }
4271         var node;
4272         var before = null;
4273         if(tag == 'td'){
4274             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4275                 return;
4276             }
4277             if(where == 'beforebegin'){
4278                 before = el;
4279                 el = el.parentNode;
4280             } else{
4281                 before = el.nextSibling;
4282                 el = el.parentNode;
4283             }
4284             node = ieTable(4, trs, html, tre);
4285         }
4286         else if(tag == 'tr'){
4287             if(where == 'beforebegin'){
4288                 before = el;
4289                 el = el.parentNode;
4290                 node = ieTable(3, tbs, html, tbe);
4291             } else if(where == 'afterend'){
4292                 before = el.nextSibling;
4293                 el = el.parentNode;
4294                 node = ieTable(3, tbs, html, tbe);
4295             } else{ // INTO a TR
4296                 if(where == 'afterbegin'){
4297                     before = el.firstChild;
4298                 }
4299                 node = ieTable(4, trs, html, tre);
4300             }
4301         } else if(tag == 'tbody'){
4302             if(where == 'beforebegin'){
4303                 before = el;
4304                 el = el.parentNode;
4305                 node = ieTable(2, ts, html, te);
4306             } else if(where == 'afterend'){
4307                 before = el.nextSibling;
4308                 el = el.parentNode;
4309                 node = ieTable(2, ts, html, te);
4310             } else{
4311                 if(where == 'afterbegin'){
4312                     before = el.firstChild;
4313                 }
4314                 node = ieTable(3, tbs, html, tbe);
4315             }
4316         } else{ // TABLE
4317             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4318                 return;
4319             }
4320             if(where == 'afterbegin'){
4321                 before = el.firstChild;
4322             }
4323             node = ieTable(2, ts, html, te);
4324         }
4325         el.insertBefore(node, before);
4326         return node;
4327     };
4328
4329     return {
4330     /** True to force the use of DOM instead of html fragments @type Boolean */
4331     useDom : false,
4332
4333     /**
4334      * Returns the markup for the passed Element(s) config
4335      * @param {Object} o The Dom object spec (and children)
4336      * @return {String}
4337      */
4338     markup : function(o){
4339         return createHtml(o);
4340     },
4341
4342     /**
4343      * Applies a style specification to an element
4344      * @param {String/HTMLElement} el The element to apply styles to
4345      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4346      * a function which returns such a specification.
4347      */
4348     applyStyles : function(el, styles){
4349         if(styles){
4350            el = Roo.fly(el);
4351            if(typeof styles == "string"){
4352                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4353                var matches;
4354                while ((matches = re.exec(styles)) != null){
4355                    el.setStyle(matches[1], matches[2]);
4356                }
4357            }else if (typeof styles == "object"){
4358                for (var style in styles){
4359                   el.setStyle(style, styles[style]);
4360                }
4361            }else if (typeof styles == "function"){
4362                 Roo.DomHelper.applyStyles(el, styles.call());
4363            }
4364         }
4365     },
4366
4367     /**
4368      * Inserts an HTML fragment into the Dom
4369      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4370      * @param {HTMLElement} el The context element
4371      * @param {String} html The HTML fragmenet
4372      * @return {HTMLElement} The new node
4373      */
4374     insertHtml : function(where, el, html){
4375         where = where.toLowerCase();
4376         if(el.insertAdjacentHTML){
4377             if(tableRe.test(el.tagName)){
4378                 var rs;
4379                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4380                     return rs;
4381                 }
4382             }
4383             switch(where){
4384                 case "beforebegin":
4385                     el.insertAdjacentHTML('BeforeBegin', html);
4386                     return el.previousSibling;
4387                 case "afterbegin":
4388                     el.insertAdjacentHTML('AfterBegin', html);
4389                     return el.firstChild;
4390                 case "beforeend":
4391                     el.insertAdjacentHTML('BeforeEnd', html);
4392                     return el.lastChild;
4393                 case "afterend":
4394                     el.insertAdjacentHTML('AfterEnd', html);
4395                     return el.nextSibling;
4396             }
4397             throw 'Illegal insertion point -> "' + where + '"';
4398         }
4399         var range = el.ownerDocument.createRange();
4400         var frag;
4401         switch(where){
4402              case "beforebegin":
4403                 range.setStartBefore(el);
4404                 frag = range.createContextualFragment(html);
4405                 el.parentNode.insertBefore(frag, el);
4406                 return el.previousSibling;
4407              case "afterbegin":
4408                 if(el.firstChild){
4409                     range.setStartBefore(el.firstChild);
4410                     frag = range.createContextualFragment(html);
4411                     el.insertBefore(frag, el.firstChild);
4412                     return el.firstChild;
4413                 }else{
4414                     el.innerHTML = html;
4415                     return el.firstChild;
4416                 }
4417             case "beforeend":
4418                 if(el.lastChild){
4419                     range.setStartAfter(el.lastChild);
4420                     frag = range.createContextualFragment(html);
4421                     el.appendChild(frag);
4422                     return el.lastChild;
4423                 }else{
4424                     el.innerHTML = html;
4425                     return el.lastChild;
4426                 }
4427             case "afterend":
4428                 range.setStartAfter(el);
4429                 frag = range.createContextualFragment(html);
4430                 el.parentNode.insertBefore(frag, el.nextSibling);
4431                 return el.nextSibling;
4432             }
4433             throw 'Illegal insertion point -> "' + where + '"';
4434     },
4435
4436     /**
4437      * Creates new Dom element(s) and inserts them before el
4438      * @param {String/HTMLElement/Element} el The context element
4439      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4440      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4441      * @return {HTMLElement/Roo.Element} The new node
4442      */
4443     insertBefore : function(el, o, returnElement){
4444         return this.doInsert(el, o, returnElement, "beforeBegin");
4445     },
4446
4447     /**
4448      * Creates new Dom element(s) and inserts them after el
4449      * @param {String/HTMLElement/Element} el The context element
4450      * @param {Object} o The Dom object spec (and children)
4451      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4452      * @return {HTMLElement/Roo.Element} The new node
4453      */
4454     insertAfter : function(el, o, returnElement){
4455         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4456     },
4457
4458     /**
4459      * Creates new Dom element(s) and inserts them as the first child of el
4460      * @param {String/HTMLElement/Element} el The context element
4461      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4462      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4463      * @return {HTMLElement/Roo.Element} The new node
4464      */
4465     insertFirst : function(el, o, returnElement){
4466         return this.doInsert(el, o, returnElement, "afterBegin");
4467     },
4468
4469     // private
4470     doInsert : function(el, o, returnElement, pos, sibling){
4471         el = Roo.getDom(el);
4472         var newNode;
4473         if(this.useDom || o.ns){
4474             newNode = createDom(o, null);
4475             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4476         }else{
4477             var html = createHtml(o);
4478             newNode = this.insertHtml(pos, el, html);
4479         }
4480         return returnElement ? Roo.get(newNode, true) : newNode;
4481     },
4482
4483     /**
4484      * Creates new Dom element(s) and appends them to el
4485      * @param {String/HTMLElement/Element} el The context element
4486      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4487      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4488      * @return {HTMLElement/Roo.Element} The new node
4489      */
4490     append : function(el, o, returnElement){
4491         el = Roo.getDom(el);
4492         var newNode;
4493         if(this.useDom || o.ns){
4494             newNode = createDom(o, null);
4495             el.appendChild(newNode);
4496         }else{
4497             var html = createHtml(o);
4498             newNode = this.insertHtml("beforeEnd", el, html);
4499         }
4500         return returnElement ? Roo.get(newNode, true) : newNode;
4501     },
4502
4503     /**
4504      * Creates new Dom element(s) and overwrites the contents of el with them
4505      * @param {String/HTMLElement/Element} el The context element
4506      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4507      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4508      * @return {HTMLElement/Roo.Element} The new node
4509      */
4510     overwrite : function(el, o, returnElement){
4511         el = Roo.getDom(el);
4512         if (o.ns) {
4513           
4514             while (el.childNodes.length) {
4515                 el.removeChild(el.firstChild);
4516             }
4517             createDom(o, el);
4518         } else {
4519             el.innerHTML = createHtml(o);   
4520         }
4521         
4522         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4523     },
4524
4525     /**
4526      * Creates a new Roo.DomHelper.Template from the Dom object spec
4527      * @param {Object} o The Dom object spec (and children)
4528      * @return {Roo.DomHelper.Template} The new template
4529      */
4530     createTemplate : function(o){
4531         var html = createHtml(o);
4532         return new Roo.Template(html);
4533     }
4534     };
4535 }();
4536 /*
4537  * Based on:
4538  * Ext JS Library 1.1.1
4539  * Copyright(c) 2006-2007, Ext JS, LLC.
4540  *
4541  * Originally Released Under LGPL - original licence link has changed is not relivant.
4542  *
4543  * Fork - LGPL
4544  * <script type="text/javascript">
4545  */
4546  
4547 /**
4548 * @class Roo.Template
4549 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4550 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4551 * Usage:
4552 <pre><code>
4553 var t = new Roo.Template({
4554     html :  '&lt;div name="{id}"&gt;' + 
4555         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4556         '&lt;/div&gt;',
4557     myformat: function (value, allValues) {
4558         return 'XX' + value;
4559     }
4560 });
4561 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4562 </code></pre>
4563 * For more information see this blog post with examples:
4564 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4565      - Create Elements using DOM, HTML fragments and Templates</a>. 
4566 * @constructor
4567 * @param {Object} cfg - Configuration object.
4568 */
4569 Roo.Template = function(cfg){
4570     // BC!
4571     if(cfg instanceof Array){
4572         cfg = cfg.join("");
4573     }else if(arguments.length > 1){
4574         cfg = Array.prototype.join.call(arguments, "");
4575     }
4576     
4577     
4578     if (typeof(cfg) == 'object') {
4579         Roo.apply(this,cfg)
4580     } else {
4581         // bc
4582         this.html = cfg;
4583     }
4584     if (this.url) {
4585         this.load();
4586     }
4587     
4588 };
4589 Roo.Template.prototype = {
4590     
4591     /**
4592      * @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..
4593      *                    it should be fixed so that template is observable...
4594      */
4595     url : false,
4596     /**
4597      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4598      */
4599     html : '',
4600     /**
4601      * Returns an HTML fragment of this template with the specified values applied.
4602      * @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'})
4603      * @return {String} The HTML fragment
4604      */
4605     applyTemplate : function(values){
4606         try {
4607            
4608             if(this.compiled){
4609                 return this.compiled(values);
4610             }
4611             var useF = this.disableFormats !== true;
4612             var fm = Roo.util.Format, tpl = this;
4613             var fn = function(m, name, format, args){
4614                 if(format && useF){
4615                     if(format.substr(0, 5) == "this."){
4616                         return tpl.call(format.substr(5), values[name], values);
4617                     }else{
4618                         if(args){
4619                             // quoted values are required for strings in compiled templates, 
4620                             // but for non compiled we need to strip them
4621                             // quoted reversed for jsmin
4622                             var re = /^\s*['"](.*)["']\s*$/;
4623                             args = args.split(',');
4624                             for(var i = 0, len = args.length; i < len; i++){
4625                                 args[i] = args[i].replace(re, "$1");
4626                             }
4627                             args = [values[name]].concat(args);
4628                         }else{
4629                             args = [values[name]];
4630                         }
4631                         return fm[format].apply(fm, args);
4632                     }
4633                 }else{
4634                     return values[name] !== undefined ? values[name] : "";
4635                 }
4636             };
4637             return this.html.replace(this.re, fn);
4638         } catch (e) {
4639             Roo.log(e);
4640             throw e;
4641         }
4642          
4643     },
4644     
4645     loading : false,
4646       
4647     load : function ()
4648     {
4649          
4650         if (this.loading) {
4651             return;
4652         }
4653         var _t = this;
4654         
4655         this.loading = true;
4656         this.compiled = false;
4657         
4658         var cx = new Roo.data.Connection();
4659         cx.request({
4660             url : this.url,
4661             method : 'GET',
4662             success : function (response) {
4663                 _t.loading = false;
4664                 _t.html = response.responseText;
4665                 _t.url = false;
4666                 _t.compile();
4667              },
4668             failure : function(response) {
4669                 Roo.log("Template failed to load from " + _t.url);
4670                 _t.loading = false;
4671             }
4672         });
4673     },
4674
4675     /**
4676      * Sets the HTML used as the template and optionally compiles it.
4677      * @param {String} html
4678      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4679      * @return {Roo.Template} this
4680      */
4681     set : function(html, compile){
4682         this.html = html;
4683         this.compiled = null;
4684         if(compile){
4685             this.compile();
4686         }
4687         return this;
4688     },
4689     
4690     /**
4691      * True to disable format functions (defaults to false)
4692      * @type Boolean
4693      */
4694     disableFormats : false,
4695     
4696     /**
4697     * The regular expression used to match template variables 
4698     * @type RegExp
4699     * @property 
4700     */
4701     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4702     
4703     /**
4704      * Compiles the template into an internal function, eliminating the RegEx overhead.
4705      * @return {Roo.Template} this
4706      */
4707     compile : function(){
4708         var fm = Roo.util.Format;
4709         var useF = this.disableFormats !== true;
4710         var sep = Roo.isGecko ? "+" : ",";
4711         var fn = function(m, name, format, args){
4712             if(format && useF){
4713                 args = args ? ',' + args : "";
4714                 if(format.substr(0, 5) != "this."){
4715                     format = "fm." + format + '(';
4716                 }else{
4717                     format = 'this.call("'+ format.substr(5) + '", ';
4718                     args = ", values";
4719                 }
4720             }else{
4721                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4722             }
4723             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4724         };
4725         var body;
4726         // branched to use + in gecko and [].join() in others
4727         if(Roo.isGecko){
4728             body = "this.compiled = function(values){ return '" +
4729                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4730                     "';};";
4731         }else{
4732             body = ["this.compiled = function(values){ return ['"];
4733             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4734             body.push("'].join('');};");
4735             body = body.join('');
4736         }
4737         /**
4738          * eval:var:values
4739          * eval:var:fm
4740          */
4741         eval(body);
4742         return this;
4743     },
4744     
4745     // private function used to call members
4746     call : function(fnName, value, allValues){
4747         return this[fnName](value, allValues);
4748     },
4749     
4750     /**
4751      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4752      * @param {String/HTMLElement/Roo.Element} el The context element
4753      * @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'})
4754      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4755      * @return {HTMLElement/Roo.Element} The new node or Element
4756      */
4757     insertFirst: function(el, values, returnElement){
4758         return this.doInsert('afterBegin', el, values, returnElement);
4759     },
4760
4761     /**
4762      * Applies the supplied values to the template and inserts the new node(s) before el.
4763      * @param {String/HTMLElement/Roo.Element} el The context element
4764      * @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'})
4765      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4766      * @return {HTMLElement/Roo.Element} The new node or Element
4767      */
4768     insertBefore: function(el, values, returnElement){
4769         return this.doInsert('beforeBegin', el, values, returnElement);
4770     },
4771
4772     /**
4773      * Applies the supplied values to the template and inserts the new node(s) after el.
4774      * @param {String/HTMLElement/Roo.Element} el The context element
4775      * @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'})
4776      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4777      * @return {HTMLElement/Roo.Element} The new node or Element
4778      */
4779     insertAfter : function(el, values, returnElement){
4780         return this.doInsert('afterEnd', el, values, returnElement);
4781     },
4782     
4783     /**
4784      * Applies the supplied values to the template and appends the new node(s) to el.
4785      * @param {String/HTMLElement/Roo.Element} el The context element
4786      * @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'})
4787      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4788      * @return {HTMLElement/Roo.Element} The new node or Element
4789      */
4790     append : function(el, values, returnElement){
4791         return this.doInsert('beforeEnd', el, values, returnElement);
4792     },
4793
4794     doInsert : function(where, el, values, returnEl){
4795         el = Roo.getDom(el);
4796         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4797         return returnEl ? Roo.get(newNode, true) : newNode;
4798     },
4799
4800     /**
4801      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4802      * @param {String/HTMLElement/Roo.Element} el The context element
4803      * @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'})
4804      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4805      * @return {HTMLElement/Roo.Element} The new node or Element
4806      */
4807     overwrite : function(el, values, returnElement){
4808         el = Roo.getDom(el);
4809         el.innerHTML = this.applyTemplate(values);
4810         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4811     }
4812 };
4813 /**
4814  * Alias for {@link #applyTemplate}
4815  * @method
4816  */
4817 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4818
4819 // backwards compat
4820 Roo.DomHelper.Template = Roo.Template;
4821
4822 /**
4823  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4824  * @param {String/HTMLElement} el A DOM element or its id
4825  * @returns {Roo.Template} The created template
4826  * @static
4827  */
4828 Roo.Template.from = function(el){
4829     el = Roo.getDom(el);
4830     return new Roo.Template(el.value || el.innerHTML);
4831 };/*
4832  * Based on:
4833  * Ext JS Library 1.1.1
4834  * Copyright(c) 2006-2007, Ext JS, LLC.
4835  *
4836  * Originally Released Under LGPL - original licence link has changed is not relivant.
4837  *
4838  * Fork - LGPL
4839  * <script type="text/javascript">
4840  */
4841  
4842
4843 /*
4844  * This is code is also distributed under MIT license for use
4845  * with jQuery and prototype JavaScript libraries.
4846  */
4847 /**
4848  * @class Roo.DomQuery
4849 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).
4850 <p>
4851 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>
4852
4853 <p>
4854 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.
4855 </p>
4856 <h4>Element Selectors:</h4>
4857 <ul class="list">
4858     <li> <b>*</b> any element</li>
4859     <li> <b>E</b> an element with the tag E</li>
4860     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4861     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4862     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4863     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4864 </ul>
4865 <h4>Attribute Selectors:</h4>
4866 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4867 <ul class="list">
4868     <li> <b>E[foo]</b> has an attribute "foo"</li>
4869     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4870     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4871     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4872     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4873     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4874     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4875 </ul>
4876 <h4>Pseudo Classes:</h4>
4877 <ul class="list">
4878     <li> <b>E:first-child</b> E is the first child of its parent</li>
4879     <li> <b>E:last-child</b> E is the last child of its parent</li>
4880     <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>
4881     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4882     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4883     <li> <b>E:only-child</b> E is the only child of its parent</li>
4884     <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>
4885     <li> <b>E:first</b> the first E in the resultset</li>
4886     <li> <b>E:last</b> the last E in the resultset</li>
4887     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4888     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4889     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4890     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4891     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4892     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4893     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4894     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4895     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4896 </ul>
4897 <h4>CSS Value Selectors:</h4>
4898 <ul class="list">
4899     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4900     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4901     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4902     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4903     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4904     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4905 </ul>
4906  * @singleton
4907  */
4908 Roo.DomQuery = function(){
4909     var cache = {}, simpleCache = {}, valueCache = {};
4910     var nonSpace = /\S/;
4911     var trimRe = /^\s+|\s+$/g;
4912     var tplRe = /\{(\d+)\}/g;
4913     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4914     var tagTokenRe = /^(#)?([\w-\*]+)/;
4915     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4916
4917     function child(p, index){
4918         var i = 0;
4919         var n = p.firstChild;
4920         while(n){
4921             if(n.nodeType == 1){
4922                if(++i == index){
4923                    return n;
4924                }
4925             }
4926             n = n.nextSibling;
4927         }
4928         return null;
4929     };
4930
4931     function next(n){
4932         while((n = n.nextSibling) && n.nodeType != 1);
4933         return n;
4934     };
4935
4936     function prev(n){
4937         while((n = n.previousSibling) && n.nodeType != 1);
4938         return n;
4939     };
4940
4941     function children(d){
4942         var n = d.firstChild, ni = -1;
4943             while(n){
4944                 var nx = n.nextSibling;
4945                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4946                     d.removeChild(n);
4947                 }else{
4948                     n.nodeIndex = ++ni;
4949                 }
4950                 n = nx;
4951             }
4952             return this;
4953         };
4954
4955     function byClassName(c, a, v){
4956         if(!v){
4957             return c;
4958         }
4959         var r = [], ri = -1, cn;
4960         for(var i = 0, ci; ci = c[i]; i++){
4961             if((' '+ci.className+' ').indexOf(v) != -1){
4962                 r[++ri] = ci;
4963             }
4964         }
4965         return r;
4966     };
4967
4968     function attrValue(n, attr){
4969         if(!n.tagName && typeof n.length != "undefined"){
4970             n = n[0];
4971         }
4972         if(!n){
4973             return null;
4974         }
4975         if(attr == "for"){
4976             return n.htmlFor;
4977         }
4978         if(attr == "class" || attr == "className"){
4979             return n.className;
4980         }
4981         return n.getAttribute(attr) || n[attr];
4982
4983     };
4984
4985     function getNodes(ns, mode, tagName){
4986         var result = [], ri = -1, cs;
4987         if(!ns){
4988             return result;
4989         }
4990         tagName = tagName || "*";
4991         if(typeof ns.getElementsByTagName != "undefined"){
4992             ns = [ns];
4993         }
4994         if(!mode){
4995             for(var i = 0, ni; ni = ns[i]; i++){
4996                 cs = ni.getElementsByTagName(tagName);
4997                 for(var j = 0, ci; ci = cs[j]; j++){
4998                     result[++ri] = ci;
4999                 }
5000             }
5001         }else if(mode == "/" || mode == ">"){
5002             var utag = tagName.toUpperCase();
5003             for(var i = 0, ni, cn; ni = ns[i]; i++){
5004                 cn = ni.children || ni.childNodes;
5005                 for(var j = 0, cj; cj = cn[j]; j++){
5006                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5007                         result[++ri] = cj;
5008                     }
5009                 }
5010             }
5011         }else if(mode == "+"){
5012             var utag = tagName.toUpperCase();
5013             for(var i = 0, n; n = ns[i]; i++){
5014                 while((n = n.nextSibling) && n.nodeType != 1);
5015                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5016                     result[++ri] = n;
5017                 }
5018             }
5019         }else if(mode == "~"){
5020             for(var i = 0, n; n = ns[i]; i++){
5021                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5022                 if(n){
5023                     result[++ri] = n;
5024                 }
5025             }
5026         }
5027         return result;
5028     };
5029
5030     function concat(a, b){
5031         if(b.slice){
5032             return a.concat(b);
5033         }
5034         for(var i = 0, l = b.length; i < l; i++){
5035             a[a.length] = b[i];
5036         }
5037         return a;
5038     }
5039
5040     function byTag(cs, tagName){
5041         if(cs.tagName || cs == document){
5042             cs = [cs];
5043         }
5044         if(!tagName){
5045             return cs;
5046         }
5047         var r = [], ri = -1;
5048         tagName = tagName.toLowerCase();
5049         for(var i = 0, ci; ci = cs[i]; i++){
5050             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5051                 r[++ri] = ci;
5052             }
5053         }
5054         return r;
5055     };
5056
5057     function byId(cs, attr, id){
5058         if(cs.tagName || cs == document){
5059             cs = [cs];
5060         }
5061         if(!id){
5062             return cs;
5063         }
5064         var r = [], ri = -1;
5065         for(var i = 0,ci; ci = cs[i]; i++){
5066             if(ci && ci.id == id){
5067                 r[++ri] = ci;
5068                 return r;
5069             }
5070         }
5071         return r;
5072     };
5073
5074     function byAttribute(cs, attr, value, op, custom){
5075         var r = [], ri = -1, st = custom=="{";
5076         var f = Roo.DomQuery.operators[op];
5077         for(var i = 0, ci; ci = cs[i]; i++){
5078             var a;
5079             if(st){
5080                 a = Roo.DomQuery.getStyle(ci, attr);
5081             }
5082             else if(attr == "class" || attr == "className"){
5083                 a = ci.className;
5084             }else if(attr == "for"){
5085                 a = ci.htmlFor;
5086             }else if(attr == "href"){
5087                 a = ci.getAttribute("href", 2);
5088             }else{
5089                 a = ci.getAttribute(attr);
5090             }
5091             if((f && f(a, value)) || (!f && a)){
5092                 r[++ri] = ci;
5093             }
5094         }
5095         return r;
5096     };
5097
5098     function byPseudo(cs, name, value){
5099         return Roo.DomQuery.pseudos[name](cs, value);
5100     };
5101
5102     // This is for IE MSXML which does not support expandos.
5103     // IE runs the same speed using setAttribute, however FF slows way down
5104     // and Safari completely fails so they need to continue to use expandos.
5105     var isIE = window.ActiveXObject ? true : false;
5106
5107     // this eval is stop the compressor from
5108     // renaming the variable to something shorter
5109     
5110     /** eval:var:batch */
5111     var batch = 30803; 
5112
5113     var key = 30803;
5114
5115     function nodupIEXml(cs){
5116         var d = ++key;
5117         cs[0].setAttribute("_nodup", d);
5118         var r = [cs[0]];
5119         for(var i = 1, len = cs.length; i < len; i++){
5120             var c = cs[i];
5121             if(!c.getAttribute("_nodup") != d){
5122                 c.setAttribute("_nodup", d);
5123                 r[r.length] = c;
5124             }
5125         }
5126         for(var i = 0, len = cs.length; i < len; i++){
5127             cs[i].removeAttribute("_nodup");
5128         }
5129         return r;
5130     }
5131
5132     function nodup(cs){
5133         if(!cs){
5134             return [];
5135         }
5136         var len = cs.length, c, i, r = cs, cj, ri = -1;
5137         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5138             return cs;
5139         }
5140         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5141             return nodupIEXml(cs);
5142         }
5143         var d = ++key;
5144         cs[0]._nodup = d;
5145         for(i = 1; c = cs[i]; i++){
5146             if(c._nodup != d){
5147                 c._nodup = d;
5148             }else{
5149                 r = [];
5150                 for(var j = 0; j < i; j++){
5151                     r[++ri] = cs[j];
5152                 }
5153                 for(j = i+1; cj = cs[j]; j++){
5154                     if(cj._nodup != d){
5155                         cj._nodup = d;
5156                         r[++ri] = cj;
5157                     }
5158                 }
5159                 return r;
5160             }
5161         }
5162         return r;
5163     }
5164
5165     function quickDiffIEXml(c1, c2){
5166         var d = ++key;
5167         for(var i = 0, len = c1.length; i < len; i++){
5168             c1[i].setAttribute("_qdiff", d);
5169         }
5170         var r = [];
5171         for(var i = 0, len = c2.length; i < len; i++){
5172             if(c2[i].getAttribute("_qdiff") != d){
5173                 r[r.length] = c2[i];
5174             }
5175         }
5176         for(var i = 0, len = c1.length; i < len; i++){
5177            c1[i].removeAttribute("_qdiff");
5178         }
5179         return r;
5180     }
5181
5182     function quickDiff(c1, c2){
5183         var len1 = c1.length;
5184         if(!len1){
5185             return c2;
5186         }
5187         if(isIE && c1[0].selectSingleNode){
5188             return quickDiffIEXml(c1, c2);
5189         }
5190         var d = ++key;
5191         for(var i = 0; i < len1; i++){
5192             c1[i]._qdiff = d;
5193         }
5194         var r = [];
5195         for(var i = 0, len = c2.length; i < len; i++){
5196             if(c2[i]._qdiff != d){
5197                 r[r.length] = c2[i];
5198             }
5199         }
5200         return r;
5201     }
5202
5203     function quickId(ns, mode, root, id){
5204         if(ns == root){
5205            var d = root.ownerDocument || root;
5206            return d.getElementById(id);
5207         }
5208         ns = getNodes(ns, mode, "*");
5209         return byId(ns, null, id);
5210     }
5211
5212     return {
5213         getStyle : function(el, name){
5214             return Roo.fly(el).getStyle(name);
5215         },
5216         /**
5217          * Compiles a selector/xpath query into a reusable function. The returned function
5218          * takes one parameter "root" (optional), which is the context node from where the query should start.
5219          * @param {String} selector The selector/xpath query
5220          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5221          * @return {Function}
5222          */
5223         compile : function(path, type){
5224             type = type || "select";
5225             
5226             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5227             var q = path, mode, lq;
5228             var tk = Roo.DomQuery.matchers;
5229             var tklen = tk.length;
5230             var mm;
5231
5232             // accept leading mode switch
5233             var lmode = q.match(modeRe);
5234             if(lmode && lmode[1]){
5235                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5236                 q = q.replace(lmode[1], "");
5237             }
5238             // strip leading slashes
5239             while(path.substr(0, 1)=="/"){
5240                 path = path.substr(1);
5241             }
5242
5243             while(q && lq != q){
5244                 lq = q;
5245                 var tm = q.match(tagTokenRe);
5246                 if(type == "select"){
5247                     if(tm){
5248                         if(tm[1] == "#"){
5249                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5250                         }else{
5251                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5252                         }
5253                         q = q.replace(tm[0], "");
5254                     }else if(q.substr(0, 1) != '@'){
5255                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5256                     }
5257                 }else{
5258                     if(tm){
5259                         if(tm[1] == "#"){
5260                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5261                         }else{
5262                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5263                         }
5264                         q = q.replace(tm[0], "");
5265                     }
5266                 }
5267                 while(!(mm = q.match(modeRe))){
5268                     var matched = false;
5269                     for(var j = 0; j < tklen; j++){
5270                         var t = tk[j];
5271                         var m = q.match(t.re);
5272                         if(m){
5273                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5274                                                     return m[i];
5275                                                 });
5276                             q = q.replace(m[0], "");
5277                             matched = true;
5278                             break;
5279                         }
5280                     }
5281                     // prevent infinite loop on bad selector
5282                     if(!matched){
5283                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5284                     }
5285                 }
5286                 if(mm[1]){
5287                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5288                     q = q.replace(mm[1], "");
5289                 }
5290             }
5291             fn[fn.length] = "return nodup(n);\n}";
5292             
5293              /** 
5294               * list of variables that need from compression as they are used by eval.
5295              *  eval:var:batch 
5296              *  eval:var:nodup
5297              *  eval:var:byTag
5298              *  eval:var:ById
5299              *  eval:var:getNodes
5300              *  eval:var:quickId
5301              *  eval:var:mode
5302              *  eval:var:root
5303              *  eval:var:n
5304              *  eval:var:byClassName
5305              *  eval:var:byPseudo
5306              *  eval:var:byAttribute
5307              *  eval:var:attrValue
5308              * 
5309              **/ 
5310             eval(fn.join(""));
5311             return f;
5312         },
5313
5314         /**
5315          * Selects a group of elements.
5316          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5317          * @param {Node} root (optional) The start of the query (defaults to document).
5318          * @return {Array}
5319          */
5320         select : function(path, root, type){
5321             if(!root || root == document){
5322                 root = document;
5323             }
5324             if(typeof root == "string"){
5325                 root = document.getElementById(root);
5326             }
5327             var paths = path.split(",");
5328             var results = [];
5329             for(var i = 0, len = paths.length; i < len; i++){
5330                 var p = paths[i].replace(trimRe, "");
5331                 if(!cache[p]){
5332                     cache[p] = Roo.DomQuery.compile(p);
5333                     if(!cache[p]){
5334                         throw p + " is not a valid selector";
5335                     }
5336                 }
5337                 var result = cache[p](root);
5338                 if(result && result != document){
5339                     results = results.concat(result);
5340                 }
5341             }
5342             if(paths.length > 1){
5343                 return nodup(results);
5344             }
5345             return results;
5346         },
5347
5348         /**
5349          * Selects a single element.
5350          * @param {String} selector The selector/xpath query
5351          * @param {Node} root (optional) The start of the query (defaults to document).
5352          * @return {Element}
5353          */
5354         selectNode : function(path, root){
5355             return Roo.DomQuery.select(path, root)[0];
5356         },
5357
5358         /**
5359          * Selects the value of a node, optionally replacing null with the defaultValue.
5360          * @param {String} selector The selector/xpath query
5361          * @param {Node} root (optional) The start of the query (defaults to document).
5362          * @param {String} defaultValue
5363          */
5364         selectValue : function(path, root, defaultValue){
5365             path = path.replace(trimRe, "");
5366             if(!valueCache[path]){
5367                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5368             }
5369             var n = valueCache[path](root);
5370             n = n[0] ? n[0] : n;
5371             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5372             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5373         },
5374
5375         /**
5376          * Selects the value of a node, parsing integers and floats.
5377          * @param {String} selector The selector/xpath query
5378          * @param {Node} root (optional) The start of the query (defaults to document).
5379          * @param {Number} defaultValue
5380          * @return {Number}
5381          */
5382         selectNumber : function(path, root, defaultValue){
5383             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5384             return parseFloat(v);
5385         },
5386
5387         /**
5388          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5389          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5390          * @param {String} selector The simple selector to test
5391          * @return {Boolean}
5392          */
5393         is : function(el, ss){
5394             if(typeof el == "string"){
5395                 el = document.getElementById(el);
5396             }
5397             var isArray = (el instanceof Array);
5398             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5399             return isArray ? (result.length == el.length) : (result.length > 0);
5400         },
5401
5402         /**
5403          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5404          * @param {Array} el An array of elements to filter
5405          * @param {String} selector The simple selector to test
5406          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5407          * the selector instead of the ones that match
5408          * @return {Array}
5409          */
5410         filter : function(els, ss, nonMatches){
5411             ss = ss.replace(trimRe, "");
5412             if(!simpleCache[ss]){
5413                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5414             }
5415             var result = simpleCache[ss](els);
5416             return nonMatches ? quickDiff(result, els) : result;
5417         },
5418
5419         /**
5420          * Collection of matching regular expressions and code snippets.
5421          */
5422         matchers : [{
5423                 re: /^\.([\w-]+)/,
5424                 select: 'n = byClassName(n, null, " {1} ");'
5425             }, {
5426                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5427                 select: 'n = byPseudo(n, "{1}", "{2}");'
5428             },{
5429                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5430                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5431             }, {
5432                 re: /^#([\w-]+)/,
5433                 select: 'n = byId(n, null, "{1}");'
5434             },{
5435                 re: /^@([\w-]+)/,
5436                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5437             }
5438         ],
5439
5440         /**
5441          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5442          * 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;.
5443          */
5444         operators : {
5445             "=" : function(a, v){
5446                 return a == v;
5447             },
5448             "!=" : function(a, v){
5449                 return a != v;
5450             },
5451             "^=" : function(a, v){
5452                 return a && a.substr(0, v.length) == v;
5453             },
5454             "$=" : function(a, v){
5455                 return a && a.substr(a.length-v.length) == v;
5456             },
5457             "*=" : function(a, v){
5458                 return a && a.indexOf(v) !== -1;
5459             },
5460             "%=" : function(a, v){
5461                 return (a % v) == 0;
5462             },
5463             "|=" : function(a, v){
5464                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5465             },
5466             "~=" : function(a, v){
5467                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5468             }
5469         },
5470
5471         /**
5472          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5473          * and the argument (if any) supplied in the selector.
5474          */
5475         pseudos : {
5476             "first-child" : function(c){
5477                 var r = [], ri = -1, n;
5478                 for(var i = 0, ci; ci = n = c[i]; i++){
5479                     while((n = n.previousSibling) && n.nodeType != 1);
5480                     if(!n){
5481                         r[++ri] = ci;
5482                     }
5483                 }
5484                 return r;
5485             },
5486
5487             "last-child" : function(c){
5488                 var r = [], ri = -1, n;
5489                 for(var i = 0, ci; ci = n = c[i]; i++){
5490                     while((n = n.nextSibling) && n.nodeType != 1);
5491                     if(!n){
5492                         r[++ri] = ci;
5493                     }
5494                 }
5495                 return r;
5496             },
5497
5498             "nth-child" : function(c, a) {
5499                 var r = [], ri = -1;
5500                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5501                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5502                 for(var i = 0, n; n = c[i]; i++){
5503                     var pn = n.parentNode;
5504                     if (batch != pn._batch) {
5505                         var j = 0;
5506                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5507                             if(cn.nodeType == 1){
5508                                cn.nodeIndex = ++j;
5509                             }
5510                         }
5511                         pn._batch = batch;
5512                     }
5513                     if (f == 1) {
5514                         if (l == 0 || n.nodeIndex == l){
5515                             r[++ri] = n;
5516                         }
5517                     } else if ((n.nodeIndex + l) % f == 0){
5518                         r[++ri] = n;
5519                     }
5520                 }
5521
5522                 return r;
5523             },
5524
5525             "only-child" : function(c){
5526                 var r = [], ri = -1;;
5527                 for(var i = 0, ci; ci = c[i]; i++){
5528                     if(!prev(ci) && !next(ci)){
5529                         r[++ri] = ci;
5530                     }
5531                 }
5532                 return r;
5533             },
5534
5535             "empty" : function(c){
5536                 var r = [], ri = -1;
5537                 for(var i = 0, ci; ci = c[i]; i++){
5538                     var cns = ci.childNodes, j = 0, cn, empty = true;
5539                     while(cn = cns[j]){
5540                         ++j;
5541                         if(cn.nodeType == 1 || cn.nodeType == 3){
5542                             empty = false;
5543                             break;
5544                         }
5545                     }
5546                     if(empty){
5547                         r[++ri] = ci;
5548                     }
5549                 }
5550                 return r;
5551             },
5552
5553             "contains" : function(c, v){
5554                 var r = [], ri = -1;
5555                 for(var i = 0, ci; ci = c[i]; i++){
5556                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5557                         r[++ri] = ci;
5558                     }
5559                 }
5560                 return r;
5561             },
5562
5563             "nodeValue" : function(c, v){
5564                 var r = [], ri = -1;
5565                 for(var i = 0, ci; ci = c[i]; i++){
5566                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5567                         r[++ri] = ci;
5568                     }
5569                 }
5570                 return r;
5571             },
5572
5573             "checked" : function(c){
5574                 var r = [], ri = -1;
5575                 for(var i = 0, ci; ci = c[i]; i++){
5576                     if(ci.checked == true){
5577                         r[++ri] = ci;
5578                     }
5579                 }
5580                 return r;
5581             },
5582
5583             "not" : function(c, ss){
5584                 return Roo.DomQuery.filter(c, ss, true);
5585             },
5586
5587             "odd" : function(c){
5588                 return this["nth-child"](c, "odd");
5589             },
5590
5591             "even" : function(c){
5592                 return this["nth-child"](c, "even");
5593             },
5594
5595             "nth" : function(c, a){
5596                 return c[a-1] || [];
5597             },
5598
5599             "first" : function(c){
5600                 return c[0] || [];
5601             },
5602
5603             "last" : function(c){
5604                 return c[c.length-1] || [];
5605             },
5606
5607             "has" : function(c, ss){
5608                 var s = Roo.DomQuery.select;
5609                 var r = [], ri = -1;
5610                 for(var i = 0, ci; ci = c[i]; i++){
5611                     if(s(ss, ci).length > 0){
5612                         r[++ri] = ci;
5613                     }
5614                 }
5615                 return r;
5616             },
5617
5618             "next" : function(c, ss){
5619                 var is = Roo.DomQuery.is;
5620                 var r = [], ri = -1;
5621                 for(var i = 0, ci; ci = c[i]; i++){
5622                     var n = next(ci);
5623                     if(n && is(n, ss)){
5624                         r[++ri] = ci;
5625                     }
5626                 }
5627                 return r;
5628             },
5629
5630             "prev" : function(c, ss){
5631                 var is = Roo.DomQuery.is;
5632                 var r = [], ri = -1;
5633                 for(var i = 0, ci; ci = c[i]; i++){
5634                     var n = prev(ci);
5635                     if(n && is(n, ss)){
5636                         r[++ri] = ci;
5637                     }
5638                 }
5639                 return r;
5640             }
5641         }
5642     };
5643 }();
5644
5645 /**
5646  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5647  * @param {String} path The selector/xpath query
5648  * @param {Node} root (optional) The start of the query (defaults to document).
5649  * @return {Array}
5650  * @member Roo
5651  * @method query
5652  */
5653 Roo.query = Roo.DomQuery.select;
5654 /*
5655  * Based on:
5656  * Ext JS Library 1.1.1
5657  * Copyright(c) 2006-2007, Ext JS, LLC.
5658  *
5659  * Originally Released Under LGPL - original licence link has changed is not relivant.
5660  *
5661  * Fork - LGPL
5662  * <script type="text/javascript">
5663  */
5664
5665 /**
5666  * @class Roo.util.Observable
5667  * Base class that provides a common interface for publishing events. Subclasses are expected to
5668  * to have a property "events" with all the events defined.<br>
5669  * For example:
5670  * <pre><code>
5671  Employee = function(name){
5672     this.name = name;
5673     this.addEvents({
5674         "fired" : true,
5675         "quit" : true
5676     });
5677  }
5678  Roo.extend(Employee, Roo.util.Observable);
5679 </code></pre>
5680  * @param {Object} config properties to use (incuding events / listeners)
5681  */
5682
5683 Roo.util.Observable = function(cfg){
5684     
5685     cfg = cfg|| {};
5686     this.addEvents(cfg.events || {});
5687     if (cfg.events) {
5688         delete cfg.events; // make sure
5689     }
5690      
5691     Roo.apply(this, cfg);
5692     
5693     if(this.listeners){
5694         this.on(this.listeners);
5695         delete this.listeners;
5696     }
5697 };
5698 Roo.util.Observable.prototype = {
5699     /** 
5700  * @cfg {Object} listeners  list of events and functions to call for this object, 
5701  * For example :
5702  * <pre><code>
5703     listeners :  { 
5704        'click' : function(e) {
5705            ..... 
5706         } ,
5707         .... 
5708     } 
5709   </code></pre>
5710  */
5711     
5712     
5713     /**
5714      * Fires the specified event with the passed parameters (minus the event name).
5715      * @param {String} eventName
5716      * @param {Object...} args Variable number of parameters are passed to handlers
5717      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5718      */
5719     fireEvent : function(){
5720         var ce = this.events[arguments[0].toLowerCase()];
5721         if(typeof ce == "object"){
5722             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5723         }else{
5724             return true;
5725         }
5726     },
5727
5728     // private
5729     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5730
5731     /**
5732      * Appends an event handler to this component
5733      * @param {String}   eventName The type of event to listen for
5734      * @param {Function} handler The method the event invokes
5735      * @param {Object}   scope (optional) The scope in which to execute the handler
5736      * function. The handler function's "this" context.
5737      * @param {Object}   options (optional) An object containing handler configuration
5738      * properties. This may contain any of the following properties:<ul>
5739      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5740      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5741      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5742      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5743      * by the specified number of milliseconds. If the event fires again within that time, the original
5744      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5745      * </ul><br>
5746      * <p>
5747      * <b>Combining Options</b><br>
5748      * Using the options argument, it is possible to combine different types of listeners:<br>
5749      * <br>
5750      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5751                 <pre><code>
5752                 el.on('click', this.onClick, this, {
5753                         single: true,
5754                 delay: 100,
5755                 forumId: 4
5756                 });
5757                 </code></pre>
5758      * <p>
5759      * <b>Attaching multiple handlers in 1 call</b><br>
5760      * The method also allows for a single argument to be passed which is a config object containing properties
5761      * which specify multiple handlers.
5762      * <pre><code>
5763                 el.on({
5764                         'click': {
5765                         fn: this.onClick,
5766                         scope: this,
5767                         delay: 100
5768                 }, 
5769                 'mouseover': {
5770                         fn: this.onMouseOver,
5771                         scope: this
5772                 },
5773                 'mouseout': {
5774                         fn: this.onMouseOut,
5775                         scope: this
5776                 }
5777                 });
5778                 </code></pre>
5779      * <p>
5780      * Or a shorthand syntax which passes the same scope object to all handlers:
5781         <pre><code>
5782                 el.on({
5783                         'click': this.onClick,
5784                 'mouseover': this.onMouseOver,
5785                 'mouseout': this.onMouseOut,
5786                 scope: this
5787                 });
5788                 </code></pre>
5789      */
5790     addListener : function(eventName, fn, scope, o){
5791         if(typeof eventName == "object"){
5792             o = eventName;
5793             for(var e in o){
5794                 if(this.filterOptRe.test(e)){
5795                     continue;
5796                 }
5797                 if(typeof o[e] == "function"){
5798                     // shared options
5799                     this.addListener(e, o[e], o.scope,  o);
5800                 }else{
5801                     // individual options
5802                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5803                 }
5804             }
5805             return;
5806         }
5807         o = (!o || typeof o == "boolean") ? {} : o;
5808         eventName = eventName.toLowerCase();
5809         var ce = this.events[eventName] || true;
5810         if(typeof ce == "boolean"){
5811             ce = new Roo.util.Event(this, eventName);
5812             this.events[eventName] = ce;
5813         }
5814         ce.addListener(fn, scope, o);
5815     },
5816
5817     /**
5818      * Removes a listener
5819      * @param {String}   eventName     The type of event to listen for
5820      * @param {Function} handler        The handler to remove
5821      * @param {Object}   scope  (optional) The scope (this object) for the handler
5822      */
5823     removeListener : function(eventName, fn, scope){
5824         var ce = this.events[eventName.toLowerCase()];
5825         if(typeof ce == "object"){
5826             ce.removeListener(fn, scope);
5827         }
5828     },
5829
5830     /**
5831      * Removes all listeners for this object
5832      */
5833     purgeListeners : function(){
5834         for(var evt in this.events){
5835             if(typeof this.events[evt] == "object"){
5836                  this.events[evt].clearListeners();
5837             }
5838         }
5839     },
5840
5841     relayEvents : function(o, events){
5842         var createHandler = function(ename){
5843             return function(){
5844                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5845             };
5846         };
5847         for(var i = 0, len = events.length; i < len; i++){
5848             var ename = events[i];
5849             if(!this.events[ename]){ this.events[ename] = true; };
5850             o.on(ename, createHandler(ename), this);
5851         }
5852     },
5853
5854     /**
5855      * Used to define events on this Observable
5856      * @param {Object} object The object with the events defined
5857      */
5858     addEvents : function(o){
5859         if(!this.events){
5860             this.events = {};
5861         }
5862         Roo.applyIf(this.events, o);
5863     },
5864
5865     /**
5866      * Checks to see if this object has any listeners for a specified event
5867      * @param {String} eventName The name of the event to check for
5868      * @return {Boolean} True if the event is being listened for, else false
5869      */
5870     hasListener : function(eventName){
5871         var e = this.events[eventName];
5872         return typeof e == "object" && e.listeners.length > 0;
5873     }
5874 };
5875 /**
5876  * Appends an event handler to this element (shorthand for addListener)
5877  * @param {String}   eventName     The type of event to listen for
5878  * @param {Function} handler        The method the event invokes
5879  * @param {Object}   scope (optional) The scope in which to execute the handler
5880  * function. The handler function's "this" context.
5881  * @param {Object}   options  (optional)
5882  * @method
5883  */
5884 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5885 /**
5886  * Removes a listener (shorthand for removeListener)
5887  * @param {String}   eventName     The type of event to listen for
5888  * @param {Function} handler        The handler to remove
5889  * @param {Object}   scope  (optional) The scope (this object) for the handler
5890  * @method
5891  */
5892 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5893
5894 /**
5895  * Starts capture on the specified Observable. All events will be passed
5896  * to the supplied function with the event name + standard signature of the event
5897  * <b>before</b> the event is fired. If the supplied function returns false,
5898  * the event will not fire.
5899  * @param {Observable} o The Observable to capture
5900  * @param {Function} fn The function to call
5901  * @param {Object} scope (optional) The scope (this object) for the fn
5902  * @static
5903  */
5904 Roo.util.Observable.capture = function(o, fn, scope){
5905     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5906 };
5907
5908 /**
5909  * Removes <b>all</b> added captures from the Observable.
5910  * @param {Observable} o The Observable to release
5911  * @static
5912  */
5913 Roo.util.Observable.releaseCapture = function(o){
5914     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5915 };
5916
5917 (function(){
5918
5919     var createBuffered = function(h, o, scope){
5920         var task = new Roo.util.DelayedTask();
5921         return function(){
5922             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5923         };
5924     };
5925
5926     var createSingle = function(h, e, fn, scope){
5927         return function(){
5928             e.removeListener(fn, scope);
5929             return h.apply(scope, arguments);
5930         };
5931     };
5932
5933     var createDelayed = function(h, o, scope){
5934         return function(){
5935             var args = Array.prototype.slice.call(arguments, 0);
5936             setTimeout(function(){
5937                 h.apply(scope, args);
5938             }, o.delay || 10);
5939         };
5940     };
5941
5942     Roo.util.Event = function(obj, name){
5943         this.name = name;
5944         this.obj = obj;
5945         this.listeners = [];
5946     };
5947
5948     Roo.util.Event.prototype = {
5949         addListener : function(fn, scope, options){
5950             var o = options || {};
5951             scope = scope || this.obj;
5952             if(!this.isListening(fn, scope)){
5953                 var l = {fn: fn, scope: scope, options: o};
5954                 var h = fn;
5955                 if(o.delay){
5956                     h = createDelayed(h, o, scope);
5957                 }
5958                 if(o.single){
5959                     h = createSingle(h, this, fn, scope);
5960                 }
5961                 if(o.buffer){
5962                     h = createBuffered(h, o, scope);
5963                 }
5964                 l.fireFn = h;
5965                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5966                     this.listeners.push(l);
5967                 }else{
5968                     this.listeners = this.listeners.slice(0);
5969                     this.listeners.push(l);
5970                 }
5971             }
5972         },
5973
5974         findListener : function(fn, scope){
5975             scope = scope || this.obj;
5976             var ls = this.listeners;
5977             for(var i = 0, len = ls.length; i < len; i++){
5978                 var l = ls[i];
5979                 if(l.fn == fn && l.scope == scope){
5980                     return i;
5981                 }
5982             }
5983             return -1;
5984         },
5985
5986         isListening : function(fn, scope){
5987             return this.findListener(fn, scope) != -1;
5988         },
5989
5990         removeListener : function(fn, scope){
5991             var index;
5992             if((index = this.findListener(fn, scope)) != -1){
5993                 if(!this.firing){
5994                     this.listeners.splice(index, 1);
5995                 }else{
5996                     this.listeners = this.listeners.slice(0);
5997                     this.listeners.splice(index, 1);
5998                 }
5999                 return true;
6000             }
6001             return false;
6002         },
6003
6004         clearListeners : function(){
6005             this.listeners = [];
6006         },
6007
6008         fire : function(){
6009             var ls = this.listeners, scope, len = ls.length;
6010             if(len > 0){
6011                 this.firing = true;
6012                 var args = Array.prototype.slice.call(arguments, 0);
6013                 for(var i = 0; i < len; i++){
6014                     var l = ls[i];
6015                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6016                         this.firing = false;
6017                         return false;
6018                     }
6019                 }
6020                 this.firing = false;
6021             }
6022             return true;
6023         }
6024     };
6025 })();/*
6026  * Based on:
6027  * Ext JS Library 1.1.1
6028  * Copyright(c) 2006-2007, Ext JS, LLC.
6029  *
6030  * Originally Released Under LGPL - original licence link has changed is not relivant.
6031  *
6032  * Fork - LGPL
6033  * <script type="text/javascript">
6034  */
6035
6036 /**
6037  * @class Roo.EventManager
6038  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6039  * several useful events directly.
6040  * See {@link Roo.EventObject} for more details on normalized event objects.
6041  * @singleton
6042  */
6043 Roo.EventManager = function(){
6044     var docReadyEvent, docReadyProcId, docReadyState = false;
6045     var resizeEvent, resizeTask, textEvent, textSize;
6046     var E = Roo.lib.Event;
6047     var D = Roo.lib.Dom;
6048
6049
6050     var fireDocReady = function(){
6051         if(!docReadyState){
6052             docReadyState = true;
6053             Roo.isReady = true;
6054             if(docReadyProcId){
6055                 clearInterval(docReadyProcId);
6056             }
6057             if(Roo.isGecko || Roo.isOpera) {
6058                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6059             }
6060             if(Roo.isIE){
6061                 var defer = document.getElementById("ie-deferred-loader");
6062                 if(defer){
6063                     defer.onreadystatechange = null;
6064                     defer.parentNode.removeChild(defer);
6065                 }
6066             }
6067             if(docReadyEvent){
6068                 docReadyEvent.fire();
6069                 docReadyEvent.clearListeners();
6070             }
6071         }
6072     };
6073     
6074     var initDocReady = function(){
6075         docReadyEvent = new Roo.util.Event();
6076         if(Roo.isGecko || Roo.isOpera) {
6077             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6078         }else if(Roo.isIE){
6079             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6080             var defer = document.getElementById("ie-deferred-loader");
6081             defer.onreadystatechange = function(){
6082                 if(this.readyState == "complete"){
6083                     fireDocReady();
6084                 }
6085             };
6086         }else if(Roo.isSafari){ 
6087             docReadyProcId = setInterval(function(){
6088                 var rs = document.readyState;
6089                 if(rs == "complete") {
6090                     fireDocReady();     
6091                  }
6092             }, 10);
6093         }
6094         // no matter what, make sure it fires on load
6095         E.on(window, "load", fireDocReady);
6096     };
6097
6098     var createBuffered = function(h, o){
6099         var task = new Roo.util.DelayedTask(h);
6100         return function(e){
6101             // create new event object impl so new events don't wipe out properties
6102             e = new Roo.EventObjectImpl(e);
6103             task.delay(o.buffer, h, null, [e]);
6104         };
6105     };
6106
6107     var createSingle = function(h, el, ename, fn){
6108         return function(e){
6109             Roo.EventManager.removeListener(el, ename, fn);
6110             h(e);
6111         };
6112     };
6113
6114     var createDelayed = function(h, o){
6115         return function(e){
6116             // create new event object impl so new events don't wipe out properties
6117             e = new Roo.EventObjectImpl(e);
6118             setTimeout(function(){
6119                 h(e);
6120             }, o.delay || 10);
6121         };
6122     };
6123
6124     var listen = function(element, ename, opt, fn, scope){
6125         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6126         fn = fn || o.fn; scope = scope || o.scope;
6127         var el = Roo.getDom(element);
6128         if(!el){
6129             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6130         }
6131         var h = function(e){
6132             e = Roo.EventObject.setEvent(e);
6133             var t;
6134             if(o.delegate){
6135                 t = e.getTarget(o.delegate, el);
6136                 if(!t){
6137                     return;
6138                 }
6139             }else{
6140                 t = e.target;
6141             }
6142             if(o.stopEvent === true){
6143                 e.stopEvent();
6144             }
6145             if(o.preventDefault === true){
6146                e.preventDefault();
6147             }
6148             if(o.stopPropagation === true){
6149                 e.stopPropagation();
6150             }
6151
6152             if(o.normalized === false){
6153                 e = e.browserEvent;
6154             }
6155
6156             fn.call(scope || el, e, t, o);
6157         };
6158         if(o.delay){
6159             h = createDelayed(h, o);
6160         }
6161         if(o.single){
6162             h = createSingle(h, el, ename, fn);
6163         }
6164         if(o.buffer){
6165             h = createBuffered(h, o);
6166         }
6167         fn._handlers = fn._handlers || [];
6168         fn._handlers.push([Roo.id(el), ename, h]);
6169
6170         E.on(el, ename, h);
6171         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6172             el.addEventListener("DOMMouseScroll", h, false);
6173             E.on(window, 'unload', function(){
6174                 el.removeEventListener("DOMMouseScroll", h, false);
6175             });
6176         }
6177         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6178             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6179         }
6180         return h;
6181     };
6182
6183     var stopListening = function(el, ename, fn){
6184         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6185         if(hds){
6186             for(var i = 0, len = hds.length; i < len; i++){
6187                 var h = hds[i];
6188                 if(h[0] == id && h[1] == ename){
6189                     hd = h[2];
6190                     hds.splice(i, 1);
6191                     break;
6192                 }
6193             }
6194         }
6195         E.un(el, ename, hd);
6196         el = Roo.getDom(el);
6197         if(ename == "mousewheel" && el.addEventListener){
6198             el.removeEventListener("DOMMouseScroll", hd, false);
6199         }
6200         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6201             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6202         }
6203     };
6204
6205     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6206     
6207     var pub = {
6208         
6209         
6210         /** 
6211          * Fix for doc tools
6212          * @scope Roo.EventManager
6213          */
6214         
6215         
6216         /** 
6217          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6218          * object with a Roo.EventObject
6219          * @param {Function} fn        The method the event invokes
6220          * @param {Object}   scope    An object that becomes the scope of the handler
6221          * @param {boolean}  override If true, the obj passed in becomes
6222          *                             the execution scope of the listener
6223          * @return {Function} The wrapped function
6224          * @deprecated
6225          */
6226         wrap : function(fn, scope, override){
6227             return function(e){
6228                 Roo.EventObject.setEvent(e);
6229                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6230             };
6231         },
6232         
6233         /**
6234      * Appends an event handler to an element (shorthand for addListener)
6235      * @param {String/HTMLElement}   element        The html element or id to assign the
6236      * @param {String}   eventName The type of event to listen for
6237      * @param {Function} handler The method the event invokes
6238      * @param {Object}   scope (optional) The scope in which to execute the handler
6239      * function. The handler function's "this" context.
6240      * @param {Object}   options (optional) An object containing handler configuration
6241      * properties. This may contain any of the following properties:<ul>
6242      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6243      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6244      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6245      * <li>preventDefault {Boolean} True to prevent the default action</li>
6246      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6247      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6248      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6249      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6250      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6251      * by the specified number of milliseconds. If the event fires again within that time, the original
6252      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6253      * </ul><br>
6254      * <p>
6255      * <b>Combining Options</b><br>
6256      * Using the options argument, it is possible to combine different types of listeners:<br>
6257      * <br>
6258      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6259      * Code:<pre><code>
6260 el.on('click', this.onClick, this, {
6261     single: true,
6262     delay: 100,
6263     stopEvent : true,
6264     forumId: 4
6265 });</code></pre>
6266      * <p>
6267      * <b>Attaching multiple handlers in 1 call</b><br>
6268       * The method also allows for a single argument to be passed which is a config object containing properties
6269      * which specify multiple handlers.
6270      * <p>
6271      * Code:<pre><code>
6272 el.on({
6273     'click' : {
6274         fn: this.onClick
6275         scope: this,
6276         delay: 100
6277     },
6278     'mouseover' : {
6279         fn: this.onMouseOver
6280         scope: this
6281     },
6282     'mouseout' : {
6283         fn: this.onMouseOut
6284         scope: this
6285     }
6286 });</code></pre>
6287      * <p>
6288      * Or a shorthand syntax:<br>
6289      * Code:<pre><code>
6290 el.on({
6291     'click' : this.onClick,
6292     'mouseover' : this.onMouseOver,
6293     'mouseout' : this.onMouseOut
6294     scope: this
6295 });</code></pre>
6296      */
6297         addListener : function(element, eventName, fn, scope, options){
6298             if(typeof eventName == "object"){
6299                 var o = eventName;
6300                 for(var e in o){
6301                     if(propRe.test(e)){
6302                         continue;
6303                     }
6304                     if(typeof o[e] == "function"){
6305                         // shared options
6306                         listen(element, e, o, o[e], o.scope);
6307                     }else{
6308                         // individual options
6309                         listen(element, e, o[e]);
6310                     }
6311                 }
6312                 return;
6313             }
6314             return listen(element, eventName, options, fn, scope);
6315         },
6316         
6317         /**
6318          * Removes an event handler
6319          *
6320          * @param {String/HTMLElement}   element        The id or html element to remove the 
6321          *                             event from
6322          * @param {String}   eventName     The type of event
6323          * @param {Function} fn
6324          * @return {Boolean} True if a listener was actually removed
6325          */
6326         removeListener : function(element, eventName, fn){
6327             return stopListening(element, eventName, fn);
6328         },
6329         
6330         /**
6331          * Fires when the document is ready (before onload and before images are loaded). Can be 
6332          * accessed shorthanded Roo.onReady().
6333          * @param {Function} fn        The method the event invokes
6334          * @param {Object}   scope    An  object that becomes the scope of the handler
6335          * @param {boolean}  options
6336          */
6337         onDocumentReady : function(fn, scope, options){
6338             if(docReadyState){ // if it already fired
6339                 docReadyEvent.addListener(fn, scope, options);
6340                 docReadyEvent.fire();
6341                 docReadyEvent.clearListeners();
6342                 return;
6343             }
6344             if(!docReadyEvent){
6345                 initDocReady();
6346             }
6347             docReadyEvent.addListener(fn, scope, options);
6348         },
6349         
6350         /**
6351          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6352          * @param {Function} fn        The method the event invokes
6353          * @param {Object}   scope    An object that becomes the scope of the handler
6354          * @param {boolean}  options
6355          */
6356         onWindowResize : function(fn, scope, options){
6357             if(!resizeEvent){
6358                 resizeEvent = new Roo.util.Event();
6359                 resizeTask = new Roo.util.DelayedTask(function(){
6360                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6361                 });
6362                 E.on(window, "resize", function(){
6363                     if(Roo.isIE){
6364                         resizeTask.delay(50);
6365                     }else{
6366                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6367                     }
6368                 });
6369             }
6370             resizeEvent.addListener(fn, scope, options);
6371         },
6372
6373         /**
6374          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6375          * @param {Function} fn        The method the event invokes
6376          * @param {Object}   scope    An object that becomes the scope of the handler
6377          * @param {boolean}  options
6378          */
6379         onTextResize : function(fn, scope, options){
6380             if(!textEvent){
6381                 textEvent = new Roo.util.Event();
6382                 var textEl = new Roo.Element(document.createElement('div'));
6383                 textEl.dom.className = 'x-text-resize';
6384                 textEl.dom.innerHTML = 'X';
6385                 textEl.appendTo(document.body);
6386                 textSize = textEl.dom.offsetHeight;
6387                 setInterval(function(){
6388                     if(textEl.dom.offsetHeight != textSize){
6389                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6390                     }
6391                 }, this.textResizeInterval);
6392             }
6393             textEvent.addListener(fn, scope, options);
6394         },
6395
6396         /**
6397          * Removes the passed window resize listener.
6398          * @param {Function} fn        The method the event invokes
6399          * @param {Object}   scope    The scope of handler
6400          */
6401         removeResizeListener : function(fn, scope){
6402             if(resizeEvent){
6403                 resizeEvent.removeListener(fn, scope);
6404             }
6405         },
6406
6407         // private
6408         fireResize : function(){
6409             if(resizeEvent){
6410                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6411             }   
6412         },
6413         /**
6414          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6415          */
6416         ieDeferSrc : false,
6417         /**
6418          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6419          */
6420         textResizeInterval : 50
6421     };
6422     
6423     /**
6424      * Fix for doc tools
6425      * @scopeAlias pub=Roo.EventManager
6426      */
6427     
6428      /**
6429      * Appends an event handler to an element (shorthand for addListener)
6430      * @param {String/HTMLElement}   element        The html element or id to assign the
6431      * @param {String}   eventName The type of event to listen for
6432      * @param {Function} handler The method the event invokes
6433      * @param {Object}   scope (optional) The scope in which to execute the handler
6434      * function. The handler function's "this" context.
6435      * @param {Object}   options (optional) An object containing handler configuration
6436      * properties. This may contain any of the following properties:<ul>
6437      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6438      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6439      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6440      * <li>preventDefault {Boolean} True to prevent the default action</li>
6441      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6442      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6443      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6444      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6445      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6446      * by the specified number of milliseconds. If the event fires again within that time, the original
6447      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6448      * </ul><br>
6449      * <p>
6450      * <b>Combining Options</b><br>
6451      * Using the options argument, it is possible to combine different types of listeners:<br>
6452      * <br>
6453      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6454      * Code:<pre><code>
6455 el.on('click', this.onClick, this, {
6456     single: true,
6457     delay: 100,
6458     stopEvent : true,
6459     forumId: 4
6460 });</code></pre>
6461      * <p>
6462      * <b>Attaching multiple handlers in 1 call</b><br>
6463       * The method also allows for a single argument to be passed which is a config object containing properties
6464      * which specify multiple handlers.
6465      * <p>
6466      * Code:<pre><code>
6467 el.on({
6468     'click' : {
6469         fn: this.onClick
6470         scope: this,
6471         delay: 100
6472     },
6473     'mouseover' : {
6474         fn: this.onMouseOver
6475         scope: this
6476     },
6477     'mouseout' : {
6478         fn: this.onMouseOut
6479         scope: this
6480     }
6481 });</code></pre>
6482      * <p>
6483      * Or a shorthand syntax:<br>
6484      * Code:<pre><code>
6485 el.on({
6486     'click' : this.onClick,
6487     'mouseover' : this.onMouseOver,
6488     'mouseout' : this.onMouseOut
6489     scope: this
6490 });</code></pre>
6491      */
6492     pub.on = pub.addListener;
6493     pub.un = pub.removeListener;
6494
6495     pub.stoppedMouseDownEvent = new Roo.util.Event();
6496     return pub;
6497 }();
6498 /**
6499   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6500   * @param {Function} fn        The method the event invokes
6501   * @param {Object}   scope    An  object that becomes the scope of the handler
6502   * @param {boolean}  override If true, the obj passed in becomes
6503   *                             the execution scope of the listener
6504   * @member Roo
6505   * @method onReady
6506  */
6507 Roo.onReady = Roo.EventManager.onDocumentReady;
6508
6509 Roo.onReady(function(){
6510     var bd = Roo.get(document.body);
6511     if(!bd){ return; }
6512
6513     var cls = [
6514             Roo.isIE ? "roo-ie"
6515             : Roo.isGecko ? "roo-gecko"
6516             : Roo.isOpera ? "roo-opera"
6517             : Roo.isSafari ? "roo-safari" : ""];
6518
6519     if(Roo.isMac){
6520         cls.push("roo-mac");
6521     }
6522     if(Roo.isLinux){
6523         cls.push("roo-linux");
6524     }
6525     if(Roo.isBorderBox){
6526         cls.push('roo-border-box');
6527     }
6528     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6529         var p = bd.dom.parentNode;
6530         if(p){
6531             p.className += ' roo-strict';
6532         }
6533     }
6534     bd.addClass(cls.join(' '));
6535 });
6536
6537 /**
6538  * @class Roo.EventObject
6539  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6540  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6541  * Example:
6542  * <pre><code>
6543  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6544     e.preventDefault();
6545     var target = e.getTarget();
6546     ...
6547  }
6548  var myDiv = Roo.get("myDiv");
6549  myDiv.on("click", handleClick);
6550  //or
6551  Roo.EventManager.on("myDiv", 'click', handleClick);
6552  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6553  </code></pre>
6554  * @singleton
6555  */
6556 Roo.EventObject = function(){
6557     
6558     var E = Roo.lib.Event;
6559     
6560     // safari keypress events for special keys return bad keycodes
6561     var safariKeys = {
6562         63234 : 37, // left
6563         63235 : 39, // right
6564         63232 : 38, // up
6565         63233 : 40, // down
6566         63276 : 33, // page up
6567         63277 : 34, // page down
6568         63272 : 46, // delete
6569         63273 : 36, // home
6570         63275 : 35  // end
6571     };
6572
6573     // normalize button clicks
6574     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6575                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6576
6577     Roo.EventObjectImpl = function(e){
6578         if(e){
6579             this.setEvent(e.browserEvent || e);
6580         }
6581     };
6582     Roo.EventObjectImpl.prototype = {
6583         /**
6584          * Used to fix doc tools.
6585          * @scope Roo.EventObject.prototype
6586          */
6587             
6588
6589         
6590         
6591         /** The normal browser event */
6592         browserEvent : null,
6593         /** The button pressed in a mouse event */
6594         button : -1,
6595         /** True if the shift key was down during the event */
6596         shiftKey : false,
6597         /** True if the control key was down during the event */
6598         ctrlKey : false,
6599         /** True if the alt key was down during the event */
6600         altKey : false,
6601
6602         /** Key constant 
6603         * @type Number */
6604         BACKSPACE : 8,
6605         /** Key constant 
6606         * @type Number */
6607         TAB : 9,
6608         /** Key constant 
6609         * @type Number */
6610         RETURN : 13,
6611         /** Key constant 
6612         * @type Number */
6613         ENTER : 13,
6614         /** Key constant 
6615         * @type Number */
6616         SHIFT : 16,
6617         /** Key constant 
6618         * @type Number */
6619         CONTROL : 17,
6620         /** Key constant 
6621         * @type Number */
6622         ESC : 27,
6623         /** Key constant 
6624         * @type Number */
6625         SPACE : 32,
6626         /** Key constant 
6627         * @type Number */
6628         PAGEUP : 33,
6629         /** Key constant 
6630         * @type Number */
6631         PAGEDOWN : 34,
6632         /** Key constant 
6633         * @type Number */
6634         END : 35,
6635         /** Key constant 
6636         * @type Number */
6637         HOME : 36,
6638         /** Key constant 
6639         * @type Number */
6640         LEFT : 37,
6641         /** Key constant 
6642         * @type Number */
6643         UP : 38,
6644         /** Key constant 
6645         * @type Number */
6646         RIGHT : 39,
6647         /** Key constant 
6648         * @type Number */
6649         DOWN : 40,
6650         /** Key constant 
6651         * @type Number */
6652         DELETE : 46,
6653         /** Key constant 
6654         * @type Number */
6655         F5 : 116,
6656
6657            /** @private */
6658         setEvent : function(e){
6659             if(e == this || (e && e.browserEvent)){ // already wrapped
6660                 return e;
6661             }
6662             this.browserEvent = e;
6663             if(e){
6664                 // normalize buttons
6665                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6666                 if(e.type == 'click' && this.button == -1){
6667                     this.button = 0;
6668                 }
6669                 this.type = e.type;
6670                 this.shiftKey = e.shiftKey;
6671                 // mac metaKey behaves like ctrlKey
6672                 this.ctrlKey = e.ctrlKey || e.metaKey;
6673                 this.altKey = e.altKey;
6674                 // in getKey these will be normalized for the mac
6675                 this.keyCode = e.keyCode;
6676                 // keyup warnings on firefox.
6677                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6678                 // cache the target for the delayed and or buffered events
6679                 this.target = E.getTarget(e);
6680                 // same for XY
6681                 this.xy = E.getXY(e);
6682             }else{
6683                 this.button = -1;
6684                 this.shiftKey = false;
6685                 this.ctrlKey = false;
6686                 this.altKey = false;
6687                 this.keyCode = 0;
6688                 this.charCode =0;
6689                 this.target = null;
6690                 this.xy = [0, 0];
6691             }
6692             return this;
6693         },
6694
6695         /**
6696          * Stop the event (preventDefault and stopPropagation)
6697          */
6698         stopEvent : function(){
6699             if(this.browserEvent){
6700                 if(this.browserEvent.type == 'mousedown'){
6701                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6702                 }
6703                 E.stopEvent(this.browserEvent);
6704             }
6705         },
6706
6707         /**
6708          * Prevents the browsers default handling of the event.
6709          */
6710         preventDefault : function(){
6711             if(this.browserEvent){
6712                 E.preventDefault(this.browserEvent);
6713             }
6714         },
6715
6716         /** @private */
6717         isNavKeyPress : function(){
6718             var k = this.keyCode;
6719             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6720             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6721         },
6722
6723         isSpecialKey : function(){
6724             var k = this.keyCode;
6725             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6726             (k == 16) || (k == 17) ||
6727             (k >= 18 && k <= 20) ||
6728             (k >= 33 && k <= 35) ||
6729             (k >= 36 && k <= 39) ||
6730             (k >= 44 && k <= 45);
6731         },
6732         /**
6733          * Cancels bubbling of the event.
6734          */
6735         stopPropagation : function(){
6736             if(this.browserEvent){
6737                 if(this.type == 'mousedown'){
6738                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6739                 }
6740                 E.stopPropagation(this.browserEvent);
6741             }
6742         },
6743
6744         /**
6745          * Gets the key code for the event.
6746          * @return {Number}
6747          */
6748         getCharCode : function(){
6749             return this.charCode || this.keyCode;
6750         },
6751
6752         /**
6753          * Returns a normalized keyCode for the event.
6754          * @return {Number} The key code
6755          */
6756         getKey : function(){
6757             var k = this.keyCode || this.charCode;
6758             return Roo.isSafari ? (safariKeys[k] || k) : k;
6759         },
6760
6761         /**
6762          * Gets the x coordinate of the event.
6763          * @return {Number}
6764          */
6765         getPageX : function(){
6766             return this.xy[0];
6767         },
6768
6769         /**
6770          * Gets the y coordinate of the event.
6771          * @return {Number}
6772          */
6773         getPageY : function(){
6774             return this.xy[1];
6775         },
6776
6777         /**
6778          * Gets the time of the event.
6779          * @return {Number}
6780          */
6781         getTime : function(){
6782             if(this.browserEvent){
6783                 return E.getTime(this.browserEvent);
6784             }
6785             return null;
6786         },
6787
6788         /**
6789          * Gets the page coordinates of the event.
6790          * @return {Array} The xy values like [x, y]
6791          */
6792         getXY : function(){
6793             return this.xy;
6794         },
6795
6796         /**
6797          * Gets the target for the event.
6798          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6799          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6800                 search as a number or element (defaults to 10 || document.body)
6801          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6802          * @return {HTMLelement}
6803          */
6804         getTarget : function(selector, maxDepth, returnEl){
6805             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6806         },
6807         /**
6808          * Gets the related target.
6809          * @return {HTMLElement}
6810          */
6811         getRelatedTarget : function(){
6812             if(this.browserEvent){
6813                 return E.getRelatedTarget(this.browserEvent);
6814             }
6815             return null;
6816         },
6817
6818         /**
6819          * Normalizes mouse wheel delta across browsers
6820          * @return {Number} The delta
6821          */
6822         getWheelDelta : function(){
6823             var e = this.browserEvent;
6824             var delta = 0;
6825             if(e.wheelDelta){ /* IE/Opera. */
6826                 delta = e.wheelDelta/120;
6827             }else if(e.detail){ /* Mozilla case. */
6828                 delta = -e.detail/3;
6829             }
6830             return delta;
6831         },
6832
6833         /**
6834          * Returns true if the control, meta, shift or alt key was pressed during this event.
6835          * @return {Boolean}
6836          */
6837         hasModifier : function(){
6838             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6839         },
6840
6841         /**
6842          * Returns true if the target of this event equals el or is a child of el
6843          * @param {String/HTMLElement/Element} el
6844          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6845          * @return {Boolean}
6846          */
6847         within : function(el, related){
6848             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6849             return t && Roo.fly(el).contains(t);
6850         },
6851
6852         getPoint : function(){
6853             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6854         }
6855     };
6856
6857     return new Roo.EventObjectImpl();
6858 }();
6859             
6860     /*
6861  * Based on:
6862  * Ext JS Library 1.1.1
6863  * Copyright(c) 2006-2007, Ext JS, LLC.
6864  *
6865  * Originally Released Under LGPL - original licence link has changed is not relivant.
6866  *
6867  * Fork - LGPL
6868  * <script type="text/javascript">
6869  */
6870
6871  
6872 // was in Composite Element!??!?!
6873  
6874 (function(){
6875     var D = Roo.lib.Dom;
6876     var E = Roo.lib.Event;
6877     var A = Roo.lib.Anim;
6878
6879     // local style camelizing for speed
6880     var propCache = {};
6881     var camelRe = /(-[a-z])/gi;
6882     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6883     var view = document.defaultView;
6884
6885 /**
6886  * @class Roo.Element
6887  * Represents an Element in the DOM.<br><br>
6888  * Usage:<br>
6889 <pre><code>
6890 var el = Roo.get("my-div");
6891
6892 // or with getEl
6893 var el = getEl("my-div");
6894
6895 // or with a DOM element
6896 var el = Roo.get(myDivElement);
6897 </code></pre>
6898  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6899  * each call instead of constructing a new one.<br><br>
6900  * <b>Animations</b><br />
6901  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6902  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6903 <pre>
6904 Option    Default   Description
6905 --------- --------  ---------------------------------------------
6906 duration  .35       The duration of the animation in seconds
6907 easing    easeOut   The YUI easing method
6908 callback  none      A function to execute when the anim completes
6909 scope     this      The scope (this) of the callback function
6910 </pre>
6911 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6912 * manipulate the animation. Here's an example:
6913 <pre><code>
6914 var el = Roo.get("my-div");
6915
6916 // no animation
6917 el.setWidth(100);
6918
6919 // default animation
6920 el.setWidth(100, true);
6921
6922 // animation with some options set
6923 el.setWidth(100, {
6924     duration: 1,
6925     callback: this.foo,
6926     scope: this
6927 });
6928
6929 // using the "anim" property to get the Anim object
6930 var opt = {
6931     duration: 1,
6932     callback: this.foo,
6933     scope: this
6934 };
6935 el.setWidth(100, opt);
6936 ...
6937 if(opt.anim.isAnimated()){
6938     opt.anim.stop();
6939 }
6940 </code></pre>
6941 * <b> Composite (Collections of) Elements</b><br />
6942  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6943  * @constructor Create a new Element directly.
6944  * @param {String/HTMLElement} element
6945  * @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).
6946  */
6947     Roo.Element = function(element, forceNew){
6948         var dom = typeof element == "string" ?
6949                 document.getElementById(element) : element;
6950         if(!dom){ // invalid id/element
6951             return null;
6952         }
6953         var id = dom.id;
6954         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6955             return Roo.Element.cache[id];
6956         }
6957
6958         /**
6959          * The DOM element
6960          * @type HTMLElement
6961          */
6962         this.dom = dom;
6963
6964         /**
6965          * The DOM element ID
6966          * @type String
6967          */
6968         this.id = id || Roo.id(dom);
6969     };
6970
6971     var El = Roo.Element;
6972
6973     El.prototype = {
6974         /**
6975          * The element's default display mode  (defaults to "")
6976          * @type String
6977          */
6978         originalDisplay : "",
6979
6980         visibilityMode : 1,
6981         /**
6982          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6983          * @type String
6984          */
6985         defaultUnit : "px",
6986         /**
6987          * Sets the element's visibility mode. When setVisible() is called it
6988          * will use this to determine whether to set the visibility or the display property.
6989          * @param visMode Element.VISIBILITY or Element.DISPLAY
6990          * @return {Roo.Element} this
6991          */
6992         setVisibilityMode : function(visMode){
6993             this.visibilityMode = visMode;
6994             return this;
6995         },
6996         /**
6997          * Convenience method for setVisibilityMode(Element.DISPLAY)
6998          * @param {String} display (optional) What to set display to when visible
6999          * @return {Roo.Element} this
7000          */
7001         enableDisplayMode : function(display){
7002             this.setVisibilityMode(El.DISPLAY);
7003             if(typeof display != "undefined") this.originalDisplay = display;
7004             return this;
7005         },
7006
7007         /**
7008          * 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)
7009          * @param {String} selector The simple selector to test
7010          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7011                 search as a number or element (defaults to 10 || document.body)
7012          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7013          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7014          */
7015         findParent : function(simpleSelector, maxDepth, returnEl){
7016             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7017             maxDepth = maxDepth || 50;
7018             if(typeof maxDepth != "number"){
7019                 stopEl = Roo.getDom(maxDepth);
7020                 maxDepth = 10;
7021             }
7022             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7023                 if(dq.is(p, simpleSelector)){
7024                     return returnEl ? Roo.get(p) : p;
7025                 }
7026                 depth++;
7027                 p = p.parentNode;
7028             }
7029             return null;
7030         },
7031
7032
7033         /**
7034          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7035          * @param {String} selector The simple selector to test
7036          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7037                 search as a number or element (defaults to 10 || document.body)
7038          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7039          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7040          */
7041         findParentNode : function(simpleSelector, maxDepth, returnEl){
7042             var p = Roo.fly(this.dom.parentNode, '_internal');
7043             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7044         },
7045
7046         /**
7047          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7048          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7049          * @param {String} selector The simple selector to test
7050          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7051                 search as a number or element (defaults to 10 || document.body)
7052          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7053          */
7054         up : function(simpleSelector, maxDepth){
7055             return this.findParentNode(simpleSelector, maxDepth, true);
7056         },
7057
7058
7059
7060         /**
7061          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7062          * @param {String} selector The simple selector to test
7063          * @return {Boolean} True if this element matches the selector, else false
7064          */
7065         is : function(simpleSelector){
7066             return Roo.DomQuery.is(this.dom, simpleSelector);
7067         },
7068
7069         /**
7070          * Perform animation on this element.
7071          * @param {Object} args The YUI animation control args
7072          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7073          * @param {Function} onComplete (optional) Function to call when animation completes
7074          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7075          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7076          * @return {Roo.Element} this
7077          */
7078         animate : function(args, duration, onComplete, easing, animType){
7079             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7080             return this;
7081         },
7082
7083         /*
7084          * @private Internal animation call
7085          */
7086         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7087             animType = animType || 'run';
7088             opt = opt || {};
7089             var anim = Roo.lib.Anim[animType](
7090                 this.dom, args,
7091                 (opt.duration || defaultDur) || .35,
7092                 (opt.easing || defaultEase) || 'easeOut',
7093                 function(){
7094                     Roo.callback(cb, this);
7095                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7096                 },
7097                 this
7098             );
7099             opt.anim = anim;
7100             return anim;
7101         },
7102
7103         // private legacy anim prep
7104         preanim : function(a, i){
7105             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7106         },
7107
7108         /**
7109          * Removes worthless text nodes
7110          * @param {Boolean} forceReclean (optional) By default the element
7111          * keeps track if it has been cleaned already so
7112          * you can call this over and over. However, if you update the element and
7113          * need to force a reclean, you can pass true.
7114          */
7115         clean : function(forceReclean){
7116             if(this.isCleaned && forceReclean !== true){
7117                 return this;
7118             }
7119             var ns = /\S/;
7120             var d = this.dom, n = d.firstChild, ni = -1;
7121             while(n){
7122                 var nx = n.nextSibling;
7123                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7124                     d.removeChild(n);
7125                 }else{
7126                     n.nodeIndex = ++ni;
7127                 }
7128                 n = nx;
7129             }
7130             this.isCleaned = true;
7131             return this;
7132         },
7133
7134         // private
7135         calcOffsetsTo : function(el){
7136             el = Roo.get(el);
7137             var d = el.dom;
7138             var restorePos = false;
7139             if(el.getStyle('position') == 'static'){
7140                 el.position('relative');
7141                 restorePos = true;
7142             }
7143             var x = 0, y =0;
7144             var op = this.dom;
7145             while(op && op != d && op.tagName != 'HTML'){
7146                 x+= op.offsetLeft;
7147                 y+= op.offsetTop;
7148                 op = op.offsetParent;
7149             }
7150             if(restorePos){
7151                 el.position('static');
7152             }
7153             return [x, y];
7154         },
7155
7156         /**
7157          * Scrolls this element into view within the passed container.
7158          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7159          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7160          * @return {Roo.Element} this
7161          */
7162         scrollIntoView : function(container, hscroll){
7163             var c = Roo.getDom(container) || document.body;
7164             var el = this.dom;
7165
7166             var o = this.calcOffsetsTo(c),
7167                 l = o[0],
7168                 t = o[1],
7169                 b = t+el.offsetHeight,
7170                 r = l+el.offsetWidth;
7171
7172             var ch = c.clientHeight;
7173             var ct = parseInt(c.scrollTop, 10);
7174             var cl = parseInt(c.scrollLeft, 10);
7175             var cb = ct + ch;
7176             var cr = cl + c.clientWidth;
7177
7178             if(t < ct){
7179                 c.scrollTop = t;
7180             }else if(b > cb){
7181                 c.scrollTop = b-ch;
7182             }
7183
7184             if(hscroll !== false){
7185                 if(l < cl){
7186                     c.scrollLeft = l;
7187                 }else if(r > cr){
7188                     c.scrollLeft = r-c.clientWidth;
7189                 }
7190             }
7191             return this;
7192         },
7193
7194         // private
7195         scrollChildIntoView : function(child, hscroll){
7196             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7197         },
7198
7199         /**
7200          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7201          * the new height may not be available immediately.
7202          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7203          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7204          * @param {Function} onComplete (optional) Function to call when animation completes
7205          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7206          * @return {Roo.Element} this
7207          */
7208         autoHeight : function(animate, duration, onComplete, easing){
7209             var oldHeight = this.getHeight();
7210             this.clip();
7211             this.setHeight(1); // force clipping
7212             setTimeout(function(){
7213                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7214                 if(!animate){
7215                     this.setHeight(height);
7216                     this.unclip();
7217                     if(typeof onComplete == "function"){
7218                         onComplete();
7219                     }
7220                 }else{
7221                     this.setHeight(oldHeight); // restore original height
7222                     this.setHeight(height, animate, duration, function(){
7223                         this.unclip();
7224                         if(typeof onComplete == "function") onComplete();
7225                     }.createDelegate(this), easing);
7226                 }
7227             }.createDelegate(this), 0);
7228             return this;
7229         },
7230
7231         /**
7232          * Returns true if this element is an ancestor of the passed element
7233          * @param {HTMLElement/String} el The element to check
7234          * @return {Boolean} True if this element is an ancestor of el, else false
7235          */
7236         contains : function(el){
7237             if(!el){return false;}
7238             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7239         },
7240
7241         /**
7242          * Checks whether the element is currently visible using both visibility and display properties.
7243          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7244          * @return {Boolean} True if the element is currently visible, else false
7245          */
7246         isVisible : function(deep) {
7247             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7248             if(deep !== true || !vis){
7249                 return vis;
7250             }
7251             var p = this.dom.parentNode;
7252             while(p && p.tagName.toLowerCase() != "body"){
7253                 if(!Roo.fly(p, '_isVisible').isVisible()){
7254                     return false;
7255                 }
7256                 p = p.parentNode;
7257             }
7258             return true;
7259         },
7260
7261         /**
7262          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7263          * @param {String} selector The CSS selector
7264          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7265          * @return {CompositeElement/CompositeElementLite} The composite element
7266          */
7267         select : function(selector, unique){
7268             return El.select(selector, unique, this.dom);
7269         },
7270
7271         /**
7272          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7273          * @param {String} selector The CSS selector
7274          * @return {Array} An array of the matched nodes
7275          */
7276         query : function(selector, unique){
7277             return Roo.DomQuery.select(selector, this.dom);
7278         },
7279
7280         /**
7281          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7282          * @param {String} selector The CSS selector
7283          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7284          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7285          */
7286         child : function(selector, returnDom){
7287             var n = Roo.DomQuery.selectNode(selector, this.dom);
7288             return returnDom ? n : Roo.get(n);
7289         },
7290
7291         /**
7292          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7293          * @param {String} selector The CSS selector
7294          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7295          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7296          */
7297         down : function(selector, returnDom){
7298             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7299             return returnDom ? n : Roo.get(n);
7300         },
7301
7302         /**
7303          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7304          * @param {String} group The group the DD object is member of
7305          * @param {Object} config The DD config object
7306          * @param {Object} overrides An object containing methods to override/implement on the DD object
7307          * @return {Roo.dd.DD} The DD object
7308          */
7309         initDD : function(group, config, overrides){
7310             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7311             return Roo.apply(dd, overrides);
7312         },
7313
7314         /**
7315          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7316          * @param {String} group The group the DDProxy object is member of
7317          * @param {Object} config The DDProxy config object
7318          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7319          * @return {Roo.dd.DDProxy} The DDProxy object
7320          */
7321         initDDProxy : function(group, config, overrides){
7322             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7323             return Roo.apply(dd, overrides);
7324         },
7325
7326         /**
7327          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7328          * @param {String} group The group the DDTarget object is member of
7329          * @param {Object} config The DDTarget config object
7330          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7331          * @return {Roo.dd.DDTarget} The DDTarget object
7332          */
7333         initDDTarget : function(group, config, overrides){
7334             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7335             return Roo.apply(dd, overrides);
7336         },
7337
7338         /**
7339          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7340          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7341          * @param {Boolean} visible Whether the element is visible
7342          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7343          * @return {Roo.Element} this
7344          */
7345          setVisible : function(visible, animate){
7346             if(!animate || !A){
7347                 if(this.visibilityMode == El.DISPLAY){
7348                     this.setDisplayed(visible);
7349                 }else{
7350                     this.fixDisplay();
7351                     this.dom.style.visibility = visible ? "visible" : "hidden";
7352                 }
7353             }else{
7354                 // closure for composites
7355                 var dom = this.dom;
7356                 var visMode = this.visibilityMode;
7357                 if(visible){
7358                     this.setOpacity(.01);
7359                     this.setVisible(true);
7360                 }
7361                 this.anim({opacity: { to: (visible?1:0) }},
7362                       this.preanim(arguments, 1),
7363                       null, .35, 'easeIn', function(){
7364                          if(!visible){
7365                              if(visMode == El.DISPLAY){
7366                                  dom.style.display = "none";
7367                              }else{
7368                                  dom.style.visibility = "hidden";
7369                              }
7370                              Roo.get(dom).setOpacity(1);
7371                          }
7372                      });
7373             }
7374             return this;
7375         },
7376
7377         /**
7378          * Returns true if display is not "none"
7379          * @return {Boolean}
7380          */
7381         isDisplayed : function() {
7382             return this.getStyle("display") != "none";
7383         },
7384
7385         /**
7386          * Toggles the element's visibility or display, depending on visibility mode.
7387          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7388          * @return {Roo.Element} this
7389          */
7390         toggle : function(animate){
7391             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7392             return this;
7393         },
7394
7395         /**
7396          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7397          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7398          * @return {Roo.Element} this
7399          */
7400         setDisplayed : function(value) {
7401             if(typeof value == "boolean"){
7402                value = value ? this.originalDisplay : "none";
7403             }
7404             this.setStyle("display", value);
7405             return this;
7406         },
7407
7408         /**
7409          * Tries to focus the element. Any exceptions are caught and ignored.
7410          * @return {Roo.Element} this
7411          */
7412         focus : function() {
7413             try{
7414                 this.dom.focus();
7415             }catch(e){}
7416             return this;
7417         },
7418
7419         /**
7420          * Tries to blur the element. Any exceptions are caught and ignored.
7421          * @return {Roo.Element} this
7422          */
7423         blur : function() {
7424             try{
7425                 this.dom.blur();
7426             }catch(e){}
7427             return this;
7428         },
7429
7430         /**
7431          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7432          * @param {String/Array} className The CSS class to add, or an array of classes
7433          * @return {Roo.Element} this
7434          */
7435         addClass : function(className){
7436             if(className instanceof Array){
7437                 for(var i = 0, len = className.length; i < len; i++) {
7438                     this.addClass(className[i]);
7439                 }
7440             }else{
7441                 if(className && !this.hasClass(className)){
7442                     this.dom.className = this.dom.className + " " + className;
7443                 }
7444             }
7445             return this;
7446         },
7447
7448         /**
7449          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7450          * @param {String/Array} className The CSS class to add, or an array of classes
7451          * @return {Roo.Element} this
7452          */
7453         radioClass : function(className){
7454             var siblings = this.dom.parentNode.childNodes;
7455             for(var i = 0; i < siblings.length; i++) {
7456                 var s = siblings[i];
7457                 if(s.nodeType == 1){
7458                     Roo.get(s).removeClass(className);
7459                 }
7460             }
7461             this.addClass(className);
7462             return this;
7463         },
7464
7465         /**
7466          * Removes one or more CSS classes from the element.
7467          * @param {String/Array} className The CSS class to remove, or an array of classes
7468          * @return {Roo.Element} this
7469          */
7470         removeClass : function(className){
7471             if(!className || !this.dom.className){
7472                 return this;
7473             }
7474             if(className instanceof Array){
7475                 for(var i = 0, len = className.length; i < len; i++) {
7476                     this.removeClass(className[i]);
7477                 }
7478             }else{
7479                 if(this.hasClass(className)){
7480                     var re = this.classReCache[className];
7481                     if (!re) {
7482                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7483                        this.classReCache[className] = re;
7484                     }
7485                     this.dom.className =
7486                         this.dom.className.replace(re, " ");
7487                 }
7488             }
7489             return this;
7490         },
7491
7492         // private
7493         classReCache: {},
7494
7495         /**
7496          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7497          * @param {String} className The CSS class to toggle
7498          * @return {Roo.Element} this
7499          */
7500         toggleClass : function(className){
7501             if(this.hasClass(className)){
7502                 this.removeClass(className);
7503             }else{
7504                 this.addClass(className);
7505             }
7506             return this;
7507         },
7508
7509         /**
7510          * Checks if the specified CSS class exists on this element's DOM node.
7511          * @param {String} className The CSS class to check for
7512          * @return {Boolean} True if the class exists, else false
7513          */
7514         hasClass : function(className){
7515             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7516         },
7517
7518         /**
7519          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7520          * @param {String} oldClassName The CSS class to replace
7521          * @param {String} newClassName The replacement CSS class
7522          * @return {Roo.Element} this
7523          */
7524         replaceClass : function(oldClassName, newClassName){
7525             this.removeClass(oldClassName);
7526             this.addClass(newClassName);
7527             return this;
7528         },
7529
7530         /**
7531          * Returns an object with properties matching the styles requested.
7532          * For example, el.getStyles('color', 'font-size', 'width') might return
7533          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7534          * @param {String} style1 A style name
7535          * @param {String} style2 A style name
7536          * @param {String} etc.
7537          * @return {Object} The style object
7538          */
7539         getStyles : function(){
7540             var a = arguments, len = a.length, r = {};
7541             for(var i = 0; i < len; i++){
7542                 r[a[i]] = this.getStyle(a[i]);
7543             }
7544             return r;
7545         },
7546
7547         /**
7548          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7549          * @param {String} property The style property whose value is returned.
7550          * @return {String} The current value of the style property for this element.
7551          */
7552         getStyle : function(){
7553             return view && view.getComputedStyle ?
7554                 function(prop){
7555                     var el = this.dom, v, cs, camel;
7556                     if(prop == 'float'){
7557                         prop = "cssFloat";
7558                     }
7559                     if(el.style && (v = el.style[prop])){
7560                         return v;
7561                     }
7562                     if(cs = view.getComputedStyle(el, "")){
7563                         if(!(camel = propCache[prop])){
7564                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7565                         }
7566                         return cs[camel];
7567                     }
7568                     return null;
7569                 } :
7570                 function(prop){
7571                     var el = this.dom, v, cs, camel;
7572                     if(prop == 'opacity'){
7573                         if(typeof el.style.filter == 'string'){
7574                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7575                             if(m){
7576                                 var fv = parseFloat(m[1]);
7577                                 if(!isNaN(fv)){
7578                                     return fv ? fv / 100 : 0;
7579                                 }
7580                             }
7581                         }
7582                         return 1;
7583                     }else if(prop == 'float'){
7584                         prop = "styleFloat";
7585                     }
7586                     if(!(camel = propCache[prop])){
7587                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7588                     }
7589                     if(v = el.style[camel]){
7590                         return v;
7591                     }
7592                     if(cs = el.currentStyle){
7593                         return cs[camel];
7594                     }
7595                     return null;
7596                 };
7597         }(),
7598
7599         /**
7600          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7601          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7602          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7603          * @return {Roo.Element} this
7604          */
7605         setStyle : function(prop, value){
7606             if(typeof prop == "string"){
7607                 
7608                 if (prop == 'float') {
7609                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7610                     return this;
7611                 }
7612                 
7613                 var camel;
7614                 if(!(camel = propCache[prop])){
7615                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616                 }
7617                 
7618                 if(camel == 'opacity') {
7619                     this.setOpacity(value);
7620                 }else{
7621                     this.dom.style[camel] = value;
7622                 }
7623             }else{
7624                 for(var style in prop){
7625                     if(typeof prop[style] != "function"){
7626                        this.setStyle(style, prop[style]);
7627                     }
7628                 }
7629             }
7630             return this;
7631         },
7632
7633         /**
7634          * More flexible version of {@link #setStyle} for setting style properties.
7635          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7636          * a function which returns such a specification.
7637          * @return {Roo.Element} this
7638          */
7639         applyStyles : function(style){
7640             Roo.DomHelper.applyStyles(this.dom, style);
7641             return this;
7642         },
7643
7644         /**
7645           * 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).
7646           * @return {Number} The X position of the element
7647           */
7648         getX : function(){
7649             return D.getX(this.dom);
7650         },
7651
7652         /**
7653           * 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).
7654           * @return {Number} The Y position of the element
7655           */
7656         getY : function(){
7657             return D.getY(this.dom);
7658         },
7659
7660         /**
7661           * 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).
7662           * @return {Array} The XY position of the element
7663           */
7664         getXY : function(){
7665             return D.getXY(this.dom);
7666         },
7667
7668         /**
7669          * 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).
7670          * @param {Number} The X position of the element
7671          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7672          * @return {Roo.Element} this
7673          */
7674         setX : function(x, animate){
7675             if(!animate || !A){
7676                 D.setX(this.dom, x);
7677             }else{
7678                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7679             }
7680             return this;
7681         },
7682
7683         /**
7684          * 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).
7685          * @param {Number} The Y position of the element
7686          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7687          * @return {Roo.Element} this
7688          */
7689         setY : function(y, animate){
7690             if(!animate || !A){
7691                 D.setY(this.dom, y);
7692             }else{
7693                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7694             }
7695             return this;
7696         },
7697
7698         /**
7699          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7700          * @param {String} left The left CSS property value
7701          * @return {Roo.Element} this
7702          */
7703         setLeft : function(left){
7704             this.setStyle("left", this.addUnits(left));
7705             return this;
7706         },
7707
7708         /**
7709          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7710          * @param {String} top The top CSS property value
7711          * @return {Roo.Element} this
7712          */
7713         setTop : function(top){
7714             this.setStyle("top", this.addUnits(top));
7715             return this;
7716         },
7717
7718         /**
7719          * Sets the element's CSS right style.
7720          * @param {String} right The right CSS property value
7721          * @return {Roo.Element} this
7722          */
7723         setRight : function(right){
7724             this.setStyle("right", this.addUnits(right));
7725             return this;
7726         },
7727
7728         /**
7729          * Sets the element's CSS bottom style.
7730          * @param {String} bottom The bottom CSS property value
7731          * @return {Roo.Element} this
7732          */
7733         setBottom : function(bottom){
7734             this.setStyle("bottom", this.addUnits(bottom));
7735             return this;
7736         },
7737
7738         /**
7739          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7740          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7741          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7742          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7743          * @return {Roo.Element} this
7744          */
7745         setXY : function(pos, animate){
7746             if(!animate || !A){
7747                 D.setXY(this.dom, pos);
7748             }else{
7749                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7750             }
7751             return this;
7752         },
7753
7754         /**
7755          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7756          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7757          * @param {Number} x X value for new position (coordinates are page-based)
7758          * @param {Number} y Y value for new position (coordinates are page-based)
7759          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7760          * @return {Roo.Element} this
7761          */
7762         setLocation : function(x, y, animate){
7763             this.setXY([x, y], this.preanim(arguments, 2));
7764             return this;
7765         },
7766
7767         /**
7768          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7769          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7770          * @param {Number} x X value for new position (coordinates are page-based)
7771          * @param {Number} y Y value for new position (coordinates are page-based)
7772          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7773          * @return {Roo.Element} this
7774          */
7775         moveTo : function(x, y, animate){
7776             this.setXY([x, y], this.preanim(arguments, 2));
7777             return this;
7778         },
7779
7780         /**
7781          * Returns the region of the given element.
7782          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7783          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7784          */
7785         getRegion : function(){
7786             return D.getRegion(this.dom);
7787         },
7788
7789         /**
7790          * Returns the offset height of the element
7791          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7792          * @return {Number} The element's height
7793          */
7794         getHeight : function(contentHeight){
7795             var h = this.dom.offsetHeight || 0;
7796             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7797         },
7798
7799         /**
7800          * Returns the offset width of the element
7801          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7802          * @return {Number} The element's width
7803          */
7804         getWidth : function(contentWidth){
7805             var w = this.dom.offsetWidth || 0;
7806             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7807         },
7808
7809         /**
7810          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7811          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7812          * if a height has not been set using CSS.
7813          * @return {Number}
7814          */
7815         getComputedHeight : function(){
7816             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7817             if(!h){
7818                 h = parseInt(this.getStyle('height'), 10) || 0;
7819                 if(!this.isBorderBox()){
7820                     h += this.getFrameWidth('tb');
7821                 }
7822             }
7823             return h;
7824         },
7825
7826         /**
7827          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7828          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7829          * if a width has not been set using CSS.
7830          * @return {Number}
7831          */
7832         getComputedWidth : function(){
7833             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7834             if(!w){
7835                 w = parseInt(this.getStyle('width'), 10) || 0;
7836                 if(!this.isBorderBox()){
7837                     w += this.getFrameWidth('lr');
7838                 }
7839             }
7840             return w;
7841         },
7842
7843         /**
7844          * Returns the size of the element.
7845          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7846          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7847          */
7848         getSize : function(contentSize){
7849             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7850         },
7851
7852         /**
7853          * Returns the width and height of the viewport.
7854          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7855          */
7856         getViewSize : function(){
7857             var d = this.dom, doc = document, aw = 0, ah = 0;
7858             if(d == doc || d == doc.body){
7859                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7860             }else{
7861                 return {
7862                     width : d.clientWidth,
7863                     height: d.clientHeight
7864                 };
7865             }
7866         },
7867
7868         /**
7869          * Returns the value of the "value" attribute
7870          * @param {Boolean} asNumber true to parse the value as a number
7871          * @return {String/Number}
7872          */
7873         getValue : function(asNumber){
7874             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7875         },
7876
7877         // private
7878         adjustWidth : function(width){
7879             if(typeof width == "number"){
7880                 if(this.autoBoxAdjust && !this.isBorderBox()){
7881                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7882                 }
7883                 if(width < 0){
7884                     width = 0;
7885                 }
7886             }
7887             return width;
7888         },
7889
7890         // private
7891         adjustHeight : function(height){
7892             if(typeof height == "number"){
7893                if(this.autoBoxAdjust && !this.isBorderBox()){
7894                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7895                }
7896                if(height < 0){
7897                    height = 0;
7898                }
7899             }
7900             return height;
7901         },
7902
7903         /**
7904          * Set the width of the element
7905          * @param {Number} width The new width
7906          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7907          * @return {Roo.Element} this
7908          */
7909         setWidth : function(width, animate){
7910             width = this.adjustWidth(width);
7911             if(!animate || !A){
7912                 this.dom.style.width = this.addUnits(width);
7913             }else{
7914                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7915             }
7916             return this;
7917         },
7918
7919         /**
7920          * Set the height of the element
7921          * @param {Number} height The new height
7922          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7923          * @return {Roo.Element} this
7924          */
7925          setHeight : function(height, animate){
7926             height = this.adjustHeight(height);
7927             if(!animate || !A){
7928                 this.dom.style.height = this.addUnits(height);
7929             }else{
7930                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7931             }
7932             return this;
7933         },
7934
7935         /**
7936          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7937          * @param {Number} width The new width
7938          * @param {Number} height The new height
7939          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7940          * @return {Roo.Element} this
7941          */
7942          setSize : function(width, height, animate){
7943             if(typeof width == "object"){ // in case of object from getSize()
7944                 height = width.height; width = width.width;
7945             }
7946             width = this.adjustWidth(width); height = this.adjustHeight(height);
7947             if(!animate || !A){
7948                 this.dom.style.width = this.addUnits(width);
7949                 this.dom.style.height = this.addUnits(height);
7950             }else{
7951                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7952             }
7953             return this;
7954         },
7955
7956         /**
7957          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7958          * @param {Number} x X value for new position (coordinates are page-based)
7959          * @param {Number} y Y value for new position (coordinates are page-based)
7960          * @param {Number} width The new width
7961          * @param {Number} height The new height
7962          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7963          * @return {Roo.Element} this
7964          */
7965         setBounds : function(x, y, width, height, animate){
7966             if(!animate || !A){
7967                 this.setSize(width, height);
7968                 this.setLocation(x, y);
7969             }else{
7970                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7971                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7972                               this.preanim(arguments, 4), 'motion');
7973             }
7974             return this;
7975         },
7976
7977         /**
7978          * 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.
7979          * @param {Roo.lib.Region} region The region to fill
7980          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7981          * @return {Roo.Element} this
7982          */
7983         setRegion : function(region, animate){
7984             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7985             return this;
7986         },
7987
7988         /**
7989          * Appends an event handler
7990          *
7991          * @param {String}   eventName     The type of event to append
7992          * @param {Function} fn        The method the event invokes
7993          * @param {Object} scope       (optional) The scope (this object) of the fn
7994          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7995          */
7996         addListener : function(eventName, fn, scope, options){
7997             if (this.dom) {
7998                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7999             }
8000         },
8001
8002         /**
8003          * Removes an event handler from this element
8004          * @param {String} eventName the type of event to remove
8005          * @param {Function} fn the method the event invokes
8006          * @return {Roo.Element} this
8007          */
8008         removeListener : function(eventName, fn){
8009             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8010             return this;
8011         },
8012
8013         /**
8014          * Removes all previous added listeners from this element
8015          * @return {Roo.Element} this
8016          */
8017         removeAllListeners : function(){
8018             E.purgeElement(this.dom);
8019             return this;
8020         },
8021
8022         relayEvent : function(eventName, observable){
8023             this.on(eventName, function(e){
8024                 observable.fireEvent(eventName, e);
8025             });
8026         },
8027
8028         /**
8029          * Set the opacity of the element
8030          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8031          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8032          * @return {Roo.Element} this
8033          */
8034          setOpacity : function(opacity, animate){
8035             if(!animate || !A){
8036                 var s = this.dom.style;
8037                 if(Roo.isIE){
8038                     s.zoom = 1;
8039                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8040                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8041                 }else{
8042                     s.opacity = opacity;
8043                 }
8044             }else{
8045                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8046             }
8047             return this;
8048         },
8049
8050         /**
8051          * Gets the left X coordinate
8052          * @param {Boolean} local True to get the local css position instead of page coordinate
8053          * @return {Number}
8054          */
8055         getLeft : function(local){
8056             if(!local){
8057                 return this.getX();
8058             }else{
8059                 return parseInt(this.getStyle("left"), 10) || 0;
8060             }
8061         },
8062
8063         /**
8064          * Gets the right X coordinate of the element (element X position + element width)
8065          * @param {Boolean} local True to get the local css position instead of page coordinate
8066          * @return {Number}
8067          */
8068         getRight : function(local){
8069             if(!local){
8070                 return this.getX() + this.getWidth();
8071             }else{
8072                 return (this.getLeft(true) + this.getWidth()) || 0;
8073             }
8074         },
8075
8076         /**
8077          * Gets the top Y coordinate
8078          * @param {Boolean} local True to get the local css position instead of page coordinate
8079          * @return {Number}
8080          */
8081         getTop : function(local) {
8082             if(!local){
8083                 return this.getY();
8084             }else{
8085                 return parseInt(this.getStyle("top"), 10) || 0;
8086             }
8087         },
8088
8089         /**
8090          * Gets the bottom Y coordinate of the element (element Y position + element height)
8091          * @param {Boolean} local True to get the local css position instead of page coordinate
8092          * @return {Number}
8093          */
8094         getBottom : function(local){
8095             if(!local){
8096                 return this.getY() + this.getHeight();
8097             }else{
8098                 return (this.getTop(true) + this.getHeight()) || 0;
8099             }
8100         },
8101
8102         /**
8103         * Initializes positioning on this element. If a desired position is not passed, it will make the
8104         * the element positioned relative IF it is not already positioned.
8105         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8106         * @param {Number} zIndex (optional) The zIndex to apply
8107         * @param {Number} x (optional) Set the page X position
8108         * @param {Number} y (optional) Set the page Y position
8109         */
8110         position : function(pos, zIndex, x, y){
8111             if(!pos){
8112                if(this.getStyle('position') == 'static'){
8113                    this.setStyle('position', 'relative');
8114                }
8115             }else{
8116                 this.setStyle("position", pos);
8117             }
8118             if(zIndex){
8119                 this.setStyle("z-index", zIndex);
8120             }
8121             if(x !== undefined && y !== undefined){
8122                 this.setXY([x, y]);
8123             }else if(x !== undefined){
8124                 this.setX(x);
8125             }else if(y !== undefined){
8126                 this.setY(y);
8127             }
8128         },
8129
8130         /**
8131         * Clear positioning back to the default when the document was loaded
8132         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8133         * @return {Roo.Element} this
8134          */
8135         clearPositioning : function(value){
8136             value = value ||'';
8137             this.setStyle({
8138                 "left": value,
8139                 "right": value,
8140                 "top": value,
8141                 "bottom": value,
8142                 "z-index": "",
8143                 "position" : "static"
8144             });
8145             return this;
8146         },
8147
8148         /**
8149         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8150         * snapshot before performing an update and then restoring the element.
8151         * @return {Object}
8152         */
8153         getPositioning : function(){
8154             var l = this.getStyle("left");
8155             var t = this.getStyle("top");
8156             return {
8157                 "position" : this.getStyle("position"),
8158                 "left" : l,
8159                 "right" : l ? "" : this.getStyle("right"),
8160                 "top" : t,
8161                 "bottom" : t ? "" : this.getStyle("bottom"),
8162                 "z-index" : this.getStyle("z-index")
8163             };
8164         },
8165
8166         /**
8167          * Gets the width of the border(s) for the specified side(s)
8168          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8169          * passing lr would get the border (l)eft width + the border (r)ight width.
8170          * @return {Number} The width of the sides passed added together
8171          */
8172         getBorderWidth : function(side){
8173             return this.addStyles(side, El.borders);
8174         },
8175
8176         /**
8177          * Gets the width of the padding(s) for the specified side(s)
8178          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8179          * passing lr would get the padding (l)eft + the padding (r)ight.
8180          * @return {Number} The padding of the sides passed added together
8181          */
8182         getPadding : function(side){
8183             return this.addStyles(side, El.paddings);
8184         },
8185
8186         /**
8187         * Set positioning with an object returned by getPositioning().
8188         * @param {Object} posCfg
8189         * @return {Roo.Element} this
8190          */
8191         setPositioning : function(pc){
8192             this.applyStyles(pc);
8193             if(pc.right == "auto"){
8194                 this.dom.style.right = "";
8195             }
8196             if(pc.bottom == "auto"){
8197                 this.dom.style.bottom = "";
8198             }
8199             return this;
8200         },
8201
8202         // private
8203         fixDisplay : function(){
8204             if(this.getStyle("display") == "none"){
8205                 this.setStyle("visibility", "hidden");
8206                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8207                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8208                     this.setStyle("display", "block");
8209                 }
8210             }
8211         },
8212
8213         /**
8214          * Quick set left and top adding default units
8215          * @param {String} left The left CSS property value
8216          * @param {String} top The top CSS property value
8217          * @return {Roo.Element} this
8218          */
8219          setLeftTop : function(left, top){
8220             this.dom.style.left = this.addUnits(left);
8221             this.dom.style.top = this.addUnits(top);
8222             return this;
8223         },
8224
8225         /**
8226          * Move this element relative to its current position.
8227          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8228          * @param {Number} distance How far to move the element in pixels
8229          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8230          * @return {Roo.Element} this
8231          */
8232          move : function(direction, distance, animate){
8233             var xy = this.getXY();
8234             direction = direction.toLowerCase();
8235             switch(direction){
8236                 case "l":
8237                 case "left":
8238                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8239                     break;
8240                case "r":
8241                case "right":
8242                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8243                     break;
8244                case "t":
8245                case "top":
8246                case "up":
8247                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8248                     break;
8249                case "b":
8250                case "bottom":
8251                case "down":
8252                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8253                     break;
8254             }
8255             return this;
8256         },
8257
8258         /**
8259          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8260          * @return {Roo.Element} this
8261          */
8262         clip : function(){
8263             if(!this.isClipped){
8264                this.isClipped = true;
8265                this.originalClip = {
8266                    "o": this.getStyle("overflow"),
8267                    "x": this.getStyle("overflow-x"),
8268                    "y": this.getStyle("overflow-y")
8269                };
8270                this.setStyle("overflow", "hidden");
8271                this.setStyle("overflow-x", "hidden");
8272                this.setStyle("overflow-y", "hidden");
8273             }
8274             return this;
8275         },
8276
8277         /**
8278          *  Return clipping (overflow) to original clipping before clip() was called
8279          * @return {Roo.Element} this
8280          */
8281         unclip : function(){
8282             if(this.isClipped){
8283                 this.isClipped = false;
8284                 var o = this.originalClip;
8285                 if(o.o){this.setStyle("overflow", o.o);}
8286                 if(o.x){this.setStyle("overflow-x", o.x);}
8287                 if(o.y){this.setStyle("overflow-y", o.y);}
8288             }
8289             return this;
8290         },
8291
8292
8293         /**
8294          * Gets the x,y coordinates specified by the anchor position on the element.
8295          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8296          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8297          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8298          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8299          * @return {Array} [x, y] An array containing the element's x and y coordinates
8300          */
8301         getAnchorXY : function(anchor, local, s){
8302             //Passing a different size is useful for pre-calculating anchors,
8303             //especially for anchored animations that change the el size.
8304
8305             var w, h, vp = false;
8306             if(!s){
8307                 var d = this.dom;
8308                 if(d == document.body || d == document){
8309                     vp = true;
8310                     w = D.getViewWidth(); h = D.getViewHeight();
8311                 }else{
8312                     w = this.getWidth(); h = this.getHeight();
8313                 }
8314             }else{
8315                 w = s.width;  h = s.height;
8316             }
8317             var x = 0, y = 0, r = Math.round;
8318             switch((anchor || "tl").toLowerCase()){
8319                 case "c":
8320                     x = r(w*.5);
8321                     y = r(h*.5);
8322                 break;
8323                 case "t":
8324                     x = r(w*.5);
8325                     y = 0;
8326                 break;
8327                 case "l":
8328                     x = 0;
8329                     y = r(h*.5);
8330                 break;
8331                 case "r":
8332                     x = w;
8333                     y = r(h*.5);
8334                 break;
8335                 case "b":
8336                     x = r(w*.5);
8337                     y = h;
8338                 break;
8339                 case "tl":
8340                     x = 0;
8341                     y = 0;
8342                 break;
8343                 case "bl":
8344                     x = 0;
8345                     y = h;
8346                 break;
8347                 case "br":
8348                     x = w;
8349                     y = h;
8350                 break;
8351                 case "tr":
8352                     x = w;
8353                     y = 0;
8354                 break;
8355             }
8356             if(local === true){
8357                 return [x, y];
8358             }
8359             if(vp){
8360                 var sc = this.getScroll();
8361                 return [x + sc.left, y + sc.top];
8362             }
8363             //Add the element's offset xy
8364             var o = this.getXY();
8365             return [x+o[0], y+o[1]];
8366         },
8367
8368         /**
8369          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8370          * supported position values.
8371          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8372          * @param {String} position The position to align to.
8373          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8374          * @return {Array} [x, y]
8375          */
8376         getAlignToXY : function(el, p, o){
8377             el = Roo.get(el);
8378             var d = this.dom;
8379             if(!el.dom){
8380                 throw "Element.alignTo with an element that doesn't exist";
8381             }
8382             var c = false; //constrain to viewport
8383             var p1 = "", p2 = "";
8384             o = o || [0,0];
8385
8386             if(!p){
8387                 p = "tl-bl";
8388             }else if(p == "?"){
8389                 p = "tl-bl?";
8390             }else if(p.indexOf("-") == -1){
8391                 p = "tl-" + p;
8392             }
8393             p = p.toLowerCase();
8394             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8395             if(!m){
8396                throw "Element.alignTo with an invalid alignment " + p;
8397             }
8398             p1 = m[1]; p2 = m[2]; c = !!m[3];
8399
8400             //Subtract the aligned el's internal xy from the target's offset xy
8401             //plus custom offset to get the aligned el's new offset xy
8402             var a1 = this.getAnchorXY(p1, true);
8403             var a2 = el.getAnchorXY(p2, false);
8404             var x = a2[0] - a1[0] + o[0];
8405             var y = a2[1] - a1[1] + o[1];
8406             if(c){
8407                 //constrain the aligned el to viewport if necessary
8408                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8409                 // 5px of margin for ie
8410                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8411
8412                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8413                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8414                 //otherwise swap the aligned el to the opposite border of the target.
8415                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8416                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8417                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8418                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8419
8420                var doc = document;
8421                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8422                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8423
8424                if((x+w) > dw + scrollX){
8425                     x = swapX ? r.left-w : dw+scrollX-w;
8426                 }
8427                if(x < scrollX){
8428                    x = swapX ? r.right : scrollX;
8429                }
8430                if((y+h) > dh + scrollY){
8431                     y = swapY ? r.top-h : dh+scrollY-h;
8432                 }
8433                if (y < scrollY){
8434                    y = swapY ? r.bottom : scrollY;
8435                }
8436             }
8437             return [x,y];
8438         },
8439
8440         // private
8441         getConstrainToXY : function(){
8442             var os = {top:0, left:0, bottom:0, right: 0};
8443
8444             return function(el, local, offsets, proposedXY){
8445                 el = Roo.get(el);
8446                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8447
8448                 var vw, vh, vx = 0, vy = 0;
8449                 if(el.dom == document.body || el.dom == document){
8450                     vw = Roo.lib.Dom.getViewWidth();
8451                     vh = Roo.lib.Dom.getViewHeight();
8452                 }else{
8453                     vw = el.dom.clientWidth;
8454                     vh = el.dom.clientHeight;
8455                     if(!local){
8456                         var vxy = el.getXY();
8457                         vx = vxy[0];
8458                         vy = vxy[1];
8459                     }
8460                 }
8461
8462                 var s = el.getScroll();
8463
8464                 vx += offsets.left + s.left;
8465                 vy += offsets.top + s.top;
8466
8467                 vw -= offsets.right;
8468                 vh -= offsets.bottom;
8469
8470                 var vr = vx+vw;
8471                 var vb = vy+vh;
8472
8473                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8474                 var x = xy[0], y = xy[1];
8475                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8476
8477                 // only move it if it needs it
8478                 var moved = false;
8479
8480                 // first validate right/bottom
8481                 if((x + w) > vr){
8482                     x = vr - w;
8483                     moved = true;
8484                 }
8485                 if((y + h) > vb){
8486                     y = vb - h;
8487                     moved = true;
8488                 }
8489                 // then make sure top/left isn't negative
8490                 if(x < vx){
8491                     x = vx;
8492                     moved = true;
8493                 }
8494                 if(y < vy){
8495                     y = vy;
8496                     moved = true;
8497                 }
8498                 return moved ? [x, y] : false;
8499             };
8500         }(),
8501
8502         // private
8503         adjustForConstraints : function(xy, parent, offsets){
8504             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8505         },
8506
8507         /**
8508          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8509          * document it aligns it to the viewport.
8510          * The position parameter is optional, and can be specified in any one of the following formats:
8511          * <ul>
8512          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8513          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8514          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8515          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8516          *   <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
8517          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8518          * </ul>
8519          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8520          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8521          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8522          * that specified in order to enforce the viewport constraints.
8523          * Following are all of the supported anchor positions:
8524     <pre>
8525     Value  Description
8526     -----  -----------------------------
8527     tl     The top left corner (default)
8528     t      The center of the top edge
8529     tr     The top right corner
8530     l      The center of the left edge
8531     c      In the center of the element
8532     r      The center of the right edge
8533     bl     The bottom left corner
8534     b      The center of the bottom edge
8535     br     The bottom right corner
8536     </pre>
8537     Example Usage:
8538     <pre><code>
8539     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8540     el.alignTo("other-el");
8541
8542     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8543     el.alignTo("other-el", "tr?");
8544
8545     // align the bottom right corner of el with the center left edge of other-el
8546     el.alignTo("other-el", "br-l?");
8547
8548     // align the center of el with the bottom left corner of other-el and
8549     // adjust the x position by -6 pixels (and the y position by 0)
8550     el.alignTo("other-el", "c-bl", [-6, 0]);
8551     </code></pre>
8552          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8553          * @param {String} position The position to align to.
8554          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8555          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8556          * @return {Roo.Element} this
8557          */
8558         alignTo : function(element, position, offsets, animate){
8559             var xy = this.getAlignToXY(element, position, offsets);
8560             this.setXY(xy, this.preanim(arguments, 3));
8561             return this;
8562         },
8563
8564         /**
8565          * Anchors an element to another element and realigns it when the window is resized.
8566          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8567          * @param {String} position The position to align to.
8568          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8569          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8570          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8571          * is a number, it is used as the buffer delay (defaults to 50ms).
8572          * @param {Function} callback The function to call after the animation finishes
8573          * @return {Roo.Element} this
8574          */
8575         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8576             var action = function(){
8577                 this.alignTo(el, alignment, offsets, animate);
8578                 Roo.callback(callback, this);
8579             };
8580             Roo.EventManager.onWindowResize(action, this);
8581             var tm = typeof monitorScroll;
8582             if(tm != 'undefined'){
8583                 Roo.EventManager.on(window, 'scroll', action, this,
8584                     {buffer: tm == 'number' ? monitorScroll : 50});
8585             }
8586             action.call(this); // align immediately
8587             return this;
8588         },
8589         /**
8590          * Clears any opacity settings from this element. Required in some cases for IE.
8591          * @return {Roo.Element} this
8592          */
8593         clearOpacity : function(){
8594             if (window.ActiveXObject) {
8595                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8596                     this.dom.style.filter = "";
8597                 }
8598             } else {
8599                 this.dom.style.opacity = "";
8600                 this.dom.style["-moz-opacity"] = "";
8601                 this.dom.style["-khtml-opacity"] = "";
8602             }
8603             return this;
8604         },
8605
8606         /**
8607          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8608          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8609          * @return {Roo.Element} this
8610          */
8611         hide : function(animate){
8612             this.setVisible(false, this.preanim(arguments, 0));
8613             return this;
8614         },
8615
8616         /**
8617         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8618         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8619          * @return {Roo.Element} this
8620          */
8621         show : function(animate){
8622             this.setVisible(true, this.preanim(arguments, 0));
8623             return this;
8624         },
8625
8626         /**
8627          * @private Test if size has a unit, otherwise appends the default
8628          */
8629         addUnits : function(size){
8630             return Roo.Element.addUnits(size, this.defaultUnit);
8631         },
8632
8633         /**
8634          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8635          * @return {Roo.Element} this
8636          */
8637         beginMeasure : function(){
8638             var el = this.dom;
8639             if(el.offsetWidth || el.offsetHeight){
8640                 return this; // offsets work already
8641             }
8642             var changed = [];
8643             var p = this.dom, b = document.body; // start with this element
8644             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8645                 var pe = Roo.get(p);
8646                 if(pe.getStyle('display') == 'none'){
8647                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8648                     p.style.visibility = "hidden";
8649                     p.style.display = "block";
8650                 }
8651                 p = p.parentNode;
8652             }
8653             this._measureChanged = changed;
8654             return this;
8655
8656         },
8657
8658         /**
8659          * Restores displays to before beginMeasure was called
8660          * @return {Roo.Element} this
8661          */
8662         endMeasure : function(){
8663             var changed = this._measureChanged;
8664             if(changed){
8665                 for(var i = 0, len = changed.length; i < len; i++) {
8666                     var r = changed[i];
8667                     r.el.style.visibility = r.visibility;
8668                     r.el.style.display = "none";
8669                 }
8670                 this._measureChanged = null;
8671             }
8672             return this;
8673         },
8674
8675         /**
8676         * Update the innerHTML of this element, optionally searching for and processing scripts
8677         * @param {String} html The new HTML
8678         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8679         * @param {Function} callback For async script loading you can be noticed when the update completes
8680         * @return {Roo.Element} this
8681          */
8682         update : function(html, loadScripts, callback){
8683             if(typeof html == "undefined"){
8684                 html = "";
8685             }
8686             if(loadScripts !== true){
8687                 this.dom.innerHTML = html;
8688                 if(typeof callback == "function"){
8689                     callback();
8690                 }
8691                 return this;
8692             }
8693             var id = Roo.id();
8694             var dom = this.dom;
8695
8696             html += '<span id="' + id + '"></span>';
8697
8698             E.onAvailable(id, function(){
8699                 var hd = document.getElementsByTagName("head")[0];
8700                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8701                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8702                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8703
8704                 var match;
8705                 while(match = re.exec(html)){
8706                     var attrs = match[1];
8707                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8708                     if(srcMatch && srcMatch[2]){
8709                        var s = document.createElement("script");
8710                        s.src = srcMatch[2];
8711                        var typeMatch = attrs.match(typeRe);
8712                        if(typeMatch && typeMatch[2]){
8713                            s.type = typeMatch[2];
8714                        }
8715                        hd.appendChild(s);
8716                     }else if(match[2] && match[2].length > 0){
8717                         if(window.execScript) {
8718                            window.execScript(match[2]);
8719                         } else {
8720                             /**
8721                              * eval:var:id
8722                              * eval:var:dom
8723                              * eval:var:html
8724                              * 
8725                              */
8726                            window.eval(match[2]);
8727                         }
8728                     }
8729                 }
8730                 var el = document.getElementById(id);
8731                 if(el){el.parentNode.removeChild(el);}
8732                 if(typeof callback == "function"){
8733                     callback();
8734                 }
8735             });
8736             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8737             return this;
8738         },
8739
8740         /**
8741          * Direct access to the UpdateManager update() method (takes the same parameters).
8742          * @param {String/Function} url The url for this request or a function to call to get the url
8743          * @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}
8744          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8745          * @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.
8746          * @return {Roo.Element} this
8747          */
8748         load : function(){
8749             var um = this.getUpdateManager();
8750             um.update.apply(um, arguments);
8751             return this;
8752         },
8753
8754         /**
8755         * Gets this element's UpdateManager
8756         * @return {Roo.UpdateManager} The UpdateManager
8757         */
8758         getUpdateManager : function(){
8759             if(!this.updateManager){
8760                 this.updateManager = new Roo.UpdateManager(this);
8761             }
8762             return this.updateManager;
8763         },
8764
8765         /**
8766          * Disables text selection for this element (normalized across browsers)
8767          * @return {Roo.Element} this
8768          */
8769         unselectable : function(){
8770             this.dom.unselectable = "on";
8771             this.swallowEvent("selectstart", true);
8772             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8773             this.addClass("x-unselectable");
8774             return this;
8775         },
8776
8777         /**
8778         * Calculates the x, y to center this element on the screen
8779         * @return {Array} The x, y values [x, y]
8780         */
8781         getCenterXY : function(){
8782             return this.getAlignToXY(document, 'c-c');
8783         },
8784
8785         /**
8786         * Centers the Element in either the viewport, or another Element.
8787         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8788         */
8789         center : function(centerIn){
8790             this.alignTo(centerIn || document, 'c-c');
8791             return this;
8792         },
8793
8794         /**
8795          * Tests various css rules/browsers to determine if this element uses a border box
8796          * @return {Boolean}
8797          */
8798         isBorderBox : function(){
8799             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8800         },
8801
8802         /**
8803          * Return a box {x, y, width, height} that can be used to set another elements
8804          * size/location to match this element.
8805          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8806          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8807          * @return {Object} box An object in the format {x, y, width, height}
8808          */
8809         getBox : function(contentBox, local){
8810             var xy;
8811             if(!local){
8812                 xy = this.getXY();
8813             }else{
8814                 var left = parseInt(this.getStyle("left"), 10) || 0;
8815                 var top = parseInt(this.getStyle("top"), 10) || 0;
8816                 xy = [left, top];
8817             }
8818             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8819             if(!contentBox){
8820                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8821             }else{
8822                 var l = this.getBorderWidth("l")+this.getPadding("l");
8823                 var r = this.getBorderWidth("r")+this.getPadding("r");
8824                 var t = this.getBorderWidth("t")+this.getPadding("t");
8825                 var b = this.getBorderWidth("b")+this.getPadding("b");
8826                 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)};
8827             }
8828             bx.right = bx.x + bx.width;
8829             bx.bottom = bx.y + bx.height;
8830             return bx;
8831         },
8832
8833         /**
8834          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8835          for more information about the sides.
8836          * @param {String} sides
8837          * @return {Number}
8838          */
8839         getFrameWidth : function(sides, onlyContentBox){
8840             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8841         },
8842
8843         /**
8844          * 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.
8845          * @param {Object} box The box to fill {x, y, width, height}
8846          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8847          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8848          * @return {Roo.Element} this
8849          */
8850         setBox : function(box, adjust, animate){
8851             var w = box.width, h = box.height;
8852             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8853                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8854                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8855             }
8856             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8857             return this;
8858         },
8859
8860         /**
8861          * Forces the browser to repaint this element
8862          * @return {Roo.Element} this
8863          */
8864          repaint : function(){
8865             var dom = this.dom;
8866             this.addClass("x-repaint");
8867             setTimeout(function(){
8868                 Roo.get(dom).removeClass("x-repaint");
8869             }, 1);
8870             return this;
8871         },
8872
8873         /**
8874          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8875          * then it returns the calculated width of the sides (see getPadding)
8876          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8877          * @return {Object/Number}
8878          */
8879         getMargins : function(side){
8880             if(!side){
8881                 return {
8882                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8883                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8884                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8885                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8886                 };
8887             }else{
8888                 return this.addStyles(side, El.margins);
8889              }
8890         },
8891
8892         // private
8893         addStyles : function(sides, styles){
8894             var val = 0, v, w;
8895             for(var i = 0, len = sides.length; i < len; i++){
8896                 v = this.getStyle(styles[sides.charAt(i)]);
8897                 if(v){
8898                      w = parseInt(v, 10);
8899                      if(w){ val += w; }
8900                 }
8901             }
8902             return val;
8903         },
8904
8905         /**
8906          * Creates a proxy element of this element
8907          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8908          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8909          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8910          * @return {Roo.Element} The new proxy element
8911          */
8912         createProxy : function(config, renderTo, matchBox){
8913             if(renderTo){
8914                 renderTo = Roo.getDom(renderTo);
8915             }else{
8916                 renderTo = document.body;
8917             }
8918             config = typeof config == "object" ?
8919                 config : {tag : "div", cls: config};
8920             var proxy = Roo.DomHelper.append(renderTo, config, true);
8921             if(matchBox){
8922                proxy.setBox(this.getBox());
8923             }
8924             return proxy;
8925         },
8926
8927         /**
8928          * Puts a mask over this element to disable user interaction. Requires core.css.
8929          * This method can only be applied to elements which accept child nodes.
8930          * @param {String} msg (optional) A message to display in the mask
8931          * @param {String} msgCls (optional) A css class to apply to the msg element
8932          * @return {Element} The mask  element
8933          */
8934         mask : function(msg, msgCls)
8935         {
8936             if(this.getStyle("position") == "static"){
8937                 this.setStyle("position", "relative");
8938             }
8939             if(!this._mask){
8940                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8941             }
8942             this.addClass("x-masked");
8943             this._mask.setDisplayed(true);
8944             
8945             // we wander
8946             var z = 0;
8947             var dom = this.dom
8948             while (dom && dom.style) {
8949                 if (!isNaN(parseInt(dom.style.zIndex))) {
8950                     z = Math.max(z, parseInt(dom.style.zIndex));
8951                 }
8952                 dom = dom.parentNode;
8953             }
8954             // if we are masking the body - then it hides everything..
8955             if (this.dom == document.body) {
8956                 z = 1000000;
8957                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8958                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8959             }
8960            
8961             if(typeof msg == 'string'){
8962                 if(!this._maskMsg){
8963                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8964                 }
8965                 var mm = this._maskMsg;
8966                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8967                 mm.dom.firstChild.innerHTML = msg;
8968                 mm.setDisplayed(true);
8969                 mm.center(this);
8970                 mm.setStyle('z-index', z + 102);
8971             }
8972             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8973                 this._mask.setHeight(this.getHeight());
8974             }
8975             this._mask.setStyle('z-index', z + 100);
8976             
8977             return this._mask;
8978         },
8979
8980         /**
8981          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8982          * it is cached for reuse.
8983          */
8984         unmask : function(removeEl){
8985             if(this._mask){
8986                 if(removeEl === true){
8987                     this._mask.remove();
8988                     delete this._mask;
8989                     if(this._maskMsg){
8990                         this._maskMsg.remove();
8991                         delete this._maskMsg;
8992                     }
8993                 }else{
8994                     this._mask.setDisplayed(false);
8995                     if(this._maskMsg){
8996                         this._maskMsg.setDisplayed(false);
8997                     }
8998                 }
8999             }
9000             this.removeClass("x-masked");
9001         },
9002
9003         /**
9004          * Returns true if this element is masked
9005          * @return {Boolean}
9006          */
9007         isMasked : function(){
9008             return this._mask && this._mask.isVisible();
9009         },
9010
9011         /**
9012          * Creates an iframe shim for this element to keep selects and other windowed objects from
9013          * showing through.
9014          * @return {Roo.Element} The new shim element
9015          */
9016         createShim : function(){
9017             var el = document.createElement('iframe');
9018             el.frameBorder = 'no';
9019             el.className = 'roo-shim';
9020             if(Roo.isIE && Roo.isSecure){
9021                 el.src = Roo.SSL_SECURE_URL;
9022             }
9023             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9024             shim.autoBoxAdjust = false;
9025             return shim;
9026         },
9027
9028         /**
9029          * Removes this element from the DOM and deletes it from the cache
9030          */
9031         remove : function(){
9032             if(this.dom.parentNode){
9033                 this.dom.parentNode.removeChild(this.dom);
9034             }
9035             delete El.cache[this.dom.id];
9036         },
9037
9038         /**
9039          * Sets up event handlers to add and remove a css class when the mouse is over this element
9040          * @param {String} className
9041          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9042          * mouseout events for children elements
9043          * @return {Roo.Element} this
9044          */
9045         addClassOnOver : function(className, preventFlicker){
9046             this.on("mouseover", function(){
9047                 Roo.fly(this, '_internal').addClass(className);
9048             }, this.dom);
9049             var removeFn = function(e){
9050                 if(preventFlicker !== true || !e.within(this, true)){
9051                     Roo.fly(this, '_internal').removeClass(className);
9052                 }
9053             };
9054             this.on("mouseout", removeFn, this.dom);
9055             return this;
9056         },
9057
9058         /**
9059          * Sets up event handlers to add and remove a css class when this element has the focus
9060          * @param {String} className
9061          * @return {Roo.Element} this
9062          */
9063         addClassOnFocus : function(className){
9064             this.on("focus", function(){
9065                 Roo.fly(this, '_internal').addClass(className);
9066             }, this.dom);
9067             this.on("blur", function(){
9068                 Roo.fly(this, '_internal').removeClass(className);
9069             }, this.dom);
9070             return this;
9071         },
9072         /**
9073          * 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)
9074          * @param {String} className
9075          * @return {Roo.Element} this
9076          */
9077         addClassOnClick : function(className){
9078             var dom = this.dom;
9079             this.on("mousedown", function(){
9080                 Roo.fly(dom, '_internal').addClass(className);
9081                 var d = Roo.get(document);
9082                 var fn = function(){
9083                     Roo.fly(dom, '_internal').removeClass(className);
9084                     d.removeListener("mouseup", fn);
9085                 };
9086                 d.on("mouseup", fn);
9087             });
9088             return this;
9089         },
9090
9091         /**
9092          * Stops the specified event from bubbling and optionally prevents the default action
9093          * @param {String} eventName
9094          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9095          * @return {Roo.Element} this
9096          */
9097         swallowEvent : function(eventName, preventDefault){
9098             var fn = function(e){
9099                 e.stopPropagation();
9100                 if(preventDefault){
9101                     e.preventDefault();
9102                 }
9103             };
9104             if(eventName instanceof Array){
9105                 for(var i = 0, len = eventName.length; i < len; i++){
9106                      this.on(eventName[i], fn);
9107                 }
9108                 return this;
9109             }
9110             this.on(eventName, fn);
9111             return this;
9112         },
9113
9114         /**
9115          * @private
9116          */
9117       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9118
9119         /**
9120          * Sizes this element to its parent element's dimensions performing
9121          * neccessary box adjustments.
9122          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9123          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9124          * @return {Roo.Element} this
9125          */
9126         fitToParent : function(monitorResize, targetParent) {
9127           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9128           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9129           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9130             return;
9131           }
9132           var p = Roo.get(targetParent || this.dom.parentNode);
9133           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9134           if (monitorResize === true) {
9135             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9136             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9137           }
9138           return this;
9139         },
9140
9141         /**
9142          * Gets the next sibling, skipping text nodes
9143          * @return {HTMLElement} The next sibling or null
9144          */
9145         getNextSibling : function(){
9146             var n = this.dom.nextSibling;
9147             while(n && n.nodeType != 1){
9148                 n = n.nextSibling;
9149             }
9150             return n;
9151         },
9152
9153         /**
9154          * Gets the previous sibling, skipping text nodes
9155          * @return {HTMLElement} The previous sibling or null
9156          */
9157         getPrevSibling : function(){
9158             var n = this.dom.previousSibling;
9159             while(n && n.nodeType != 1){
9160                 n = n.previousSibling;
9161             }
9162             return n;
9163         },
9164
9165
9166         /**
9167          * Appends the passed element(s) to this element
9168          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9169          * @return {Roo.Element} this
9170          */
9171         appendChild: function(el){
9172             el = Roo.get(el);
9173             el.appendTo(this);
9174             return this;
9175         },
9176
9177         /**
9178          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9179          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9180          * automatically generated with the specified attributes.
9181          * @param {HTMLElement} insertBefore (optional) a child element of this element
9182          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9183          * @return {Roo.Element} The new child element
9184          */
9185         createChild: function(config, insertBefore, returnDom){
9186             config = config || {tag:'div'};
9187             if(insertBefore){
9188                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9189             }
9190             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9191         },
9192
9193         /**
9194          * Appends this element to the passed element
9195          * @param {String/HTMLElement/Element} el The new parent element
9196          * @return {Roo.Element} this
9197          */
9198         appendTo: function(el){
9199             el = Roo.getDom(el);
9200             el.appendChild(this.dom);
9201             return this;
9202         },
9203
9204         /**
9205          * Inserts this element before the passed element in the DOM
9206          * @param {String/HTMLElement/Element} el The element to insert before
9207          * @return {Roo.Element} this
9208          */
9209         insertBefore: function(el){
9210             el = Roo.getDom(el);
9211             el.parentNode.insertBefore(this.dom, el);
9212             return this;
9213         },
9214
9215         /**
9216          * Inserts this element after the passed element in the DOM
9217          * @param {String/HTMLElement/Element} el The element to insert after
9218          * @return {Roo.Element} this
9219          */
9220         insertAfter: function(el){
9221             el = Roo.getDom(el);
9222             el.parentNode.insertBefore(this.dom, el.nextSibling);
9223             return this;
9224         },
9225
9226         /**
9227          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9228          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9229          * @return {Roo.Element} The new child
9230          */
9231         insertFirst: function(el, returnDom){
9232             el = el || {};
9233             if(typeof el == 'object' && !el.nodeType){ // dh config
9234                 return this.createChild(el, this.dom.firstChild, returnDom);
9235             }else{
9236                 el = Roo.getDom(el);
9237                 this.dom.insertBefore(el, this.dom.firstChild);
9238                 return !returnDom ? Roo.get(el) : el;
9239             }
9240         },
9241
9242         /**
9243          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9244          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9245          * @param {String} where (optional) 'before' or 'after' defaults to before
9246          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9247          * @return {Roo.Element} the inserted Element
9248          */
9249         insertSibling: function(el, where, returnDom){
9250             where = where ? where.toLowerCase() : 'before';
9251             el = el || {};
9252             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9253
9254             if(typeof el == 'object' && !el.nodeType){ // dh config
9255                 if(where == 'after' && !this.dom.nextSibling){
9256                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9257                 }else{
9258                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9259                 }
9260
9261             }else{
9262                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9263                             where == 'before' ? this.dom : this.dom.nextSibling);
9264                 if(!returnDom){
9265                     rt = Roo.get(rt);
9266                 }
9267             }
9268             return rt;
9269         },
9270
9271         /**
9272          * Creates and wraps this element with another element
9273          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9274          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9275          * @return {HTMLElement/Element} The newly created wrapper element
9276          */
9277         wrap: function(config, returnDom){
9278             if(!config){
9279                 config = {tag: "div"};
9280             }
9281             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9282             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9283             return newEl;
9284         },
9285
9286         /**
9287          * Replaces the passed element with this element
9288          * @param {String/HTMLElement/Element} el The element to replace
9289          * @return {Roo.Element} this
9290          */
9291         replace: function(el){
9292             el = Roo.get(el);
9293             this.insertBefore(el);
9294             el.remove();
9295             return this;
9296         },
9297
9298         /**
9299          * Inserts an html fragment into this element
9300          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9301          * @param {String} html The HTML fragment
9302          * @param {Boolean} returnEl True to return an Roo.Element
9303          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9304          */
9305         insertHtml : function(where, html, returnEl){
9306             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9307             return returnEl ? Roo.get(el) : el;
9308         },
9309
9310         /**
9311          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9312          * @param {Object} o The object with the attributes
9313          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9314          * @return {Roo.Element} this
9315          */
9316         set : function(o, useSet){
9317             var el = this.dom;
9318             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9319             for(var attr in o){
9320                 if(attr == "style" || typeof o[attr] == "function") continue;
9321                 if(attr=="cls"){
9322                     el.className = o["cls"];
9323                 }else{
9324                     if(useSet) el.setAttribute(attr, o[attr]);
9325                     else el[attr] = o[attr];
9326                 }
9327             }
9328             if(o.style){
9329                 Roo.DomHelper.applyStyles(el, o.style);
9330             }
9331             return this;
9332         },
9333
9334         /**
9335          * Convenience method for constructing a KeyMap
9336          * @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:
9337          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9338          * @param {Function} fn The function to call
9339          * @param {Object} scope (optional) The scope of the function
9340          * @return {Roo.KeyMap} The KeyMap created
9341          */
9342         addKeyListener : function(key, fn, scope){
9343             var config;
9344             if(typeof key != "object" || key instanceof Array){
9345                 config = {
9346                     key: key,
9347                     fn: fn,
9348                     scope: scope
9349                 };
9350             }else{
9351                 config = {
9352                     key : key.key,
9353                     shift : key.shift,
9354                     ctrl : key.ctrl,
9355                     alt : key.alt,
9356                     fn: fn,
9357                     scope: scope
9358                 };
9359             }
9360             return new Roo.KeyMap(this, config);
9361         },
9362
9363         /**
9364          * Creates a KeyMap for this element
9365          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9366          * @return {Roo.KeyMap} The KeyMap created
9367          */
9368         addKeyMap : function(config){
9369             return new Roo.KeyMap(this, config);
9370         },
9371
9372         /**
9373          * Returns true if this element is scrollable.
9374          * @return {Boolean}
9375          */
9376          isScrollable : function(){
9377             var dom = this.dom;
9378             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9379         },
9380
9381         /**
9382          * 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().
9383          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9384          * @param {Number} value The new scroll value
9385          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9386          * @return {Element} this
9387          */
9388
9389         scrollTo : function(side, value, animate){
9390             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9391             if(!animate || !A){
9392                 this.dom[prop] = value;
9393             }else{
9394                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9395                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9396             }
9397             return this;
9398         },
9399
9400         /**
9401          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9402          * within this element's scrollable range.
9403          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9404          * @param {Number} distance How far to scroll the element in pixels
9405          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9406          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9407          * was scrolled as far as it could go.
9408          */
9409          scroll : function(direction, distance, animate){
9410              if(!this.isScrollable()){
9411                  return;
9412              }
9413              var el = this.dom;
9414              var l = el.scrollLeft, t = el.scrollTop;
9415              var w = el.scrollWidth, h = el.scrollHeight;
9416              var cw = el.clientWidth, ch = el.clientHeight;
9417              direction = direction.toLowerCase();
9418              var scrolled = false;
9419              var a = this.preanim(arguments, 2);
9420              switch(direction){
9421                  case "l":
9422                  case "left":
9423                      if(w - l > cw){
9424                          var v = Math.min(l + distance, w-cw);
9425                          this.scrollTo("left", v, a);
9426                          scrolled = true;
9427                      }
9428                      break;
9429                 case "r":
9430                 case "right":
9431                      if(l > 0){
9432                          var v = Math.max(l - distance, 0);
9433                          this.scrollTo("left", v, a);
9434                          scrolled = true;
9435                      }
9436                      break;
9437                 case "t":
9438                 case "top":
9439                 case "up":
9440                      if(t > 0){
9441                          var v = Math.max(t - distance, 0);
9442                          this.scrollTo("top", v, a);
9443                          scrolled = true;
9444                      }
9445                      break;
9446                 case "b":
9447                 case "bottom":
9448                 case "down":
9449                      if(h - t > ch){
9450                          var v = Math.min(t + distance, h-ch);
9451                          this.scrollTo("top", v, a);
9452                          scrolled = true;
9453                      }
9454                      break;
9455              }
9456              return scrolled;
9457         },
9458
9459         /**
9460          * Translates the passed page coordinates into left/top css values for this element
9461          * @param {Number/Array} x The page x or an array containing [x, y]
9462          * @param {Number} y The page y
9463          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9464          */
9465         translatePoints : function(x, y){
9466             if(typeof x == 'object' || x instanceof Array){
9467                 y = x[1]; x = x[0];
9468             }
9469             var p = this.getStyle('position');
9470             var o = this.getXY();
9471
9472             var l = parseInt(this.getStyle('left'), 10);
9473             var t = parseInt(this.getStyle('top'), 10);
9474
9475             if(isNaN(l)){
9476                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9477             }
9478             if(isNaN(t)){
9479                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9480             }
9481
9482             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9483         },
9484
9485         /**
9486          * Returns the current scroll position of the element.
9487          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9488          */
9489         getScroll : function(){
9490             var d = this.dom, doc = document;
9491             if(d == doc || d == doc.body){
9492                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9493                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9494                 return {left: l, top: t};
9495             }else{
9496                 return {left: d.scrollLeft, top: d.scrollTop};
9497             }
9498         },
9499
9500         /**
9501          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9502          * are convert to standard 6 digit hex color.
9503          * @param {String} attr The css attribute
9504          * @param {String} defaultValue The default value to use when a valid color isn't found
9505          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9506          * YUI color anims.
9507          */
9508         getColor : function(attr, defaultValue, prefix){
9509             var v = this.getStyle(attr);
9510             if(!v || v == "transparent" || v == "inherit") {
9511                 return defaultValue;
9512             }
9513             var color = typeof prefix == "undefined" ? "#" : prefix;
9514             if(v.substr(0, 4) == "rgb("){
9515                 var rvs = v.slice(4, v.length -1).split(",");
9516                 for(var i = 0; i < 3; i++){
9517                     var h = parseInt(rvs[i]).toString(16);
9518                     if(h < 16){
9519                         h = "0" + h;
9520                     }
9521                     color += h;
9522                 }
9523             } else {
9524                 if(v.substr(0, 1) == "#"){
9525                     if(v.length == 4) {
9526                         for(var i = 1; i < 4; i++){
9527                             var c = v.charAt(i);
9528                             color +=  c + c;
9529                         }
9530                     }else if(v.length == 7){
9531                         color += v.substr(1);
9532                     }
9533                 }
9534             }
9535             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9536         },
9537
9538         /**
9539          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9540          * gradient background, rounded corners and a 4-way shadow.
9541          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9542          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9543          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9544          * @return {Roo.Element} this
9545          */
9546         boxWrap : function(cls){
9547             cls = cls || 'x-box';
9548             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9549             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9550             return el;
9551         },
9552
9553         /**
9554          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9555          * @param {String} namespace The namespace in which to look for the attribute
9556          * @param {String} name The attribute name
9557          * @return {String} The attribute value
9558          */
9559         getAttributeNS : Roo.isIE ? function(ns, name){
9560             var d = this.dom;
9561             var type = typeof d[ns+":"+name];
9562             if(type != 'undefined' && type != 'unknown'){
9563                 return d[ns+":"+name];
9564             }
9565             return d[name];
9566         } : function(ns, name){
9567             var d = this.dom;
9568             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9569         },
9570         
9571         
9572         /**
9573          * Sets or Returns the value the dom attribute value
9574          * @param {String} name The attribute name
9575          * @param {String} value (optional) The value to set the attribute to
9576          * @return {String} The attribute value
9577          */
9578         attr : function(name){
9579             if (arguments.length > 1) {
9580                 this.dom.setAttribute(name, arguments[1]);
9581                 return arguments[1];
9582             }
9583             if (!this.dom.hasAttribute(name)) {
9584                 return undefined;
9585             }
9586             return this.dom.getAttribute(name);
9587         }
9588         
9589         
9590         
9591     };
9592
9593     var ep = El.prototype;
9594
9595     /**
9596      * Appends an event handler (Shorthand for addListener)
9597      * @param {String}   eventName     The type of event to append
9598      * @param {Function} fn        The method the event invokes
9599      * @param {Object} scope       (optional) The scope (this object) of the fn
9600      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9601      * @method
9602      */
9603     ep.on = ep.addListener;
9604         // backwards compat
9605     ep.mon = ep.addListener;
9606
9607     /**
9608      * Removes an event handler from this element (shorthand for removeListener)
9609      * @param {String} eventName the type of event to remove
9610      * @param {Function} fn the method the event invokes
9611      * @return {Roo.Element} this
9612      * @method
9613      */
9614     ep.un = ep.removeListener;
9615
9616     /**
9617      * true to automatically adjust width and height settings for box-model issues (default to true)
9618      */
9619     ep.autoBoxAdjust = true;
9620
9621     // private
9622     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9623
9624     // private
9625     El.addUnits = function(v, defaultUnit){
9626         if(v === "" || v == "auto"){
9627             return v;
9628         }
9629         if(v === undefined){
9630             return '';
9631         }
9632         if(typeof v == "number" || !El.unitPattern.test(v)){
9633             return v + (defaultUnit || 'px');
9634         }
9635         return v;
9636     };
9637
9638     // special markup used throughout Roo when box wrapping elements
9639     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>';
9640     /**
9641      * Visibility mode constant - Use visibility to hide element
9642      * @static
9643      * @type Number
9644      */
9645     El.VISIBILITY = 1;
9646     /**
9647      * Visibility mode constant - Use display to hide element
9648      * @static
9649      * @type Number
9650      */
9651     El.DISPLAY = 2;
9652
9653     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9654     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9655     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9656
9657
9658
9659     /**
9660      * @private
9661      */
9662     El.cache = {};
9663
9664     var docEl;
9665
9666     /**
9667      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9668      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9669      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9670      * @return {Element} The Element object
9671      * @static
9672      */
9673     El.get = function(el){
9674         var ex, elm, id;
9675         if(!el){ return null; }
9676         if(typeof el == "string"){ // element id
9677             if(!(elm = document.getElementById(el))){
9678                 return null;
9679             }
9680             if(ex = El.cache[el]){
9681                 ex.dom = elm;
9682             }else{
9683                 ex = El.cache[el] = new El(elm);
9684             }
9685             return ex;
9686         }else if(el.tagName){ // dom element
9687             if(!(id = el.id)){
9688                 id = Roo.id(el);
9689             }
9690             if(ex = El.cache[id]){
9691                 ex.dom = el;
9692             }else{
9693                 ex = El.cache[id] = new El(el);
9694             }
9695             return ex;
9696         }else if(el instanceof El){
9697             if(el != docEl){
9698                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9699                                                               // catch case where it hasn't been appended
9700                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9701             }
9702             return el;
9703         }else if(el.isComposite){
9704             return el;
9705         }else if(el instanceof Array){
9706             return El.select(el);
9707         }else if(el == document){
9708             // create a bogus element object representing the document object
9709             if(!docEl){
9710                 var f = function(){};
9711                 f.prototype = El.prototype;
9712                 docEl = new f();
9713                 docEl.dom = document;
9714             }
9715             return docEl;
9716         }
9717         return null;
9718     };
9719
9720     // private
9721     El.uncache = function(el){
9722         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9723             if(a[i]){
9724                 delete El.cache[a[i].id || a[i]];
9725             }
9726         }
9727     };
9728
9729     // private
9730     // Garbage collection - uncache elements/purge listeners on orphaned elements
9731     // so we don't hold a reference and cause the browser to retain them
9732     El.garbageCollect = function(){
9733         if(!Roo.enableGarbageCollector){
9734             clearInterval(El.collectorThread);
9735             return;
9736         }
9737         for(var eid in El.cache){
9738             var el = El.cache[eid], d = el.dom;
9739             // -------------------------------------------------------
9740             // Determining what is garbage:
9741             // -------------------------------------------------------
9742             // !d
9743             // dom node is null, definitely garbage
9744             // -------------------------------------------------------
9745             // !d.parentNode
9746             // no parentNode == direct orphan, definitely garbage
9747             // -------------------------------------------------------
9748             // !d.offsetParent && !document.getElementById(eid)
9749             // display none elements have no offsetParent so we will
9750             // also try to look it up by it's id. However, check
9751             // offsetParent first so we don't do unneeded lookups.
9752             // This enables collection of elements that are not orphans
9753             // directly, but somewhere up the line they have an orphan
9754             // parent.
9755             // -------------------------------------------------------
9756             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9757                 delete El.cache[eid];
9758                 if(d && Roo.enableListenerCollection){
9759                     E.purgeElement(d);
9760                 }
9761             }
9762         }
9763     }
9764     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9765
9766
9767     // dom is optional
9768     El.Flyweight = function(dom){
9769         this.dom = dom;
9770     };
9771     El.Flyweight.prototype = El.prototype;
9772
9773     El._flyweights = {};
9774     /**
9775      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9776      * the dom node can be overwritten by other code.
9777      * @param {String/HTMLElement} el The dom node or id
9778      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9779      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9780      * @static
9781      * @return {Element} The shared Element object
9782      */
9783     El.fly = function(el, named){
9784         named = named || '_global';
9785         el = Roo.getDom(el);
9786         if(!el){
9787             return null;
9788         }
9789         if(!El._flyweights[named]){
9790             El._flyweights[named] = new El.Flyweight();
9791         }
9792         El._flyweights[named].dom = el;
9793         return El._flyweights[named];
9794     };
9795
9796     /**
9797      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9798      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9799      * Shorthand of {@link Roo.Element#get}
9800      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9801      * @return {Element} The Element object
9802      * @member Roo
9803      * @method get
9804      */
9805     Roo.get = El.get;
9806     /**
9807      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9808      * the dom node can be overwritten by other code.
9809      * Shorthand of {@link Roo.Element#fly}
9810      * @param {String/HTMLElement} el The dom node or id
9811      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9812      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9813      * @static
9814      * @return {Element} The shared Element object
9815      * @member Roo
9816      * @method fly
9817      */
9818     Roo.fly = El.fly;
9819
9820     // speedy lookup for elements never to box adjust
9821     var noBoxAdjust = Roo.isStrict ? {
9822         select:1
9823     } : {
9824         input:1, select:1, textarea:1
9825     };
9826     if(Roo.isIE || Roo.isGecko){
9827         noBoxAdjust['button'] = 1;
9828     }
9829
9830
9831     Roo.EventManager.on(window, 'unload', function(){
9832         delete El.cache;
9833         delete El._flyweights;
9834     });
9835 })();
9836
9837
9838
9839
9840 if(Roo.DomQuery){
9841     Roo.Element.selectorFunction = Roo.DomQuery.select;
9842 }
9843
9844 Roo.Element.select = function(selector, unique, root){
9845     var els;
9846     if(typeof selector == "string"){
9847         els = Roo.Element.selectorFunction(selector, root);
9848     }else if(selector.length !== undefined){
9849         els = selector;
9850     }else{
9851         throw "Invalid selector";
9852     }
9853     if(unique === true){
9854         return new Roo.CompositeElement(els);
9855     }else{
9856         return new Roo.CompositeElementLite(els);
9857     }
9858 };
9859 /**
9860  * Selects elements based on the passed CSS selector to enable working on them as 1.
9861  * @param {String/Array} selector The CSS selector or an array of elements
9862  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9863  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9864  * @return {CompositeElementLite/CompositeElement}
9865  * @member Roo
9866  * @method select
9867  */
9868 Roo.select = Roo.Element.select;
9869
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883 /*
9884  * Based on:
9885  * Ext JS Library 1.1.1
9886  * Copyright(c) 2006-2007, Ext JS, LLC.
9887  *
9888  * Originally Released Under LGPL - original licence link has changed is not relivant.
9889  *
9890  * Fork - LGPL
9891  * <script type="text/javascript">
9892  */
9893
9894
9895
9896 //Notifies Element that fx methods are available
9897 Roo.enableFx = true;
9898
9899 /**
9900  * @class Roo.Fx
9901  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9902  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9903  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9904  * Element effects to work.</p><br/>
9905  *
9906  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9907  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9908  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9909  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9910  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9911  * expected results and should be done with care.</p><br/>
9912  *
9913  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9914  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9915 <pre>
9916 Value  Description
9917 -----  -----------------------------
9918 tl     The top left corner
9919 t      The center of the top edge
9920 tr     The top right corner
9921 l      The center of the left edge
9922 r      The center of the right edge
9923 bl     The bottom left corner
9924 b      The center of the bottom edge
9925 br     The bottom right corner
9926 </pre>
9927  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9928  * below are common options that can be passed to any Fx method.</b>
9929  * @cfg {Function} callback A function called when the effect is finished
9930  * @cfg {Object} scope The scope of the effect function
9931  * @cfg {String} easing A valid Easing value for the effect
9932  * @cfg {String} afterCls A css class to apply after the effect
9933  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9934  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9935  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9936  * effects that end with the element being visually hidden, ignored otherwise)
9937  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9938  * a function which returns such a specification that will be applied to the Element after the effect finishes
9939  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9940  * @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
9941  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9942  */
9943 Roo.Fx = {
9944         /**
9945          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9946          * origin for the slide effect.  This function automatically handles wrapping the element with
9947          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9948          * Usage:
9949          *<pre><code>
9950 // default: slide the element in from the top
9951 el.slideIn();
9952
9953 // custom: slide the element in from the right with a 2-second duration
9954 el.slideIn('r', { duration: 2 });
9955
9956 // common config options shown with default values
9957 el.slideIn('t', {
9958     easing: 'easeOut',
9959     duration: .5
9960 });
9961 </code></pre>
9962          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9963          * @param {Object} options (optional) Object literal with any of the Fx config options
9964          * @return {Roo.Element} The Element
9965          */
9966     slideIn : function(anchor, o){
9967         var el = this.getFxEl();
9968         o = o || {};
9969
9970         el.queueFx(o, function(){
9971
9972             anchor = anchor || "t";
9973
9974             // fix display to visibility
9975             this.fixDisplay();
9976
9977             // restore values after effect
9978             var r = this.getFxRestore();
9979             var b = this.getBox();
9980             // fixed size for slide
9981             this.setSize(b);
9982
9983             // wrap if needed
9984             var wrap = this.fxWrap(r.pos, o, "hidden");
9985
9986             var st = this.dom.style;
9987             st.visibility = "visible";
9988             st.position = "absolute";
9989
9990             // clear out temp styles after slide and unwrap
9991             var after = function(){
9992                 el.fxUnwrap(wrap, r.pos, o);
9993                 st.width = r.width;
9994                 st.height = r.height;
9995                 el.afterFx(o);
9996             };
9997             // time to calc the positions
9998             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9999
10000             switch(anchor.toLowerCase()){
10001                 case "t":
10002                     wrap.setSize(b.width, 0);
10003                     st.left = st.bottom = "0";
10004                     a = {height: bh};
10005                 break;
10006                 case "l":
10007                     wrap.setSize(0, b.height);
10008                     st.right = st.top = "0";
10009                     a = {width: bw};
10010                 break;
10011                 case "r":
10012                     wrap.setSize(0, b.height);
10013                     wrap.setX(b.right);
10014                     st.left = st.top = "0";
10015                     a = {width: bw, points: pt};
10016                 break;
10017                 case "b":
10018                     wrap.setSize(b.width, 0);
10019                     wrap.setY(b.bottom);
10020                     st.left = st.top = "0";
10021                     a = {height: bh, points: pt};
10022                 break;
10023                 case "tl":
10024                     wrap.setSize(0, 0);
10025                     st.right = st.bottom = "0";
10026                     a = {width: bw, height: bh};
10027                 break;
10028                 case "bl":
10029                     wrap.setSize(0, 0);
10030                     wrap.setY(b.y+b.height);
10031                     st.right = st.top = "0";
10032                     a = {width: bw, height: bh, points: pt};
10033                 break;
10034                 case "br":
10035                     wrap.setSize(0, 0);
10036                     wrap.setXY([b.right, b.bottom]);
10037                     st.left = st.top = "0";
10038                     a = {width: bw, height: bh, points: pt};
10039                 break;
10040                 case "tr":
10041                     wrap.setSize(0, 0);
10042                     wrap.setX(b.x+b.width);
10043                     st.left = st.bottom = "0";
10044                     a = {width: bw, height: bh, points: pt};
10045                 break;
10046             }
10047             this.dom.style.visibility = "visible";
10048             wrap.show();
10049
10050             arguments.callee.anim = wrap.fxanim(a,
10051                 o,
10052                 'motion',
10053                 .5,
10054                 'easeOut', after);
10055         });
10056         return this;
10057     },
10058     
10059         /**
10060          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10061          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10062          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10063          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10064          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10065          * Usage:
10066          *<pre><code>
10067 // default: slide the element out to the top
10068 el.slideOut();
10069
10070 // custom: slide the element out to the right with a 2-second duration
10071 el.slideOut('r', { duration: 2 });
10072
10073 // common config options shown with default values
10074 el.slideOut('t', {
10075     easing: 'easeOut',
10076     duration: .5,
10077     remove: false,
10078     useDisplay: false
10079 });
10080 </code></pre>
10081          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10082          * @param {Object} options (optional) Object literal with any of the Fx config options
10083          * @return {Roo.Element} The Element
10084          */
10085     slideOut : function(anchor, o){
10086         var el = this.getFxEl();
10087         o = o || {};
10088
10089         el.queueFx(o, function(){
10090
10091             anchor = anchor || "t";
10092
10093             // restore values after effect
10094             var r = this.getFxRestore();
10095             
10096             var b = this.getBox();
10097             // fixed size for slide
10098             this.setSize(b);
10099
10100             // wrap if needed
10101             var wrap = this.fxWrap(r.pos, o, "visible");
10102
10103             var st = this.dom.style;
10104             st.visibility = "visible";
10105             st.position = "absolute";
10106
10107             wrap.setSize(b);
10108
10109             var after = function(){
10110                 if(o.useDisplay){
10111                     el.setDisplayed(false);
10112                 }else{
10113                     el.hide();
10114                 }
10115
10116                 el.fxUnwrap(wrap, r.pos, o);
10117
10118                 st.width = r.width;
10119                 st.height = r.height;
10120
10121                 el.afterFx(o);
10122             };
10123
10124             var a, zero = {to: 0};
10125             switch(anchor.toLowerCase()){
10126                 case "t":
10127                     st.left = st.bottom = "0";
10128                     a = {height: zero};
10129                 break;
10130                 case "l":
10131                     st.right = st.top = "0";
10132                     a = {width: zero};
10133                 break;
10134                 case "r":
10135                     st.left = st.top = "0";
10136                     a = {width: zero, points: {to:[b.right, b.y]}};
10137                 break;
10138                 case "b":
10139                     st.left = st.top = "0";
10140                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10141                 break;
10142                 case "tl":
10143                     st.right = st.bottom = "0";
10144                     a = {width: zero, height: zero};
10145                 break;
10146                 case "bl":
10147                     st.right = st.top = "0";
10148                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10149                 break;
10150                 case "br":
10151                     st.left = st.top = "0";
10152                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10153                 break;
10154                 case "tr":
10155                     st.left = st.bottom = "0";
10156                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10157                 break;
10158             }
10159
10160             arguments.callee.anim = wrap.fxanim(a,
10161                 o,
10162                 'motion',
10163                 .5,
10164                 "easeOut", after);
10165         });
10166         return this;
10167     },
10168
10169         /**
10170          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10171          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10172          * The element must be removed from the DOM using the 'remove' config option if desired.
10173          * Usage:
10174          *<pre><code>
10175 // default
10176 el.puff();
10177
10178 // common config options shown with default values
10179 el.puff({
10180     easing: 'easeOut',
10181     duration: .5,
10182     remove: false,
10183     useDisplay: false
10184 });
10185 </code></pre>
10186          * @param {Object} options (optional) Object literal with any of the Fx config options
10187          * @return {Roo.Element} The Element
10188          */
10189     puff : function(o){
10190         var el = this.getFxEl();
10191         o = o || {};
10192
10193         el.queueFx(o, function(){
10194             this.clearOpacity();
10195             this.show();
10196
10197             // restore values after effect
10198             var r = this.getFxRestore();
10199             var st = this.dom.style;
10200
10201             var after = function(){
10202                 if(o.useDisplay){
10203                     el.setDisplayed(false);
10204                 }else{
10205                     el.hide();
10206                 }
10207
10208                 el.clearOpacity();
10209
10210                 el.setPositioning(r.pos);
10211                 st.width = r.width;
10212                 st.height = r.height;
10213                 st.fontSize = '';
10214                 el.afterFx(o);
10215             };
10216
10217             var width = this.getWidth();
10218             var height = this.getHeight();
10219
10220             arguments.callee.anim = this.fxanim({
10221                     width : {to: this.adjustWidth(width * 2)},
10222                     height : {to: this.adjustHeight(height * 2)},
10223                     points : {by: [-(width * .5), -(height * .5)]},
10224                     opacity : {to: 0},
10225                     fontSize: {to:200, unit: "%"}
10226                 },
10227                 o,
10228                 'motion',
10229                 .5,
10230                 "easeOut", after);
10231         });
10232         return this;
10233     },
10234
10235         /**
10236          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10237          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10238          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10239          * Usage:
10240          *<pre><code>
10241 // default
10242 el.switchOff();
10243
10244 // all config options shown with default values
10245 el.switchOff({
10246     easing: 'easeIn',
10247     duration: .3,
10248     remove: false,
10249     useDisplay: false
10250 });
10251 </code></pre>
10252          * @param {Object} options (optional) Object literal with any of the Fx config options
10253          * @return {Roo.Element} The Element
10254          */
10255     switchOff : function(o){
10256         var el = this.getFxEl();
10257         o = o || {};
10258
10259         el.queueFx(o, function(){
10260             this.clearOpacity();
10261             this.clip();
10262
10263             // restore values after effect
10264             var r = this.getFxRestore();
10265             var st = this.dom.style;
10266
10267             var after = function(){
10268                 if(o.useDisplay){
10269                     el.setDisplayed(false);
10270                 }else{
10271                     el.hide();
10272                 }
10273
10274                 el.clearOpacity();
10275                 el.setPositioning(r.pos);
10276                 st.width = r.width;
10277                 st.height = r.height;
10278
10279                 el.afterFx(o);
10280             };
10281
10282             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10283                 this.clearOpacity();
10284                 (function(){
10285                     this.fxanim({
10286                         height:{to:1},
10287                         points:{by:[0, this.getHeight() * .5]}
10288                     }, o, 'motion', 0.3, 'easeIn', after);
10289                 }).defer(100, this);
10290             });
10291         });
10292         return this;
10293     },
10294
10295     /**
10296      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10297      * changed using the "attr" config option) and then fading back to the original color. If no original
10298      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10299      * Usage:
10300 <pre><code>
10301 // default: highlight background to yellow
10302 el.highlight();
10303
10304 // custom: highlight foreground text to blue for 2 seconds
10305 el.highlight("0000ff", { attr: 'color', duration: 2 });
10306
10307 // common config options shown with default values
10308 el.highlight("ffff9c", {
10309     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10310     endColor: (current color) or "ffffff",
10311     easing: 'easeIn',
10312     duration: 1
10313 });
10314 </code></pre>
10315      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10316      * @param {Object} options (optional) Object literal with any of the Fx config options
10317      * @return {Roo.Element} The Element
10318      */ 
10319     highlight : function(color, o){
10320         var el = this.getFxEl();
10321         o = o || {};
10322
10323         el.queueFx(o, function(){
10324             color = color || "ffff9c";
10325             attr = o.attr || "backgroundColor";
10326
10327             this.clearOpacity();
10328             this.show();
10329
10330             var origColor = this.getColor(attr);
10331             var restoreColor = this.dom.style[attr];
10332             endColor = (o.endColor || origColor) || "ffffff";
10333
10334             var after = function(){
10335                 el.dom.style[attr] = restoreColor;
10336                 el.afterFx(o);
10337             };
10338
10339             var a = {};
10340             a[attr] = {from: color, to: endColor};
10341             arguments.callee.anim = this.fxanim(a,
10342                 o,
10343                 'color',
10344                 1,
10345                 'easeIn', after);
10346         });
10347         return this;
10348     },
10349
10350    /**
10351     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10352     * Usage:
10353 <pre><code>
10354 // default: a single light blue ripple
10355 el.frame();
10356
10357 // custom: 3 red ripples lasting 3 seconds total
10358 el.frame("ff0000", 3, { duration: 3 });
10359
10360 // common config options shown with default values
10361 el.frame("C3DAF9", 1, {
10362     duration: 1 //duration of entire animation (not each individual ripple)
10363     // Note: Easing is not configurable and will be ignored if included
10364 });
10365 </code></pre>
10366     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10367     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10368     * @param {Object} options (optional) Object literal with any of the Fx config options
10369     * @return {Roo.Element} The Element
10370     */
10371     frame : function(color, count, o){
10372         var el = this.getFxEl();
10373         o = o || {};
10374
10375         el.queueFx(o, function(){
10376             color = color || "#C3DAF9";
10377             if(color.length == 6){
10378                 color = "#" + color;
10379             }
10380             count = count || 1;
10381             duration = o.duration || 1;
10382             this.show();
10383
10384             var b = this.getBox();
10385             var animFn = function(){
10386                 var proxy = this.createProxy({
10387
10388                      style:{
10389                         visbility:"hidden",
10390                         position:"absolute",
10391                         "z-index":"35000", // yee haw
10392                         border:"0px solid " + color
10393                      }
10394                   });
10395                 var scale = Roo.isBorderBox ? 2 : 1;
10396                 proxy.animate({
10397                     top:{from:b.y, to:b.y - 20},
10398                     left:{from:b.x, to:b.x - 20},
10399                     borderWidth:{from:0, to:10},
10400                     opacity:{from:1, to:0},
10401                     height:{from:b.height, to:(b.height + (20*scale))},
10402                     width:{from:b.width, to:(b.width + (20*scale))}
10403                 }, duration, function(){
10404                     proxy.remove();
10405                 });
10406                 if(--count > 0){
10407                      animFn.defer((duration/2)*1000, this);
10408                 }else{
10409                     el.afterFx(o);
10410                 }
10411             };
10412             animFn.call(this);
10413         });
10414         return this;
10415     },
10416
10417    /**
10418     * Creates a pause before any subsequent queued effects begin.  If there are
10419     * no effects queued after the pause it will have no effect.
10420     * Usage:
10421 <pre><code>
10422 el.pause(1);
10423 </code></pre>
10424     * @param {Number} seconds The length of time to pause (in seconds)
10425     * @return {Roo.Element} The Element
10426     */
10427     pause : function(seconds){
10428         var el = this.getFxEl();
10429         var o = {};
10430
10431         el.queueFx(o, function(){
10432             setTimeout(function(){
10433                 el.afterFx(o);
10434             }, seconds * 1000);
10435         });
10436         return this;
10437     },
10438
10439    /**
10440     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10441     * using the "endOpacity" config option.
10442     * Usage:
10443 <pre><code>
10444 // default: fade in from opacity 0 to 100%
10445 el.fadeIn();
10446
10447 // custom: fade in from opacity 0 to 75% over 2 seconds
10448 el.fadeIn({ endOpacity: .75, duration: 2});
10449
10450 // common config options shown with default values
10451 el.fadeIn({
10452     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10453     easing: 'easeOut',
10454     duration: .5
10455 });
10456 </code></pre>
10457     * @param {Object} options (optional) Object literal with any of the Fx config options
10458     * @return {Roo.Element} The Element
10459     */
10460     fadeIn : function(o){
10461         var el = this.getFxEl();
10462         o = o || {};
10463         el.queueFx(o, function(){
10464             this.setOpacity(0);
10465             this.fixDisplay();
10466             this.dom.style.visibility = 'visible';
10467             var to = o.endOpacity || 1;
10468             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10469                 o, null, .5, "easeOut", function(){
10470                 if(to == 1){
10471                     this.clearOpacity();
10472                 }
10473                 el.afterFx(o);
10474             });
10475         });
10476         return this;
10477     },
10478
10479    /**
10480     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10481     * using the "endOpacity" config option.
10482     * Usage:
10483 <pre><code>
10484 // default: fade out from the element's current opacity to 0
10485 el.fadeOut();
10486
10487 // custom: fade out from the element's current opacity to 25% over 2 seconds
10488 el.fadeOut({ endOpacity: .25, duration: 2});
10489
10490 // common config options shown with default values
10491 el.fadeOut({
10492     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10493     easing: 'easeOut',
10494     duration: .5
10495     remove: false,
10496     useDisplay: false
10497 });
10498 </code></pre>
10499     * @param {Object} options (optional) Object literal with any of the Fx config options
10500     * @return {Roo.Element} The Element
10501     */
10502     fadeOut : function(o){
10503         var el = this.getFxEl();
10504         o = o || {};
10505         el.queueFx(o, function(){
10506             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10507                 o, null, .5, "easeOut", function(){
10508                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10509                      this.dom.style.display = "none";
10510                 }else{
10511                      this.dom.style.visibility = "hidden";
10512                 }
10513                 this.clearOpacity();
10514                 el.afterFx(o);
10515             });
10516         });
10517         return this;
10518     },
10519
10520    /**
10521     * Animates the transition of an element's dimensions from a starting height/width
10522     * to an ending height/width.
10523     * Usage:
10524 <pre><code>
10525 // change height and width to 100x100 pixels
10526 el.scale(100, 100);
10527
10528 // common config options shown with default values.  The height and width will default to
10529 // the element's existing values if passed as null.
10530 el.scale(
10531     [element's width],
10532     [element's height], {
10533     easing: 'easeOut',
10534     duration: .35
10535 });
10536 </code></pre>
10537     * @param {Number} width  The new width (pass undefined to keep the original width)
10538     * @param {Number} height  The new height (pass undefined to keep the original height)
10539     * @param {Object} options (optional) Object literal with any of the Fx config options
10540     * @return {Roo.Element} The Element
10541     */
10542     scale : function(w, h, o){
10543         this.shift(Roo.apply({}, o, {
10544             width: w,
10545             height: h
10546         }));
10547         return this;
10548     },
10549
10550    /**
10551     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10552     * Any of these properties not specified in the config object will not be changed.  This effect 
10553     * requires that at least one new dimension, position or opacity setting must be passed in on
10554     * the config object in order for the function to have any effect.
10555     * Usage:
10556 <pre><code>
10557 // slide the element horizontally to x position 200 while changing the height and opacity
10558 el.shift({ x: 200, height: 50, opacity: .8 });
10559
10560 // common config options shown with default values.
10561 el.shift({
10562     width: [element's width],
10563     height: [element's height],
10564     x: [element's x position],
10565     y: [element's y position],
10566     opacity: [element's opacity],
10567     easing: 'easeOut',
10568     duration: .35
10569 });
10570 </code></pre>
10571     * @param {Object} options  Object literal with any of the Fx config options
10572     * @return {Roo.Element} The Element
10573     */
10574     shift : function(o){
10575         var el = this.getFxEl();
10576         o = o || {};
10577         el.queueFx(o, function(){
10578             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10579             if(w !== undefined){
10580                 a.width = {to: this.adjustWidth(w)};
10581             }
10582             if(h !== undefined){
10583                 a.height = {to: this.adjustHeight(h)};
10584             }
10585             if(x !== undefined || y !== undefined){
10586                 a.points = {to: [
10587                     x !== undefined ? x : this.getX(),
10588                     y !== undefined ? y : this.getY()
10589                 ]};
10590             }
10591             if(op !== undefined){
10592                 a.opacity = {to: op};
10593             }
10594             if(o.xy !== undefined){
10595                 a.points = {to: o.xy};
10596             }
10597             arguments.callee.anim = this.fxanim(a,
10598                 o, 'motion', .35, "easeOut", function(){
10599                 el.afterFx(o);
10600             });
10601         });
10602         return this;
10603     },
10604
10605         /**
10606          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10607          * ending point of the effect.
10608          * Usage:
10609          *<pre><code>
10610 // default: slide the element downward while fading out
10611 el.ghost();
10612
10613 // custom: slide the element out to the right with a 2-second duration
10614 el.ghost('r', { duration: 2 });
10615
10616 // common config options shown with default values
10617 el.ghost('b', {
10618     easing: 'easeOut',
10619     duration: .5
10620     remove: false,
10621     useDisplay: false
10622 });
10623 </code></pre>
10624          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10625          * @param {Object} options (optional) Object literal with any of the Fx config options
10626          * @return {Roo.Element} The Element
10627          */
10628     ghost : function(anchor, o){
10629         var el = this.getFxEl();
10630         o = o || {};
10631
10632         el.queueFx(o, function(){
10633             anchor = anchor || "b";
10634
10635             // restore values after effect
10636             var r = this.getFxRestore();
10637             var w = this.getWidth(),
10638                 h = this.getHeight();
10639
10640             var st = this.dom.style;
10641
10642             var after = function(){
10643                 if(o.useDisplay){
10644                     el.setDisplayed(false);
10645                 }else{
10646                     el.hide();
10647                 }
10648
10649                 el.clearOpacity();
10650                 el.setPositioning(r.pos);
10651                 st.width = r.width;
10652                 st.height = r.height;
10653
10654                 el.afterFx(o);
10655             };
10656
10657             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10658             switch(anchor.toLowerCase()){
10659                 case "t":
10660                     pt.by = [0, -h];
10661                 break;
10662                 case "l":
10663                     pt.by = [-w, 0];
10664                 break;
10665                 case "r":
10666                     pt.by = [w, 0];
10667                 break;
10668                 case "b":
10669                     pt.by = [0, h];
10670                 break;
10671                 case "tl":
10672                     pt.by = [-w, -h];
10673                 break;
10674                 case "bl":
10675                     pt.by = [-w, h];
10676                 break;
10677                 case "br":
10678                     pt.by = [w, h];
10679                 break;
10680                 case "tr":
10681                     pt.by = [w, -h];
10682                 break;
10683             }
10684
10685             arguments.callee.anim = this.fxanim(a,
10686                 o,
10687                 'motion',
10688                 .5,
10689                 "easeOut", after);
10690         });
10691         return this;
10692     },
10693
10694         /**
10695          * Ensures that all effects queued after syncFx is called on the element are
10696          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10697          * @return {Roo.Element} The Element
10698          */
10699     syncFx : function(){
10700         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10701             block : false,
10702             concurrent : true,
10703             stopFx : false
10704         });
10705         return this;
10706     },
10707
10708         /**
10709          * Ensures that all effects queued after sequenceFx is called on the element are
10710          * run in sequence.  This is the opposite of {@link #syncFx}.
10711          * @return {Roo.Element} The Element
10712          */
10713     sequenceFx : function(){
10714         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10715             block : false,
10716             concurrent : false,
10717             stopFx : false
10718         });
10719         return this;
10720     },
10721
10722         /* @private */
10723     nextFx : function(){
10724         var ef = this.fxQueue[0];
10725         if(ef){
10726             ef.call(this);
10727         }
10728     },
10729
10730         /**
10731          * Returns true if the element has any effects actively running or queued, else returns false.
10732          * @return {Boolean} True if element has active effects, else false
10733          */
10734     hasActiveFx : function(){
10735         return this.fxQueue && this.fxQueue[0];
10736     },
10737
10738         /**
10739          * Stops any running effects and clears the element's internal effects queue if it contains
10740          * any additional effects that haven't started yet.
10741          * @return {Roo.Element} The Element
10742          */
10743     stopFx : function(){
10744         if(this.hasActiveFx()){
10745             var cur = this.fxQueue[0];
10746             if(cur && cur.anim && cur.anim.isAnimated()){
10747                 this.fxQueue = [cur]; // clear out others
10748                 cur.anim.stop(true);
10749             }
10750         }
10751         return this;
10752     },
10753
10754         /* @private */
10755     beforeFx : function(o){
10756         if(this.hasActiveFx() && !o.concurrent){
10757            if(o.stopFx){
10758                this.stopFx();
10759                return true;
10760            }
10761            return false;
10762         }
10763         return true;
10764     },
10765
10766         /**
10767          * Returns true if the element is currently blocking so that no other effect can be queued
10768          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10769          * used to ensure that an effect initiated by a user action runs to completion prior to the
10770          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10771          * @return {Boolean} True if blocking, else false
10772          */
10773     hasFxBlock : function(){
10774         var q = this.fxQueue;
10775         return q && q[0] && q[0].block;
10776     },
10777
10778         /* @private */
10779     queueFx : function(o, fn){
10780         if(!this.fxQueue){
10781             this.fxQueue = [];
10782         }
10783         if(!this.hasFxBlock()){
10784             Roo.applyIf(o, this.fxDefaults);
10785             if(!o.concurrent){
10786                 var run = this.beforeFx(o);
10787                 fn.block = o.block;
10788                 this.fxQueue.push(fn);
10789                 if(run){
10790                     this.nextFx();
10791                 }
10792             }else{
10793                 fn.call(this);
10794             }
10795         }
10796         return this;
10797     },
10798
10799         /* @private */
10800     fxWrap : function(pos, o, vis){
10801         var wrap;
10802         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10803             var wrapXY;
10804             if(o.fixPosition){
10805                 wrapXY = this.getXY();
10806             }
10807             var div = document.createElement("div");
10808             div.style.visibility = vis;
10809             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10810             wrap.setPositioning(pos);
10811             if(wrap.getStyle("position") == "static"){
10812                 wrap.position("relative");
10813             }
10814             this.clearPositioning('auto');
10815             wrap.clip();
10816             wrap.dom.appendChild(this.dom);
10817             if(wrapXY){
10818                 wrap.setXY(wrapXY);
10819             }
10820         }
10821         return wrap;
10822     },
10823
10824         /* @private */
10825     fxUnwrap : function(wrap, pos, o){
10826         this.clearPositioning();
10827         this.setPositioning(pos);
10828         if(!o.wrap){
10829             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10830             wrap.remove();
10831         }
10832     },
10833
10834         /* @private */
10835     getFxRestore : function(){
10836         var st = this.dom.style;
10837         return {pos: this.getPositioning(), width: st.width, height : st.height};
10838     },
10839
10840         /* @private */
10841     afterFx : function(o){
10842         if(o.afterStyle){
10843             this.applyStyles(o.afterStyle);
10844         }
10845         if(o.afterCls){
10846             this.addClass(o.afterCls);
10847         }
10848         if(o.remove === true){
10849             this.remove();
10850         }
10851         Roo.callback(o.callback, o.scope, [this]);
10852         if(!o.concurrent){
10853             this.fxQueue.shift();
10854             this.nextFx();
10855         }
10856     },
10857
10858         /* @private */
10859     getFxEl : function(){ // support for composite element fx
10860         return Roo.get(this.dom);
10861     },
10862
10863         /* @private */
10864     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10865         animType = animType || 'run';
10866         opt = opt || {};
10867         var anim = Roo.lib.Anim[animType](
10868             this.dom, args,
10869             (opt.duration || defaultDur) || .35,
10870             (opt.easing || defaultEase) || 'easeOut',
10871             function(){
10872                 Roo.callback(cb, this);
10873             },
10874             this
10875         );
10876         opt.anim = anim;
10877         return anim;
10878     }
10879 };
10880
10881 // backwords compat
10882 Roo.Fx.resize = Roo.Fx.scale;
10883
10884 //When included, Roo.Fx is automatically applied to Element so that all basic
10885 //effects are available directly via the Element API
10886 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10887  * Based on:
10888  * Ext JS Library 1.1.1
10889  * Copyright(c) 2006-2007, Ext JS, LLC.
10890  *
10891  * Originally Released Under LGPL - original licence link has changed is not relivant.
10892  *
10893  * Fork - LGPL
10894  * <script type="text/javascript">
10895  */
10896
10897
10898 /**
10899  * @class Roo.CompositeElement
10900  * Standard composite class. Creates a Roo.Element for every element in the collection.
10901  * <br><br>
10902  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10903  * actions will be performed on all the elements in this collection.</b>
10904  * <br><br>
10905  * All methods return <i>this</i> and can be chained.
10906  <pre><code>
10907  var els = Roo.select("#some-el div.some-class", true);
10908  // or select directly from an existing element
10909  var el = Roo.get('some-el');
10910  el.select('div.some-class', true);
10911
10912  els.setWidth(100); // all elements become 100 width
10913  els.hide(true); // all elements fade out and hide
10914  // or
10915  els.setWidth(100).hide(true);
10916  </code></pre>
10917  */
10918 Roo.CompositeElement = function(els){
10919     this.elements = [];
10920     this.addElements(els);
10921 };
10922 Roo.CompositeElement.prototype = {
10923     isComposite: true,
10924     addElements : function(els){
10925         if(!els) return this;
10926         if(typeof els == "string"){
10927             els = Roo.Element.selectorFunction(els);
10928         }
10929         var yels = this.elements;
10930         var index = yels.length-1;
10931         for(var i = 0, len = els.length; i < len; i++) {
10932                 yels[++index] = Roo.get(els[i]);
10933         }
10934         return this;
10935     },
10936
10937     /**
10938     * Clears this composite and adds the elements returned by the passed selector.
10939     * @param {String/Array} els A string CSS selector, an array of elements or an element
10940     * @return {CompositeElement} this
10941     */
10942     fill : function(els){
10943         this.elements = [];
10944         this.add(els);
10945         return this;
10946     },
10947
10948     /**
10949     * Filters this composite to only elements that match the passed selector.
10950     * @param {String} selector A string CSS selector
10951     * @return {CompositeElement} this
10952     */
10953     filter : function(selector){
10954         var els = [];
10955         this.each(function(el){
10956             if(el.is(selector)){
10957                 els[els.length] = el.dom;
10958             }
10959         });
10960         this.fill(els);
10961         return this;
10962     },
10963
10964     invoke : function(fn, args){
10965         var els = this.elements;
10966         for(var i = 0, len = els.length; i < len; i++) {
10967                 Roo.Element.prototype[fn].apply(els[i], args);
10968         }
10969         return this;
10970     },
10971     /**
10972     * Adds elements to this composite.
10973     * @param {String/Array} els A string CSS selector, an array of elements or an element
10974     * @return {CompositeElement} this
10975     */
10976     add : function(els){
10977         if(typeof els == "string"){
10978             this.addElements(Roo.Element.selectorFunction(els));
10979         }else if(els.length !== undefined){
10980             this.addElements(els);
10981         }else{
10982             this.addElements([els]);
10983         }
10984         return this;
10985     },
10986     /**
10987     * Calls the passed function passing (el, this, index) for each element in this composite.
10988     * @param {Function} fn The function to call
10989     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10990     * @return {CompositeElement} this
10991     */
10992     each : function(fn, scope){
10993         var els = this.elements;
10994         for(var i = 0, len = els.length; i < len; i++){
10995             if(fn.call(scope || els[i], els[i], this, i) === false) {
10996                 break;
10997             }
10998         }
10999         return this;
11000     },
11001
11002     /**
11003      * Returns the Element object at the specified index
11004      * @param {Number} index
11005      * @return {Roo.Element}
11006      */
11007     item : function(index){
11008         return this.elements[index] || null;
11009     },
11010
11011     /**
11012      * Returns the first Element
11013      * @return {Roo.Element}
11014      */
11015     first : function(){
11016         return this.item(0);
11017     },
11018
11019     /**
11020      * Returns the last Element
11021      * @return {Roo.Element}
11022      */
11023     last : function(){
11024         return this.item(this.elements.length-1);
11025     },
11026
11027     /**
11028      * Returns the number of elements in this composite
11029      * @return Number
11030      */
11031     getCount : function(){
11032         return this.elements.length;
11033     },
11034
11035     /**
11036      * Returns true if this composite contains the passed element
11037      * @return Boolean
11038      */
11039     contains : function(el){
11040         return this.indexOf(el) !== -1;
11041     },
11042
11043     /**
11044      * Returns true if this composite contains the passed element
11045      * @return Boolean
11046      */
11047     indexOf : function(el){
11048         return this.elements.indexOf(Roo.get(el));
11049     },
11050
11051
11052     /**
11053     * Removes the specified element(s).
11054     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11055     * or an array of any of those.
11056     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11057     * @return {CompositeElement} this
11058     */
11059     removeElement : function(el, removeDom){
11060         if(el instanceof Array){
11061             for(var i = 0, len = el.length; i < len; i++){
11062                 this.removeElement(el[i]);
11063             }
11064             return this;
11065         }
11066         var index = typeof el == 'number' ? el : this.indexOf(el);
11067         if(index !== -1){
11068             if(removeDom){
11069                 var d = this.elements[index];
11070                 if(d.dom){
11071                     d.remove();
11072                 }else{
11073                     d.parentNode.removeChild(d);
11074                 }
11075             }
11076             this.elements.splice(index, 1);
11077         }
11078         return this;
11079     },
11080
11081     /**
11082     * Replaces the specified element with the passed element.
11083     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11084     * to replace.
11085     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11086     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11087     * @return {CompositeElement} this
11088     */
11089     replaceElement : function(el, replacement, domReplace){
11090         var index = typeof el == 'number' ? el : this.indexOf(el);
11091         if(index !== -1){
11092             if(domReplace){
11093                 this.elements[index].replaceWith(replacement);
11094             }else{
11095                 this.elements.splice(index, 1, Roo.get(replacement))
11096             }
11097         }
11098         return this;
11099     },
11100
11101     /**
11102      * Removes all elements.
11103      */
11104     clear : function(){
11105         this.elements = [];
11106     }
11107 };
11108 (function(){
11109     Roo.CompositeElement.createCall = function(proto, fnName){
11110         if(!proto[fnName]){
11111             proto[fnName] = function(){
11112                 return this.invoke(fnName, arguments);
11113             };
11114         }
11115     };
11116     for(var fnName in Roo.Element.prototype){
11117         if(typeof Roo.Element.prototype[fnName] == "function"){
11118             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11119         }
11120     };
11121 })();
11122 /*
11123  * Based on:
11124  * Ext JS Library 1.1.1
11125  * Copyright(c) 2006-2007, Ext JS, LLC.
11126  *
11127  * Originally Released Under LGPL - original licence link has changed is not relivant.
11128  *
11129  * Fork - LGPL
11130  * <script type="text/javascript">
11131  */
11132
11133 /**
11134  * @class Roo.CompositeElementLite
11135  * @extends Roo.CompositeElement
11136  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11137  <pre><code>
11138  var els = Roo.select("#some-el div.some-class");
11139  // or select directly from an existing element
11140  var el = Roo.get('some-el');
11141  el.select('div.some-class');
11142
11143  els.setWidth(100); // all elements become 100 width
11144  els.hide(true); // all elements fade out and hide
11145  // or
11146  els.setWidth(100).hide(true);
11147  </code></pre><br><br>
11148  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11149  * actions will be performed on all the elements in this collection.</b>
11150  */
11151 Roo.CompositeElementLite = function(els){
11152     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11153     this.el = new Roo.Element.Flyweight();
11154 };
11155 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11156     addElements : function(els){
11157         if(els){
11158             if(els instanceof Array){
11159                 this.elements = this.elements.concat(els);
11160             }else{
11161                 var yels = this.elements;
11162                 var index = yels.length-1;
11163                 for(var i = 0, len = els.length; i < len; i++) {
11164                     yels[++index] = els[i];
11165                 }
11166             }
11167         }
11168         return this;
11169     },
11170     invoke : function(fn, args){
11171         var els = this.elements;
11172         var el = this.el;
11173         for(var i = 0, len = els.length; i < len; i++) {
11174             el.dom = els[i];
11175                 Roo.Element.prototype[fn].apply(el, args);
11176         }
11177         return this;
11178     },
11179     /**
11180      * Returns a flyweight Element of the dom element object at the specified index
11181      * @param {Number} index
11182      * @return {Roo.Element}
11183      */
11184     item : function(index){
11185         if(!this.elements[index]){
11186             return null;
11187         }
11188         this.el.dom = this.elements[index];
11189         return this.el;
11190     },
11191
11192     // fixes scope with flyweight
11193     addListener : function(eventName, handler, scope, opt){
11194         var els = this.elements;
11195         for(var i = 0, len = els.length; i < len; i++) {
11196             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11197         }
11198         return this;
11199     },
11200
11201     /**
11202     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11203     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11204     * a reference to the dom node, use el.dom.</b>
11205     * @param {Function} fn The function to call
11206     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11207     * @return {CompositeElement} this
11208     */
11209     each : function(fn, scope){
11210         var els = this.elements;
11211         var el = this.el;
11212         for(var i = 0, len = els.length; i < len; i++){
11213             el.dom = els[i];
11214                 if(fn.call(scope || el, el, this, i) === false){
11215                 break;
11216             }
11217         }
11218         return this;
11219     },
11220
11221     indexOf : function(el){
11222         return this.elements.indexOf(Roo.getDom(el));
11223     },
11224
11225     replaceElement : function(el, replacement, domReplace){
11226         var index = typeof el == 'number' ? el : this.indexOf(el);
11227         if(index !== -1){
11228             replacement = Roo.getDom(replacement);
11229             if(domReplace){
11230                 var d = this.elements[index];
11231                 d.parentNode.insertBefore(replacement, d);
11232                 d.parentNode.removeChild(d);
11233             }
11234             this.elements.splice(index, 1, replacement);
11235         }
11236         return this;
11237     }
11238 });
11239 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11240
11241 /*
11242  * Based on:
11243  * Ext JS Library 1.1.1
11244  * Copyright(c) 2006-2007, Ext JS, LLC.
11245  *
11246  * Originally Released Under LGPL - original licence link has changed is not relivant.
11247  *
11248  * Fork - LGPL
11249  * <script type="text/javascript">
11250  */
11251
11252  
11253
11254 /**
11255  * @class Roo.data.Connection
11256  * @extends Roo.util.Observable
11257  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11258  * either to a configured URL, or to a URL specified at request time.<br><br>
11259  * <p>
11260  * Requests made by this class are asynchronous, and will return immediately. No data from
11261  * the server will be available to the statement immediately following the {@link #request} call.
11262  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11263  * <p>
11264  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11265  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11266  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11267  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11268  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11269  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11270  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11271  * standard DOM methods.
11272  * @constructor
11273  * @param {Object} config a configuration object.
11274  */
11275 Roo.data.Connection = function(config){
11276     Roo.apply(this, config);
11277     this.addEvents({
11278         /**
11279          * @event beforerequest
11280          * Fires before a network request is made to retrieve a data object.
11281          * @param {Connection} conn This Connection object.
11282          * @param {Object} options The options config object passed to the {@link #request} method.
11283          */
11284         "beforerequest" : true,
11285         /**
11286          * @event requestcomplete
11287          * Fires if the request was successfully completed.
11288          * @param {Connection} conn This Connection object.
11289          * @param {Object} response The XHR object containing the response data.
11290          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11291          * @param {Object} options The options config object passed to the {@link #request} method.
11292          */
11293         "requestcomplete" : true,
11294         /**
11295          * @event requestexception
11296          * Fires if an error HTTP status was returned from the server.
11297          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11298          * @param {Connection} conn This Connection object.
11299          * @param {Object} response The XHR object containing the response data.
11300          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11301          * @param {Object} options The options config object passed to the {@link #request} method.
11302          */
11303         "requestexception" : true
11304     });
11305     Roo.data.Connection.superclass.constructor.call(this);
11306 };
11307
11308 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11309     /**
11310      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11311      */
11312     /**
11313      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11314      * extra parameters to each request made by this object. (defaults to undefined)
11315      */
11316     /**
11317      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11318      *  to each request made by this object. (defaults to undefined)
11319      */
11320     /**
11321      * @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)
11322      */
11323     /**
11324      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11325      */
11326     timeout : 30000,
11327     /**
11328      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11329      * @type Boolean
11330      */
11331     autoAbort:false,
11332
11333     /**
11334      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11335      * @type Boolean
11336      */
11337     disableCaching: true,
11338
11339     /**
11340      * Sends an HTTP request to a remote server.
11341      * @param {Object} options An object which may contain the following properties:<ul>
11342      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11343      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11344      * request, a url encoded string or a function to call to get either.</li>
11345      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11346      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11347      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11348      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11349      * <li>options {Object} The parameter to the request call.</li>
11350      * <li>success {Boolean} True if the request succeeded.</li>
11351      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11352      * </ul></li>
11353      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11354      * The callback is passed the following parameters:<ul>
11355      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11356      * <li>options {Object} The parameter to the request call.</li>
11357      * </ul></li>
11358      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11359      * The callback is passed the following parameters:<ul>
11360      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11361      * <li>options {Object} The parameter to the request call.</li>
11362      * </ul></li>
11363      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11364      * for the callback function. Defaults to the browser window.</li>
11365      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11366      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11367      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11368      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11369      * params for the post data. Any params will be appended to the URL.</li>
11370      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11371      * </ul>
11372      * @return {Number} transactionId
11373      */
11374     request : function(o){
11375         if(this.fireEvent("beforerequest", this, o) !== false){
11376             var p = o.params;
11377
11378             if(typeof p == "function"){
11379                 p = p.call(o.scope||window, o);
11380             }
11381             if(typeof p == "object"){
11382                 p = Roo.urlEncode(o.params);
11383             }
11384             if(this.extraParams){
11385                 var extras = Roo.urlEncode(this.extraParams);
11386                 p = p ? (p + '&' + extras) : extras;
11387             }
11388
11389             var url = o.url || this.url;
11390             if(typeof url == 'function'){
11391                 url = url.call(o.scope||window, o);
11392             }
11393
11394             if(o.form){
11395                 var form = Roo.getDom(o.form);
11396                 url = url || form.action;
11397
11398                 var enctype = form.getAttribute("enctype");
11399                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11400                     return this.doFormUpload(o, p, url);
11401                 }
11402                 var f = Roo.lib.Ajax.serializeForm(form);
11403                 p = p ? (p + '&' + f) : f;
11404             }
11405
11406             var hs = o.headers;
11407             if(this.defaultHeaders){
11408                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11409                 if(!o.headers){
11410                     o.headers = hs;
11411                 }
11412             }
11413
11414             var cb = {
11415                 success: this.handleResponse,
11416                 failure: this.handleFailure,
11417                 scope: this,
11418                 argument: {options: o},
11419                 timeout : o.timeout || this.timeout
11420             };
11421
11422             var method = o.method||this.method||(p ? "POST" : "GET");
11423
11424             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11425                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11426             }
11427
11428             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11429                 if(o.autoAbort){
11430                     this.abort();
11431                 }
11432             }else if(this.autoAbort !== false){
11433                 this.abort();
11434             }
11435
11436             if((method == 'GET' && p) || o.xmlData){
11437                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11438                 p = '';
11439             }
11440             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11441             return this.transId;
11442         }else{
11443             Roo.callback(o.callback, o.scope, [o, null, null]);
11444             return null;
11445         }
11446     },
11447
11448     /**
11449      * Determine whether this object has a request outstanding.
11450      * @param {Number} transactionId (Optional) defaults to the last transaction
11451      * @return {Boolean} True if there is an outstanding request.
11452      */
11453     isLoading : function(transId){
11454         if(transId){
11455             return Roo.lib.Ajax.isCallInProgress(transId);
11456         }else{
11457             return this.transId ? true : false;
11458         }
11459     },
11460
11461     /**
11462      * Aborts any outstanding request.
11463      * @param {Number} transactionId (Optional) defaults to the last transaction
11464      */
11465     abort : function(transId){
11466         if(transId || this.isLoading()){
11467             Roo.lib.Ajax.abort(transId || this.transId);
11468         }
11469     },
11470
11471     // private
11472     handleResponse : function(response){
11473         this.transId = false;
11474         var options = response.argument.options;
11475         response.argument = options ? options.argument : null;
11476         this.fireEvent("requestcomplete", this, response, options);
11477         Roo.callback(options.success, options.scope, [response, options]);
11478         Roo.callback(options.callback, options.scope, [options, true, response]);
11479     },
11480
11481     // private
11482     handleFailure : function(response, e){
11483         this.transId = false;
11484         var options = response.argument.options;
11485         response.argument = options ? options.argument : null;
11486         this.fireEvent("requestexception", this, response, options, e);
11487         Roo.callback(options.failure, options.scope, [response, options]);
11488         Roo.callback(options.callback, options.scope, [options, false, response]);
11489     },
11490
11491     // private
11492     doFormUpload : function(o, ps, url){
11493         var id = Roo.id();
11494         var frame = document.createElement('iframe');
11495         frame.id = id;
11496         frame.name = id;
11497         frame.className = 'x-hidden';
11498         if(Roo.isIE){
11499             frame.src = Roo.SSL_SECURE_URL;
11500         }
11501         document.body.appendChild(frame);
11502
11503         if(Roo.isIE){
11504            document.frames[id].name = id;
11505         }
11506
11507         var form = Roo.getDom(o.form);
11508         form.target = id;
11509         form.method = 'POST';
11510         form.enctype = form.encoding = 'multipart/form-data';
11511         if(url){
11512             form.action = url;
11513         }
11514
11515         var hiddens, hd;
11516         if(ps){ // add dynamic params
11517             hiddens = [];
11518             ps = Roo.urlDecode(ps, false);
11519             for(var k in ps){
11520                 if(ps.hasOwnProperty(k)){
11521                     hd = document.createElement('input');
11522                     hd.type = 'hidden';
11523                     hd.name = k;
11524                     hd.value = ps[k];
11525                     form.appendChild(hd);
11526                     hiddens.push(hd);
11527                 }
11528             }
11529         }
11530
11531         function cb(){
11532             var r = {  // bogus response object
11533                 responseText : '',
11534                 responseXML : null
11535             };
11536
11537             r.argument = o ? o.argument : null;
11538
11539             try { //
11540                 var doc;
11541                 if(Roo.isIE){
11542                     doc = frame.contentWindow.document;
11543                 }else {
11544                     doc = (frame.contentDocument || window.frames[id].document);
11545                 }
11546                 if(doc && doc.body){
11547                     r.responseText = doc.body.innerHTML;
11548                 }
11549                 if(doc && doc.XMLDocument){
11550                     r.responseXML = doc.XMLDocument;
11551                 }else {
11552                     r.responseXML = doc;
11553                 }
11554             }
11555             catch(e) {
11556                 // ignore
11557             }
11558
11559             Roo.EventManager.removeListener(frame, 'load', cb, this);
11560
11561             this.fireEvent("requestcomplete", this, r, o);
11562             Roo.callback(o.success, o.scope, [r, o]);
11563             Roo.callback(o.callback, o.scope, [o, true, r]);
11564
11565             setTimeout(function(){document.body.removeChild(frame);}, 100);
11566         }
11567
11568         Roo.EventManager.on(frame, 'load', cb, this);
11569         form.submit();
11570
11571         if(hiddens){ // remove dynamic params
11572             for(var i = 0, len = hiddens.length; i < len; i++){
11573                 form.removeChild(hiddens[i]);
11574             }
11575         }
11576     }
11577 });
11578 /*
11579  * Based on:
11580  * Ext JS Library 1.1.1
11581  * Copyright(c) 2006-2007, Ext JS, LLC.
11582  *
11583  * Originally Released Under LGPL - original licence link has changed is not relivant.
11584  *
11585  * Fork - LGPL
11586  * <script type="text/javascript">
11587  */
11588  
11589 /**
11590  * Global Ajax request class.
11591  * 
11592  * @class Roo.Ajax
11593  * @extends Roo.data.Connection
11594  * @static
11595  * 
11596  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11597  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11598  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11599  * @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)
11600  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11601  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11602  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11603  */
11604 Roo.Ajax = new Roo.data.Connection({
11605     // fix up the docs
11606     /**
11607      * @scope Roo.Ajax
11608      * @type {Boolear} 
11609      */
11610     autoAbort : false,
11611
11612     /**
11613      * Serialize the passed form into a url encoded string
11614      * @scope Roo.Ajax
11615      * @param {String/HTMLElement} form
11616      * @return {String}
11617      */
11618     serializeForm : function(form){
11619         return Roo.lib.Ajax.serializeForm(form);
11620     }
11621 });/*
11622  * Based on:
11623  * Ext JS Library 1.1.1
11624  * Copyright(c) 2006-2007, Ext JS, LLC.
11625  *
11626  * Originally Released Under LGPL - original licence link has changed is not relivant.
11627  *
11628  * Fork - LGPL
11629  * <script type="text/javascript">
11630  */
11631
11632  
11633 /**
11634  * @class Roo.UpdateManager
11635  * @extends Roo.util.Observable
11636  * Provides AJAX-style update for Element object.<br><br>
11637  * Usage:<br>
11638  * <pre><code>
11639  * // Get it from a Roo.Element object
11640  * var el = Roo.get("foo");
11641  * var mgr = el.getUpdateManager();
11642  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11643  * ...
11644  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11645  * <br>
11646  * // or directly (returns the same UpdateManager instance)
11647  * var mgr = new Roo.UpdateManager("myElementId");
11648  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11649  * mgr.on("update", myFcnNeedsToKnow);
11650  * <br>
11651    // short handed call directly from the element object
11652    Roo.get("foo").load({
11653         url: "bar.php",
11654         scripts:true,
11655         params: "for=bar",
11656         text: "Loading Foo..."
11657    });
11658  * </code></pre>
11659  * @constructor
11660  * Create new UpdateManager directly.
11661  * @param {String/HTMLElement/Roo.Element} el The element to update
11662  * @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).
11663  */
11664 Roo.UpdateManager = function(el, forceNew){
11665     el = Roo.get(el);
11666     if(!forceNew && el.updateManager){
11667         return el.updateManager;
11668     }
11669     /**
11670      * The Element object
11671      * @type Roo.Element
11672      */
11673     this.el = el;
11674     /**
11675      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11676      * @type String
11677      */
11678     this.defaultUrl = null;
11679
11680     this.addEvents({
11681         /**
11682          * @event beforeupdate
11683          * Fired before an update is made, return false from your handler and the update is cancelled.
11684          * @param {Roo.Element} el
11685          * @param {String/Object/Function} url
11686          * @param {String/Object} params
11687          */
11688         "beforeupdate": true,
11689         /**
11690          * @event update
11691          * Fired after successful update is made.
11692          * @param {Roo.Element} el
11693          * @param {Object} oResponseObject The response Object
11694          */
11695         "update": true,
11696         /**
11697          * @event failure
11698          * Fired on update failure.
11699          * @param {Roo.Element} el
11700          * @param {Object} oResponseObject The response Object
11701          */
11702         "failure": true
11703     });
11704     var d = Roo.UpdateManager.defaults;
11705     /**
11706      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11707      * @type String
11708      */
11709     this.sslBlankUrl = d.sslBlankUrl;
11710     /**
11711      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11712      * @type Boolean
11713      */
11714     this.disableCaching = d.disableCaching;
11715     /**
11716      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11717      * @type String
11718      */
11719     this.indicatorText = d.indicatorText;
11720     /**
11721      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11722      * @type String
11723      */
11724     this.showLoadIndicator = d.showLoadIndicator;
11725     /**
11726      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11727      * @type Number
11728      */
11729     this.timeout = d.timeout;
11730
11731     /**
11732      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11733      * @type Boolean
11734      */
11735     this.loadScripts = d.loadScripts;
11736
11737     /**
11738      * Transaction object of current executing transaction
11739      */
11740     this.transaction = null;
11741
11742     /**
11743      * @private
11744      */
11745     this.autoRefreshProcId = null;
11746     /**
11747      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11748      * @type Function
11749      */
11750     this.refreshDelegate = this.refresh.createDelegate(this);
11751     /**
11752      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11753      * @type Function
11754      */
11755     this.updateDelegate = this.update.createDelegate(this);
11756     /**
11757      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11758      * @type Function
11759      */
11760     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11761     /**
11762      * @private
11763      */
11764     this.successDelegate = this.processSuccess.createDelegate(this);
11765     /**
11766      * @private
11767      */
11768     this.failureDelegate = this.processFailure.createDelegate(this);
11769
11770     if(!this.renderer){
11771      /**
11772       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11773       */
11774     this.renderer = new Roo.UpdateManager.BasicRenderer();
11775     }
11776     
11777     Roo.UpdateManager.superclass.constructor.call(this);
11778 };
11779
11780 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11781     /**
11782      * Get the Element this UpdateManager is bound to
11783      * @return {Roo.Element} The element
11784      */
11785     getEl : function(){
11786         return this.el;
11787     },
11788     /**
11789      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11790      * @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:
11791 <pre><code>
11792 um.update({<br/>
11793     url: "your-url.php",<br/>
11794     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11795     callback: yourFunction,<br/>
11796     scope: yourObject, //(optional scope)  <br/>
11797     discardUrl: false, <br/>
11798     nocache: false,<br/>
11799     text: "Loading...",<br/>
11800     timeout: 30,<br/>
11801     scripts: false<br/>
11802 });
11803 </code></pre>
11804      * The only required property is url. The optional properties nocache, text and scripts
11805      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11806      * @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}
11807      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11808      * @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.
11809      */
11810     update : function(url, params, callback, discardUrl){
11811         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11812             var method = this.method,
11813                 cfg;
11814             if(typeof url == "object"){ // must be config object
11815                 cfg = url;
11816                 url = cfg.url;
11817                 params = params || cfg.params;
11818                 callback = callback || cfg.callback;
11819                 discardUrl = discardUrl || cfg.discardUrl;
11820                 if(callback && cfg.scope){
11821                     callback = callback.createDelegate(cfg.scope);
11822                 }
11823                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11824                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11825                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11826                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11827                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11828             }
11829             this.showLoading();
11830             if(!discardUrl){
11831                 this.defaultUrl = url;
11832             }
11833             if(typeof url == "function"){
11834                 url = url.call(this);
11835             }
11836
11837             method = method || (params ? "POST" : "GET");
11838             if(method == "GET"){
11839                 url = this.prepareUrl(url);
11840             }
11841
11842             var o = Roo.apply(cfg ||{}, {
11843                 url : url,
11844                 params: params,
11845                 success: this.successDelegate,
11846                 failure: this.failureDelegate,
11847                 callback: undefined,
11848                 timeout: (this.timeout*1000),
11849                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11850             });
11851             Roo.log("updated manager called with timeout of " + o.timeout);
11852             this.transaction = Roo.Ajax.request(o);
11853         }
11854     },
11855
11856     /**
11857      * 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.
11858      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11859      * @param {String/HTMLElement} form The form Id or form element
11860      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11861      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11862      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11863      */
11864     formUpdate : function(form, url, reset, callback){
11865         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11866             if(typeof url == "function"){
11867                 url = url.call(this);
11868             }
11869             form = Roo.getDom(form);
11870             this.transaction = Roo.Ajax.request({
11871                 form: form,
11872                 url:url,
11873                 success: this.successDelegate,
11874                 failure: this.failureDelegate,
11875                 timeout: (this.timeout*1000),
11876                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11877             });
11878             this.showLoading.defer(1, this);
11879         }
11880     },
11881
11882     /**
11883      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11884      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11885      */
11886     refresh : function(callback){
11887         if(this.defaultUrl == null){
11888             return;
11889         }
11890         this.update(this.defaultUrl, null, callback, true);
11891     },
11892
11893     /**
11894      * Set this element to auto refresh.
11895      * @param {Number} interval How often to update (in seconds).
11896      * @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)
11897      * @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}
11898      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11899      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11900      */
11901     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11902         if(refreshNow){
11903             this.update(url || this.defaultUrl, params, callback, true);
11904         }
11905         if(this.autoRefreshProcId){
11906             clearInterval(this.autoRefreshProcId);
11907         }
11908         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11909     },
11910
11911     /**
11912      * Stop auto refresh on this element.
11913      */
11914      stopAutoRefresh : function(){
11915         if(this.autoRefreshProcId){
11916             clearInterval(this.autoRefreshProcId);
11917             delete this.autoRefreshProcId;
11918         }
11919     },
11920
11921     isAutoRefreshing : function(){
11922        return this.autoRefreshProcId ? true : false;
11923     },
11924     /**
11925      * Called to update the element to "Loading" state. Override to perform custom action.
11926      */
11927     showLoading : function(){
11928         if(this.showLoadIndicator){
11929             this.el.update(this.indicatorText);
11930         }
11931     },
11932
11933     /**
11934      * Adds unique parameter to query string if disableCaching = true
11935      * @private
11936      */
11937     prepareUrl : function(url){
11938         if(this.disableCaching){
11939             var append = "_dc=" + (new Date().getTime());
11940             if(url.indexOf("?") !== -1){
11941                 url += "&" + append;
11942             }else{
11943                 url += "?" + append;
11944             }
11945         }
11946         return url;
11947     },
11948
11949     /**
11950      * @private
11951      */
11952     processSuccess : function(response){
11953         this.transaction = null;
11954         if(response.argument.form && response.argument.reset){
11955             try{ // put in try/catch since some older FF releases had problems with this
11956                 response.argument.form.reset();
11957             }catch(e){}
11958         }
11959         if(this.loadScripts){
11960             this.renderer.render(this.el, response, this,
11961                 this.updateComplete.createDelegate(this, [response]));
11962         }else{
11963             this.renderer.render(this.el, response, this);
11964             this.updateComplete(response);
11965         }
11966     },
11967
11968     updateComplete : function(response){
11969         this.fireEvent("update", this.el, response);
11970         if(typeof response.argument.callback == "function"){
11971             response.argument.callback(this.el, true, response);
11972         }
11973     },
11974
11975     /**
11976      * @private
11977      */
11978     processFailure : function(response){
11979         this.transaction = null;
11980         this.fireEvent("failure", this.el, response);
11981         if(typeof response.argument.callback == "function"){
11982             response.argument.callback(this.el, false, response);
11983         }
11984     },
11985
11986     /**
11987      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11988      * @param {Object} renderer The object implementing the render() method
11989      */
11990     setRenderer : function(renderer){
11991         this.renderer = renderer;
11992     },
11993
11994     getRenderer : function(){
11995        return this.renderer;
11996     },
11997
11998     /**
11999      * Set the defaultUrl used for updates
12000      * @param {String/Function} defaultUrl The url or a function to call to get the url
12001      */
12002     setDefaultUrl : function(defaultUrl){
12003         this.defaultUrl = defaultUrl;
12004     },
12005
12006     /**
12007      * Aborts the executing transaction
12008      */
12009     abort : function(){
12010         if(this.transaction){
12011             Roo.Ajax.abort(this.transaction);
12012         }
12013     },
12014
12015     /**
12016      * Returns true if an update is in progress
12017      * @return {Boolean}
12018      */
12019     isUpdating : function(){
12020         if(this.transaction){
12021             return Roo.Ajax.isLoading(this.transaction);
12022         }
12023         return false;
12024     }
12025 });
12026
12027 /**
12028  * @class Roo.UpdateManager.defaults
12029  * @static (not really - but it helps the doc tool)
12030  * The defaults collection enables customizing the default properties of UpdateManager
12031  */
12032    Roo.UpdateManager.defaults = {
12033        /**
12034          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12035          * @type Number
12036          */
12037          timeout : 30,
12038
12039          /**
12040          * True to process scripts by default (Defaults to false).
12041          * @type Boolean
12042          */
12043         loadScripts : false,
12044
12045         /**
12046         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12047         * @type String
12048         */
12049         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12050         /**
12051          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12052          * @type Boolean
12053          */
12054         disableCaching : false,
12055         /**
12056          * Whether to show indicatorText when loading (Defaults to true).
12057          * @type Boolean
12058          */
12059         showLoadIndicator : true,
12060         /**
12061          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12062          * @type String
12063          */
12064         indicatorText : '<div class="loading-indicator">Loading...</div>'
12065    };
12066
12067 /**
12068  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12069  *Usage:
12070  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12071  * @param {String/HTMLElement/Roo.Element} el The element to update
12072  * @param {String} url The url
12073  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12074  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12075  * @static
12076  * @deprecated
12077  * @member Roo.UpdateManager
12078  */
12079 Roo.UpdateManager.updateElement = function(el, url, params, options){
12080     var um = Roo.get(el, true).getUpdateManager();
12081     Roo.apply(um, options);
12082     um.update(url, params, options ? options.callback : null);
12083 };
12084 // alias for backwards compat
12085 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12086 /**
12087  * @class Roo.UpdateManager.BasicRenderer
12088  * Default Content renderer. Updates the elements innerHTML with the responseText.
12089  */
12090 Roo.UpdateManager.BasicRenderer = function(){};
12091
12092 Roo.UpdateManager.BasicRenderer.prototype = {
12093     /**
12094      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12095      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12096      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12097      * @param {Roo.Element} el The element being rendered
12098      * @param {Object} response The YUI Connect response object
12099      * @param {UpdateManager} updateManager The calling update manager
12100      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12101      */
12102      render : function(el, response, updateManager, callback){
12103         el.update(response.responseText, updateManager.loadScripts, callback);
12104     }
12105 };
12106 /*
12107  * Based on:
12108  * Roo JS
12109  * (c)) Alan Knowles
12110  * Licence : LGPL
12111  */
12112
12113
12114 /**
12115  * @class Roo.DomTemplate
12116  * @extends Roo.Template
12117  * An effort at a dom based template engine..
12118  *
12119  * Similar to XTemplate, except it uses dom parsing to create the template..
12120  *
12121  * Supported features:
12122  *
12123  *  Tags:
12124
12125 <pre><code>
12126       {a_variable} - output encoded.
12127       {a_variable.format:("Y-m-d")} - call a method on the variable
12128       {a_variable:raw} - unencoded output
12129       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12130       {a_variable:this.method_on_template(...)} - call a method on the template object.
12131  
12132 </code></pre>
12133  *  The tpl tag:
12134 <pre><code>
12135         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12136         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12137         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12138         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12139   
12140 </code></pre>
12141  *      
12142  */
12143 Roo.DomTemplate = function()
12144 {
12145      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12146      if (this.html) {
12147         this.compile();
12148      }
12149 };
12150
12151
12152 Roo.extend(Roo.DomTemplate, Roo.Template, {
12153     /**
12154      * id counter for sub templates.
12155      */
12156     id : 0,
12157     /**
12158      * flag to indicate if dom parser is inside a pre,
12159      * it will strip whitespace if not.
12160      */
12161     inPre : false,
12162     
12163     /**
12164      * The various sub templates
12165      */
12166     tpls : false,
12167     
12168     
12169     
12170     /**
12171      *
12172      * basic tag replacing syntax
12173      * WORD:WORD()
12174      *
12175      * // you can fake an object call by doing this
12176      *  x.t:(test,tesT) 
12177      * 
12178      */
12179     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12180     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12181     
12182     iterChild : function (node, method) {
12183         
12184         var oldPre = this.inPre;
12185         if (node.tagName == 'PRE') {
12186             this.inPre = true;
12187         }
12188         for( var i = 0; i < node.childNodes.length; i++) {
12189             method.call(this, node.childNodes[i]);
12190         }
12191         this.inPre = oldPre;
12192     },
12193     
12194     
12195     
12196     /**
12197      * compile the template
12198      *
12199      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12200      *
12201      */
12202     compile: function()
12203     {
12204         var s = this.html;
12205         
12206         // covert the html into DOM...
12207         var doc = false;
12208         var div =false;
12209         try {
12210             doc = document.implementation.createHTMLDocument("");
12211             doc.documentElement.innerHTML =   this.html  ;
12212             div = doc.documentElement;
12213         } catch (e) {
12214             // old IE... - nasty -- it causes all sorts of issues.. with
12215             // images getting pulled from server..
12216             div = document.createElement('div');
12217             div.innerHTML = this.html;
12218         }
12219         //doc.documentElement.innerHTML = htmlBody
12220          
12221         
12222         
12223         this.tpls = [];
12224         var _t = this;
12225         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12226         
12227         var tpls = this.tpls;
12228         
12229         // create a top level template from the snippet..
12230         
12231         //Roo.log(div.innerHTML);
12232         
12233         var tpl = {
12234             uid : 'master',
12235             id : this.id++,
12236             attr : false,
12237             value : false,
12238             body : div.innerHTML,
12239             
12240             forCall : false,
12241             execCall : false,
12242             dom : div,
12243             isTop : true
12244             
12245         };
12246         tpls.unshift(tpl);
12247         
12248         
12249         // compile them...
12250         this.tpls = [];
12251         Roo.each(tpls, function(tp){
12252             this.compileTpl(tp);
12253             this.tpls[tp.id] = tp;
12254         }, this);
12255         
12256         this.master = tpls[0];
12257         return this;
12258         
12259         
12260     },
12261     
12262     compileNode : function(node, istop) {
12263         // test for
12264         //Roo.log(node);
12265         
12266         
12267         // skip anything not a tag..
12268         if (node.nodeType != 1) {
12269             if (node.nodeType == 3 && !this.inPre) {
12270                 // reduce white space..
12271                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12272                 
12273             }
12274             return;
12275         }
12276         
12277         var tpl = {
12278             uid : false,
12279             id : false,
12280             attr : false,
12281             value : false,
12282             body : '',
12283             
12284             forCall : false,
12285             execCall : false,
12286             dom : false,
12287             isTop : istop
12288             
12289             
12290         };
12291         
12292         
12293         switch(true) {
12294             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12295             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12296             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12297             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12298             // no default..
12299         }
12300         
12301         
12302         if (!tpl.attr) {
12303             // just itterate children..
12304             this.iterChild(node,this.compileNode);
12305             return;
12306         }
12307         tpl.uid = this.id++;
12308         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12309         node.removeAttribute('roo-'+ tpl.attr);
12310         if (tpl.attr != 'name') {
12311             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12312             node.parentNode.replaceChild(placeholder,  node);
12313         } else {
12314             
12315             var placeholder =  document.createElement('span');
12316             placeholder.className = 'roo-tpl-' + tpl.value;
12317             node.parentNode.replaceChild(placeholder,  node);
12318         }
12319         
12320         // parent now sees '{domtplXXXX}
12321         this.iterChild(node,this.compileNode);
12322         
12323         // we should now have node body...
12324         var div = document.createElement('div');
12325         div.appendChild(node);
12326         tpl.dom = node;
12327         // this has the unfortunate side effect of converting tagged attributes
12328         // eg. href="{...}" into %7C...%7D
12329         // this has been fixed by searching for those combo's although it's a bit hacky..
12330         
12331         
12332         tpl.body = div.innerHTML;
12333         
12334         
12335          
12336         tpl.id = tpl.uid;
12337         switch(tpl.attr) {
12338             case 'for' :
12339                 switch (tpl.value) {
12340                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12341                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12342                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12343                 }
12344                 break;
12345             
12346             case 'exec':
12347                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12348                 break;
12349             
12350             case 'if':     
12351                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12352                 break;
12353             
12354             case 'name':
12355                 tpl.id  = tpl.value; // replace non characters???
12356                 break;
12357             
12358         }
12359         
12360         
12361         this.tpls.push(tpl);
12362         
12363         
12364         
12365     },
12366     
12367     
12368     
12369     
12370     /**
12371      * Compile a segment of the template into a 'sub-template'
12372      *
12373      * 
12374      * 
12375      *
12376      */
12377     compileTpl : function(tpl)
12378     {
12379         var fm = Roo.util.Format;
12380         var useF = this.disableFormats !== true;
12381         
12382         var sep = Roo.isGecko ? "+\n" : ",\n";
12383         
12384         var undef = function(str) {
12385             Roo.debug && Roo.log("Property not found :"  + str);
12386             return '';
12387         };
12388           
12389         //Roo.log(tpl.body);
12390         
12391         
12392         
12393         var fn = function(m, lbrace, name, format, args)
12394         {
12395             //Roo.log("ARGS");
12396             //Roo.log(arguments);
12397             args = args ? args.replace(/\\'/g,"'") : args;
12398             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12399             if (typeof(format) == 'undefined') {
12400                 format =  'htmlEncode'; 
12401             }
12402             if (format == 'raw' ) {
12403                 format = false;
12404             }
12405             
12406             if(name.substr(0, 6) == 'domtpl'){
12407                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12408             }
12409             
12410             // build an array of options to determine if value is undefined..
12411             
12412             // basically get 'xxxx.yyyy' then do
12413             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12414             //    (function () { Roo.log("Property not found"); return ''; })() :
12415             //    ......
12416             
12417             var udef_ar = [];
12418             var lookfor = '';
12419             Roo.each(name.split('.'), function(st) {
12420                 lookfor += (lookfor.length ? '.': '') + st;
12421                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12422             });
12423             
12424             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12425             
12426             
12427             if(format && useF){
12428                 
12429                 args = args ? ',' + args : "";
12430                  
12431                 if(format.substr(0, 5) != "this."){
12432                     format = "fm." + format + '(';
12433                 }else{
12434                     format = 'this.call("'+ format.substr(5) + '", ';
12435                     args = ", values";
12436                 }
12437                 
12438                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12439             }
12440              
12441             if (args && args.length) {
12442                 // called with xxyx.yuu:(test,test)
12443                 // change to ()
12444                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12445             }
12446             // raw.. - :raw modifier..
12447             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12448             
12449         };
12450         var body;
12451         // branched to use + in gecko and [].join() in others
12452         if(Roo.isGecko){
12453             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12454                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12455                     "';};};";
12456         }else{
12457             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12458             body.push(tpl.body.replace(/(\r\n|\n)/g,
12459                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12460             body.push("'].join('');};};");
12461             body = body.join('');
12462         }
12463         
12464         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12465        
12466         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12467         eval(body);
12468         
12469         return this;
12470     },
12471      
12472     /**
12473      * same as applyTemplate, except it's done to one of the subTemplates
12474      * when using named templates, you can do:
12475      *
12476      * var str = pl.applySubTemplate('your-name', values);
12477      *
12478      * 
12479      * @param {Number} id of the template
12480      * @param {Object} values to apply to template
12481      * @param {Object} parent (normaly the instance of this object)
12482      */
12483     applySubTemplate : function(id, values, parent)
12484     {
12485         
12486         
12487         var t = this.tpls[id];
12488         
12489         
12490         try { 
12491             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12492                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12493                 return '';
12494             }
12495         } catch(e) {
12496             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12497             Roo.log(values);
12498           
12499             return '';
12500         }
12501         try { 
12502             
12503             if(t.execCall && t.execCall.call(this, values, parent)){
12504                 return '';
12505             }
12506         } catch(e) {
12507             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12508             Roo.log(values);
12509             return '';
12510         }
12511         
12512         try {
12513             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12514             parent = t.target ? values : parent;
12515             if(t.forCall && vs instanceof Array){
12516                 var buf = [];
12517                 for(var i = 0, len = vs.length; i < len; i++){
12518                     try {
12519                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12520                     } catch (e) {
12521                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12522                         Roo.log(e.body);
12523                         //Roo.log(t.compiled);
12524                         Roo.log(vs[i]);
12525                     }   
12526                 }
12527                 return buf.join('');
12528             }
12529         } catch (e) {
12530             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12531             Roo.log(values);
12532             return '';
12533         }
12534         try {
12535             return t.compiled.call(this, vs, parent);
12536         } catch (e) {
12537             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12538             Roo.log(e.body);
12539             //Roo.log(t.compiled);
12540             Roo.log(values);
12541             return '';
12542         }
12543     },
12544
12545    
12546
12547     applyTemplate : function(values){
12548         return this.master.compiled.call(this, values, {});
12549         //var s = this.subs;
12550     },
12551
12552     apply : function(){
12553         return this.applyTemplate.apply(this, arguments);
12554     }
12555
12556  });
12557
12558 Roo.DomTemplate.from = function(el){
12559     el = Roo.getDom(el);
12560     return new Roo.Domtemplate(el.value || el.innerHTML);
12561 };/*
12562  * Based on:
12563  * Ext JS Library 1.1.1
12564  * Copyright(c) 2006-2007, Ext JS, LLC.
12565  *
12566  * Originally Released Under LGPL - original licence link has changed is not relivant.
12567  *
12568  * Fork - LGPL
12569  * <script type="text/javascript">
12570  */
12571
12572 /**
12573  * @class Roo.util.DelayedTask
12574  * Provides a convenient method of performing setTimeout where a new
12575  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12576  * You can use this class to buffer
12577  * the keypress events for a certain number of milliseconds, and perform only if they stop
12578  * for that amount of time.
12579  * @constructor The parameters to this constructor serve as defaults and are not required.
12580  * @param {Function} fn (optional) The default function to timeout
12581  * @param {Object} scope (optional) The default scope of that timeout
12582  * @param {Array} args (optional) The default Array of arguments
12583  */
12584 Roo.util.DelayedTask = function(fn, scope, args){
12585     var id = null, d, t;
12586
12587     var call = function(){
12588         var now = new Date().getTime();
12589         if(now - t >= d){
12590             clearInterval(id);
12591             id = null;
12592             fn.apply(scope, args || []);
12593         }
12594     };
12595     /**
12596      * Cancels any pending timeout and queues a new one
12597      * @param {Number} delay The milliseconds to delay
12598      * @param {Function} newFn (optional) Overrides function passed to constructor
12599      * @param {Object} newScope (optional) Overrides scope passed to constructor
12600      * @param {Array} newArgs (optional) Overrides args passed to constructor
12601      */
12602     this.delay = function(delay, newFn, newScope, newArgs){
12603         if(id && delay != d){
12604             this.cancel();
12605         }
12606         d = delay;
12607         t = new Date().getTime();
12608         fn = newFn || fn;
12609         scope = newScope || scope;
12610         args = newArgs || args;
12611         if(!id){
12612             id = setInterval(call, d);
12613         }
12614     };
12615
12616     /**
12617      * Cancel the last queued timeout
12618      */
12619     this.cancel = function(){
12620         if(id){
12621             clearInterval(id);
12622             id = null;
12623         }
12624     };
12625 };/*
12626  * Based on:
12627  * Ext JS Library 1.1.1
12628  * Copyright(c) 2006-2007, Ext JS, LLC.
12629  *
12630  * Originally Released Under LGPL - original licence link has changed is not relivant.
12631  *
12632  * Fork - LGPL
12633  * <script type="text/javascript">
12634  */
12635  
12636  
12637 Roo.util.TaskRunner = function(interval){
12638     interval = interval || 10;
12639     var tasks = [], removeQueue = [];
12640     var id = 0;
12641     var running = false;
12642
12643     var stopThread = function(){
12644         running = false;
12645         clearInterval(id);
12646         id = 0;
12647     };
12648
12649     var startThread = function(){
12650         if(!running){
12651             running = true;
12652             id = setInterval(runTasks, interval);
12653         }
12654     };
12655
12656     var removeTask = function(task){
12657         removeQueue.push(task);
12658         if(task.onStop){
12659             task.onStop();
12660         }
12661     };
12662
12663     var runTasks = function(){
12664         if(removeQueue.length > 0){
12665             for(var i = 0, len = removeQueue.length; i < len; i++){
12666                 tasks.remove(removeQueue[i]);
12667             }
12668             removeQueue = [];
12669             if(tasks.length < 1){
12670                 stopThread();
12671                 return;
12672             }
12673         }
12674         var now = new Date().getTime();
12675         for(var i = 0, len = tasks.length; i < len; ++i){
12676             var t = tasks[i];
12677             var itime = now - t.taskRunTime;
12678             if(t.interval <= itime){
12679                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12680                 t.taskRunTime = now;
12681                 if(rt === false || t.taskRunCount === t.repeat){
12682                     removeTask(t);
12683                     return;
12684                 }
12685             }
12686             if(t.duration && t.duration <= (now - t.taskStartTime)){
12687                 removeTask(t);
12688             }
12689         }
12690     };
12691
12692     /**
12693      * Queues a new task.
12694      * @param {Object} task
12695      */
12696     this.start = function(task){
12697         tasks.push(task);
12698         task.taskStartTime = new Date().getTime();
12699         task.taskRunTime = 0;
12700         task.taskRunCount = 0;
12701         startThread();
12702         return task;
12703     };
12704
12705     this.stop = function(task){
12706         removeTask(task);
12707         return task;
12708     };
12709
12710     this.stopAll = function(){
12711         stopThread();
12712         for(var i = 0, len = tasks.length; i < len; i++){
12713             if(tasks[i].onStop){
12714                 tasks[i].onStop();
12715             }
12716         }
12717         tasks = [];
12718         removeQueue = [];
12719     };
12720 };
12721
12722 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12723  * Based on:
12724  * Ext JS Library 1.1.1
12725  * Copyright(c) 2006-2007, Ext JS, LLC.
12726  *
12727  * Originally Released Under LGPL - original licence link has changed is not relivant.
12728  *
12729  * Fork - LGPL
12730  * <script type="text/javascript">
12731  */
12732
12733  
12734 /**
12735  * @class Roo.util.MixedCollection
12736  * @extends Roo.util.Observable
12737  * A Collection class that maintains both numeric indexes and keys and exposes events.
12738  * @constructor
12739  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12740  * collection (defaults to false)
12741  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12742  * and return the key value for that item.  This is used when available to look up the key on items that
12743  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12744  * equivalent to providing an implementation for the {@link #getKey} method.
12745  */
12746 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12747     this.items = [];
12748     this.map = {};
12749     this.keys = [];
12750     this.length = 0;
12751     this.addEvents({
12752         /**
12753          * @event clear
12754          * Fires when the collection is cleared.
12755          */
12756         "clear" : true,
12757         /**
12758          * @event add
12759          * Fires when an item is added to the collection.
12760          * @param {Number} index The index at which the item was added.
12761          * @param {Object} o The item added.
12762          * @param {String} key The key associated with the added item.
12763          */
12764         "add" : true,
12765         /**
12766          * @event replace
12767          * Fires when an item is replaced in the collection.
12768          * @param {String} key he key associated with the new added.
12769          * @param {Object} old The item being replaced.
12770          * @param {Object} new The new item.
12771          */
12772         "replace" : true,
12773         /**
12774          * @event remove
12775          * Fires when an item is removed from the collection.
12776          * @param {Object} o The item being removed.
12777          * @param {String} key (optional) The key associated with the removed item.
12778          */
12779         "remove" : true,
12780         "sort" : true
12781     });
12782     this.allowFunctions = allowFunctions === true;
12783     if(keyFn){
12784         this.getKey = keyFn;
12785     }
12786     Roo.util.MixedCollection.superclass.constructor.call(this);
12787 };
12788
12789 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12790     allowFunctions : false,
12791     
12792 /**
12793  * Adds an item to the collection.
12794  * @param {String} key The key to associate with the item
12795  * @param {Object} o The item to add.
12796  * @return {Object} The item added.
12797  */
12798     add : function(key, o){
12799         if(arguments.length == 1){
12800             o = arguments[0];
12801             key = this.getKey(o);
12802         }
12803         if(typeof key == "undefined" || key === null){
12804             this.length++;
12805             this.items.push(o);
12806             this.keys.push(null);
12807         }else{
12808             var old = this.map[key];
12809             if(old){
12810                 return this.replace(key, o);
12811             }
12812             this.length++;
12813             this.items.push(o);
12814             this.map[key] = o;
12815             this.keys.push(key);
12816         }
12817         this.fireEvent("add", this.length-1, o, key);
12818         return o;
12819     },
12820        
12821 /**
12822   * MixedCollection has a generic way to fetch keys if you implement getKey.
12823 <pre><code>
12824 // normal way
12825 var mc = new Roo.util.MixedCollection();
12826 mc.add(someEl.dom.id, someEl);
12827 mc.add(otherEl.dom.id, otherEl);
12828 //and so on
12829
12830 // using getKey
12831 var mc = new Roo.util.MixedCollection();
12832 mc.getKey = function(el){
12833    return el.dom.id;
12834 };
12835 mc.add(someEl);
12836 mc.add(otherEl);
12837
12838 // or via the constructor
12839 var mc = new Roo.util.MixedCollection(false, function(el){
12840    return el.dom.id;
12841 });
12842 mc.add(someEl);
12843 mc.add(otherEl);
12844 </code></pre>
12845  * @param o {Object} The item for which to find the key.
12846  * @return {Object} The key for the passed item.
12847  */
12848     getKey : function(o){
12849          return o.id; 
12850     },
12851    
12852 /**
12853  * Replaces an item in the collection.
12854  * @param {String} key The key associated with the item to replace, or the item to replace.
12855  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12856  * @return {Object}  The new item.
12857  */
12858     replace : function(key, o){
12859         if(arguments.length == 1){
12860             o = arguments[0];
12861             key = this.getKey(o);
12862         }
12863         var old = this.item(key);
12864         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12865              return this.add(key, o);
12866         }
12867         var index = this.indexOfKey(key);
12868         this.items[index] = o;
12869         this.map[key] = o;
12870         this.fireEvent("replace", key, old, o);
12871         return o;
12872     },
12873    
12874 /**
12875  * Adds all elements of an Array or an Object to the collection.
12876  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12877  * an Array of values, each of which are added to the collection.
12878  */
12879     addAll : function(objs){
12880         if(arguments.length > 1 || objs instanceof Array){
12881             var args = arguments.length > 1 ? arguments : objs;
12882             for(var i = 0, len = args.length; i < len; i++){
12883                 this.add(args[i]);
12884             }
12885         }else{
12886             for(var key in objs){
12887                 if(this.allowFunctions || typeof objs[key] != "function"){
12888                     this.add(key, objs[key]);
12889                 }
12890             }
12891         }
12892     },
12893    
12894 /**
12895  * Executes the specified function once for every item in the collection, passing each
12896  * item as the first and only parameter. returning false from the function will stop the iteration.
12897  * @param {Function} fn The function to execute for each item.
12898  * @param {Object} scope (optional) The scope in which to execute the function.
12899  */
12900     each : function(fn, scope){
12901         var items = [].concat(this.items); // each safe for removal
12902         for(var i = 0, len = items.length; i < len; i++){
12903             if(fn.call(scope || items[i], items[i], i, len) === false){
12904                 break;
12905             }
12906         }
12907     },
12908    
12909 /**
12910  * Executes the specified function once for every key in the collection, passing each
12911  * key, and its associated item as the first two parameters.
12912  * @param {Function} fn The function to execute for each item.
12913  * @param {Object} scope (optional) The scope in which to execute the function.
12914  */
12915     eachKey : function(fn, scope){
12916         for(var i = 0, len = this.keys.length; i < len; i++){
12917             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12918         }
12919     },
12920    
12921 /**
12922  * Returns the first item in the collection which elicits a true return value from the
12923  * passed selection function.
12924  * @param {Function} fn The selection function to execute for each item.
12925  * @param {Object} scope (optional) The scope in which to execute the function.
12926  * @return {Object} The first item in the collection which returned true from the selection function.
12927  */
12928     find : function(fn, scope){
12929         for(var i = 0, len = this.items.length; i < len; i++){
12930             if(fn.call(scope || window, this.items[i], this.keys[i])){
12931                 return this.items[i];
12932             }
12933         }
12934         return null;
12935     },
12936    
12937 /**
12938  * Inserts an item at the specified index in the collection.
12939  * @param {Number} index The index to insert the item at.
12940  * @param {String} key The key to associate with the new item, or the item itself.
12941  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12942  * @return {Object} The item inserted.
12943  */
12944     insert : function(index, key, o){
12945         if(arguments.length == 2){
12946             o = arguments[1];
12947             key = this.getKey(o);
12948         }
12949         if(index >= this.length){
12950             return this.add(key, o);
12951         }
12952         this.length++;
12953         this.items.splice(index, 0, o);
12954         if(typeof key != "undefined" && key != null){
12955             this.map[key] = o;
12956         }
12957         this.keys.splice(index, 0, key);
12958         this.fireEvent("add", index, o, key);
12959         return o;
12960     },
12961    
12962 /**
12963  * Removed an item from the collection.
12964  * @param {Object} o The item to remove.
12965  * @return {Object} The item removed.
12966  */
12967     remove : function(o){
12968         return this.removeAt(this.indexOf(o));
12969     },
12970    
12971 /**
12972  * Remove an item from a specified index in the collection.
12973  * @param {Number} index The index within the collection of the item to remove.
12974  */
12975     removeAt : function(index){
12976         if(index < this.length && index >= 0){
12977             this.length--;
12978             var o = this.items[index];
12979             this.items.splice(index, 1);
12980             var key = this.keys[index];
12981             if(typeof key != "undefined"){
12982                 delete this.map[key];
12983             }
12984             this.keys.splice(index, 1);
12985             this.fireEvent("remove", o, key);
12986         }
12987     },
12988    
12989 /**
12990  * Removed an item associated with the passed key fom the collection.
12991  * @param {String} key The key of the item to remove.
12992  */
12993     removeKey : function(key){
12994         return this.removeAt(this.indexOfKey(key));
12995     },
12996    
12997 /**
12998  * Returns the number of items in the collection.
12999  * @return {Number} the number of items in the collection.
13000  */
13001     getCount : function(){
13002         return this.length; 
13003     },
13004    
13005 /**
13006  * Returns index within the collection of the passed Object.
13007  * @param {Object} o The item to find the index of.
13008  * @return {Number} index of the item.
13009  */
13010     indexOf : function(o){
13011         if(!this.items.indexOf){
13012             for(var i = 0, len = this.items.length; i < len; i++){
13013                 if(this.items[i] == o) return i;
13014             }
13015             return -1;
13016         }else{
13017             return this.items.indexOf(o);
13018         }
13019     },
13020    
13021 /**
13022  * Returns index within the collection of the passed key.
13023  * @param {String} key The key to find the index of.
13024  * @return {Number} index of the key.
13025  */
13026     indexOfKey : function(key){
13027         if(!this.keys.indexOf){
13028             for(var i = 0, len = this.keys.length; i < len; i++){
13029                 if(this.keys[i] == key) return i;
13030             }
13031             return -1;
13032         }else{
13033             return this.keys.indexOf(key);
13034         }
13035     },
13036    
13037 /**
13038  * Returns the item associated with the passed key OR index. Key has priority over index.
13039  * @param {String/Number} key The key or index of the item.
13040  * @return {Object} The item associated with the passed key.
13041  */
13042     item : function(key){
13043         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13044         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13045     },
13046     
13047 /**
13048  * Returns the item at the specified index.
13049  * @param {Number} index The index of the item.
13050  * @return {Object}
13051  */
13052     itemAt : function(index){
13053         return this.items[index];
13054     },
13055     
13056 /**
13057  * Returns the item associated with the passed key.
13058  * @param {String/Number} key The key of the item.
13059  * @return {Object} The item associated with the passed key.
13060  */
13061     key : function(key){
13062         return this.map[key];
13063     },
13064    
13065 /**
13066  * Returns true if the collection contains the passed Object as an item.
13067  * @param {Object} o  The Object to look for in the collection.
13068  * @return {Boolean} True if the collection contains the Object as an item.
13069  */
13070     contains : function(o){
13071         return this.indexOf(o) != -1;
13072     },
13073    
13074 /**
13075  * Returns true if the collection contains the passed Object as a key.
13076  * @param {String} key The key to look for in the collection.
13077  * @return {Boolean} True if the collection contains the Object as a key.
13078  */
13079     containsKey : function(key){
13080         return typeof this.map[key] != "undefined";
13081     },
13082    
13083 /**
13084  * Removes all items from the collection.
13085  */
13086     clear : function(){
13087         this.length = 0;
13088         this.items = [];
13089         this.keys = [];
13090         this.map = {};
13091         this.fireEvent("clear");
13092     },
13093    
13094 /**
13095  * Returns the first item in the collection.
13096  * @return {Object} the first item in the collection..
13097  */
13098     first : function(){
13099         return this.items[0]; 
13100     },
13101    
13102 /**
13103  * Returns the last item in the collection.
13104  * @return {Object} the last item in the collection..
13105  */
13106     last : function(){
13107         return this.items[this.length-1];   
13108     },
13109     
13110     _sort : function(property, dir, fn){
13111         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13112         fn = fn || function(a, b){
13113             return a-b;
13114         };
13115         var c = [], k = this.keys, items = this.items;
13116         for(var i = 0, len = items.length; i < len; i++){
13117             c[c.length] = {key: k[i], value: items[i], index: i};
13118         }
13119         c.sort(function(a, b){
13120             var v = fn(a[property], b[property]) * dsc;
13121             if(v == 0){
13122                 v = (a.index < b.index ? -1 : 1);
13123             }
13124             return v;
13125         });
13126         for(var i = 0, len = c.length; i < len; i++){
13127             items[i] = c[i].value;
13128             k[i] = c[i].key;
13129         }
13130         this.fireEvent("sort", this);
13131     },
13132     
13133     /**
13134      * Sorts this collection with the passed comparison function
13135      * @param {String} direction (optional) "ASC" or "DESC"
13136      * @param {Function} fn (optional) comparison function
13137      */
13138     sort : function(dir, fn){
13139         this._sort("value", dir, fn);
13140     },
13141     
13142     /**
13143      * Sorts this collection by keys
13144      * @param {String} direction (optional) "ASC" or "DESC"
13145      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13146      */
13147     keySort : function(dir, fn){
13148         this._sort("key", dir, fn || function(a, b){
13149             return String(a).toUpperCase()-String(b).toUpperCase();
13150         });
13151     },
13152     
13153     /**
13154      * Returns a range of items in this collection
13155      * @param {Number} startIndex (optional) defaults to 0
13156      * @param {Number} endIndex (optional) default to the last item
13157      * @return {Array} An array of items
13158      */
13159     getRange : function(start, end){
13160         var items = this.items;
13161         if(items.length < 1){
13162             return [];
13163         }
13164         start = start || 0;
13165         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13166         var r = [];
13167         if(start <= end){
13168             for(var i = start; i <= end; i++) {
13169                     r[r.length] = items[i];
13170             }
13171         }else{
13172             for(var i = start; i >= end; i--) {
13173                     r[r.length] = items[i];
13174             }
13175         }
13176         return r;
13177     },
13178         
13179     /**
13180      * Filter the <i>objects</i> in this collection by a specific property. 
13181      * Returns a new collection that has been filtered.
13182      * @param {String} property A property on your objects
13183      * @param {String/RegExp} value Either string that the property values 
13184      * should start with or a RegExp to test against the property
13185      * @return {MixedCollection} The new filtered collection
13186      */
13187     filter : function(property, value){
13188         if(!value.exec){ // not a regex
13189             value = String(value);
13190             if(value.length == 0){
13191                 return this.clone();
13192             }
13193             value = new RegExp("^" + Roo.escapeRe(value), "i");
13194         }
13195         return this.filterBy(function(o){
13196             return o && value.test(o[property]);
13197         });
13198         },
13199     
13200     /**
13201      * Filter by a function. * Returns a new collection that has been filtered.
13202      * The passed function will be called with each 
13203      * object in the collection. If the function returns true, the value is included 
13204      * otherwise it is filtered.
13205      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13206      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13207      * @return {MixedCollection} The new filtered collection
13208      */
13209     filterBy : function(fn, scope){
13210         var r = new Roo.util.MixedCollection();
13211         r.getKey = this.getKey;
13212         var k = this.keys, it = this.items;
13213         for(var i = 0, len = it.length; i < len; i++){
13214             if(fn.call(scope||this, it[i], k[i])){
13215                                 r.add(k[i], it[i]);
13216                         }
13217         }
13218         return r;
13219     },
13220     
13221     /**
13222      * Creates a duplicate of this collection
13223      * @return {MixedCollection}
13224      */
13225     clone : function(){
13226         var r = new Roo.util.MixedCollection();
13227         var k = this.keys, it = this.items;
13228         for(var i = 0, len = it.length; i < len; i++){
13229             r.add(k[i], it[i]);
13230         }
13231         r.getKey = this.getKey;
13232         return r;
13233     }
13234 });
13235 /**
13236  * Returns the item associated with the passed key or index.
13237  * @method
13238  * @param {String/Number} key The key or index of the item.
13239  * @return {Object} The item associated with the passed key.
13240  */
13241 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13242  * Based on:
13243  * Ext JS Library 1.1.1
13244  * Copyright(c) 2006-2007, Ext JS, LLC.
13245  *
13246  * Originally Released Under LGPL - original licence link has changed is not relivant.
13247  *
13248  * Fork - LGPL
13249  * <script type="text/javascript">
13250  */
13251 /**
13252  * @class Roo.util.JSON
13253  * Modified version of Douglas Crockford"s json.js that doesn"t
13254  * mess with the Object prototype 
13255  * http://www.json.org/js.html
13256  * @singleton
13257  */
13258 Roo.util.JSON = new (function(){
13259     var useHasOwn = {}.hasOwnProperty ? true : false;
13260     
13261     // crashes Safari in some instances
13262     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13263     
13264     var pad = function(n) {
13265         return n < 10 ? "0" + n : n;
13266     };
13267     
13268     var m = {
13269         "\b": '\\b',
13270         "\t": '\\t',
13271         "\n": '\\n',
13272         "\f": '\\f',
13273         "\r": '\\r',
13274         '"' : '\\"',
13275         "\\": '\\\\'
13276     };
13277
13278     var encodeString = function(s){
13279         if (/["\\\x00-\x1f]/.test(s)) {
13280             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13281                 var c = m[b];
13282                 if(c){
13283                     return c;
13284                 }
13285                 c = b.charCodeAt();
13286                 return "\\u00" +
13287                     Math.floor(c / 16).toString(16) +
13288                     (c % 16).toString(16);
13289             }) + '"';
13290         }
13291         return '"' + s + '"';
13292     };
13293     
13294     var encodeArray = function(o){
13295         var a = ["["], b, i, l = o.length, v;
13296             for (i = 0; i < l; i += 1) {
13297                 v = o[i];
13298                 switch (typeof v) {
13299                     case "undefined":
13300                     case "function":
13301                     case "unknown":
13302                         break;
13303                     default:
13304                         if (b) {
13305                             a.push(',');
13306                         }
13307                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13308                         b = true;
13309                 }
13310             }
13311             a.push("]");
13312             return a.join("");
13313     };
13314     
13315     var encodeDate = function(o){
13316         return '"' + o.getFullYear() + "-" +
13317                 pad(o.getMonth() + 1) + "-" +
13318                 pad(o.getDate()) + "T" +
13319                 pad(o.getHours()) + ":" +
13320                 pad(o.getMinutes()) + ":" +
13321                 pad(o.getSeconds()) + '"';
13322     };
13323     
13324     /**
13325      * Encodes an Object, Array or other value
13326      * @param {Mixed} o The variable to encode
13327      * @return {String} The JSON string
13328      */
13329     this.encode = function(o)
13330     {
13331         // should this be extended to fully wrap stringify..
13332         
13333         if(typeof o == "undefined" || o === null){
13334             return "null";
13335         }else if(o instanceof Array){
13336             return encodeArray(o);
13337         }else if(o instanceof Date){
13338             return encodeDate(o);
13339         }else if(typeof o == "string"){
13340             return encodeString(o);
13341         }else if(typeof o == "number"){
13342             return isFinite(o) ? String(o) : "null";
13343         }else if(typeof o == "boolean"){
13344             return String(o);
13345         }else {
13346             var a = ["{"], b, i, v;
13347             for (i in o) {
13348                 if(!useHasOwn || o.hasOwnProperty(i)) {
13349                     v = o[i];
13350                     switch (typeof v) {
13351                     case "undefined":
13352                     case "function":
13353                     case "unknown":
13354                         break;
13355                     default:
13356                         if(b){
13357                             a.push(',');
13358                         }
13359                         a.push(this.encode(i), ":",
13360                                 v === null ? "null" : this.encode(v));
13361                         b = true;
13362                     }
13363                 }
13364             }
13365             a.push("}");
13366             return a.join("");
13367         }
13368     };
13369     
13370     /**
13371      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13372      * @param {String} json The JSON string
13373      * @return {Object} The resulting object
13374      */
13375     this.decode = function(json){
13376         
13377         return  /** eval:var:json */ eval("(" + json + ')');
13378     };
13379 })();
13380 /** 
13381  * Shorthand for {@link Roo.util.JSON#encode}
13382  * @member Roo encode 
13383  * @method */
13384 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13385 /** 
13386  * Shorthand for {@link Roo.util.JSON#decode}
13387  * @member Roo decode 
13388  * @method */
13389 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13390 /*
13391  * Based on:
13392  * Ext JS Library 1.1.1
13393  * Copyright(c) 2006-2007, Ext JS, LLC.
13394  *
13395  * Originally Released Under LGPL - original licence link has changed is not relivant.
13396  *
13397  * Fork - LGPL
13398  * <script type="text/javascript">
13399  */
13400  
13401 /**
13402  * @class Roo.util.Format
13403  * Reusable data formatting functions
13404  * @singleton
13405  */
13406 Roo.util.Format = function(){
13407     var trimRe = /^\s+|\s+$/g;
13408     return {
13409         /**
13410          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13411          * @param {String} value The string to truncate
13412          * @param {Number} length The maximum length to allow before truncating
13413          * @return {String} The converted text
13414          */
13415         ellipsis : function(value, len){
13416             if(value && value.length > len){
13417                 return value.substr(0, len-3)+"...";
13418             }
13419             return value;
13420         },
13421
13422         /**
13423          * Checks a reference and converts it to empty string if it is undefined
13424          * @param {Mixed} value Reference to check
13425          * @return {Mixed} Empty string if converted, otherwise the original value
13426          */
13427         undef : function(value){
13428             return typeof value != "undefined" ? value : "";
13429         },
13430
13431         /**
13432          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13433          * @param {String} value The string to encode
13434          * @return {String} The encoded text
13435          */
13436         htmlEncode : function(value){
13437             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13438         },
13439
13440         /**
13441          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13442          * @param {String} value The string to decode
13443          * @return {String} The decoded text
13444          */
13445         htmlDecode : function(value){
13446             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13447         },
13448
13449         /**
13450          * Trims any whitespace from either side of a string
13451          * @param {String} value The text to trim
13452          * @return {String} The trimmed text
13453          */
13454         trim : function(value){
13455             return String(value).replace(trimRe, "");
13456         },
13457
13458         /**
13459          * Returns a substring from within an original string
13460          * @param {String} value The original text
13461          * @param {Number} start The start index of the substring
13462          * @param {Number} length The length of the substring
13463          * @return {String} The substring
13464          */
13465         substr : function(value, start, length){
13466             return String(value).substr(start, length);
13467         },
13468
13469         /**
13470          * Converts a string to all lower case letters
13471          * @param {String} value The text to convert
13472          * @return {String} The converted text
13473          */
13474         lowercase : function(value){
13475             return String(value).toLowerCase();
13476         },
13477
13478         /**
13479          * Converts a string to all upper case letters
13480          * @param {String} value The text to convert
13481          * @return {String} The converted text
13482          */
13483         uppercase : function(value){
13484             return String(value).toUpperCase();
13485         },
13486
13487         /**
13488          * Converts the first character only of a string to upper case
13489          * @param {String} value The text to convert
13490          * @return {String} The converted text
13491          */
13492         capitalize : function(value){
13493             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13494         },
13495
13496         // private
13497         call : function(value, fn){
13498             if(arguments.length > 2){
13499                 var args = Array.prototype.slice.call(arguments, 2);
13500                 args.unshift(value);
13501                  
13502                 return /** eval:var:value */  eval(fn).apply(window, args);
13503             }else{
13504                 /** eval:var:value */
13505                 return /** eval:var:value */ eval(fn).call(window, value);
13506             }
13507         },
13508
13509        
13510         /**
13511          * safer version of Math.toFixed..??/
13512          * @param {Number/String} value The numeric value to format
13513          * @param {Number/String} value Decimal places 
13514          * @return {String} The formatted currency string
13515          */
13516         toFixed : function(v, n)
13517         {
13518             // why not use to fixed - precision is buggered???
13519             if (!n) {
13520                 return Math.round(v-0);
13521             }
13522             var fact = Math.pow(10,n+1);
13523             v = (Math.round((v-0)*fact))/fact;
13524             var z = (''+fact).substring(2);
13525             if (v == Math.floor(v)) {
13526                 return Math.floor(v) + '.' + z;
13527             }
13528             
13529             // now just padd decimals..
13530             var ps = String(v).split('.');
13531             var fd = (ps[1] + z);
13532             var r = fd.substring(0,n); 
13533             var rm = fd.substring(n); 
13534             if (rm < 5) {
13535                 return ps[0] + '.' + r;
13536             }
13537             r*=1; // turn it into a number;
13538             r++;
13539             if (String(r).length != n) {
13540                 ps[0]*=1;
13541                 ps[0]++;
13542                 r = String(r).substring(1); // chop the end off.
13543             }
13544             
13545             return ps[0] + '.' + r;
13546              
13547         },
13548         
13549         /**
13550          * Format a number as US currency
13551          * @param {Number/String} value The numeric value to format
13552          * @return {String} The formatted currency string
13553          */
13554         usMoney : function(v){
13555             return '$' + Roo.util.Format.number(v);
13556         },
13557         
13558         /**
13559          * Format a number
13560          * eventually this should probably emulate php's number_format
13561          * @param {Number/String} value The numeric value to format
13562          * @param {Number} decimals number of decimal places
13563          * @return {String} The formatted currency string
13564          */
13565         number : function(v,decimals)
13566         {
13567             // multiply and round.
13568             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13569             var mul = Math.pow(10, decimals);
13570             var zero = String(mul).substring(1);
13571             v = (Math.round((v-0)*mul))/mul;
13572             
13573             // if it's '0' number.. then
13574             
13575             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13576             v = String(v);
13577             var ps = v.split('.');
13578             var whole = ps[0];
13579             
13580             
13581             var r = /(\d+)(\d{3})/;
13582             // add comma's
13583             while (r.test(whole)) {
13584                 whole = whole.replace(r, '$1' + ',' + '$2');
13585             }
13586             
13587             
13588             var sub = ps[1] ?
13589                     // has decimals..
13590                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13591                     // does not have decimals
13592                     (decimals ? ('.' + zero) : '');
13593             
13594             
13595             return whole + sub ;
13596         },
13597         
13598         /**
13599          * Parse a value into a formatted date using the specified format pattern.
13600          * @param {Mixed} value The value to format
13601          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13602          * @return {String} The formatted date string
13603          */
13604         date : function(v, format){
13605             if(!v){
13606                 return "";
13607             }
13608             if(!(v instanceof Date)){
13609                 v = new Date(Date.parse(v));
13610             }
13611             return v.dateFormat(format || Roo.util.Format.defaults.date);
13612         },
13613
13614         /**
13615          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13616          * @param {String} format Any valid date format string
13617          * @return {Function} The date formatting function
13618          */
13619         dateRenderer : function(format){
13620             return function(v){
13621                 return Roo.util.Format.date(v, format);  
13622             };
13623         },
13624
13625         // private
13626         stripTagsRE : /<\/?[^>]+>/gi,
13627         
13628         /**
13629          * Strips all HTML tags
13630          * @param {Mixed} value The text from which to strip tags
13631          * @return {String} The stripped text
13632          */
13633         stripTags : function(v){
13634             return !v ? v : String(v).replace(this.stripTagsRE, "");
13635         }
13636     };
13637 }();
13638 Roo.util.Format.defaults = {
13639     date : 'd/M/Y'
13640 };/*
13641  * Based on:
13642  * Ext JS Library 1.1.1
13643  * Copyright(c) 2006-2007, Ext JS, LLC.
13644  *
13645  * Originally Released Under LGPL - original licence link has changed is not relivant.
13646  *
13647  * Fork - LGPL
13648  * <script type="text/javascript">
13649  */
13650
13651
13652  
13653
13654 /**
13655  * @class Roo.MasterTemplate
13656  * @extends Roo.Template
13657  * Provides a template that can have child templates. The syntax is:
13658 <pre><code>
13659 var t = new Roo.MasterTemplate(
13660         '&lt;select name="{name}"&gt;',
13661                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13662         '&lt;/select&gt;'
13663 );
13664 t.add('options', {value: 'foo', text: 'bar'});
13665 // or you can add multiple child elements in one shot
13666 t.addAll('options', [
13667     {value: 'foo', text: 'bar'},
13668     {value: 'foo2', text: 'bar2'},
13669     {value: 'foo3', text: 'bar3'}
13670 ]);
13671 // then append, applying the master template values
13672 t.append('my-form', {name: 'my-select'});
13673 </code></pre>
13674 * A name attribute for the child template is not required if you have only one child
13675 * template or you want to refer to them by index.
13676  */
13677 Roo.MasterTemplate = function(){
13678     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13679     this.originalHtml = this.html;
13680     var st = {};
13681     var m, re = this.subTemplateRe;
13682     re.lastIndex = 0;
13683     var subIndex = 0;
13684     while(m = re.exec(this.html)){
13685         var name = m[1], content = m[2];
13686         st[subIndex] = {
13687             name: name,
13688             index: subIndex,
13689             buffer: [],
13690             tpl : new Roo.Template(content)
13691         };
13692         if(name){
13693             st[name] = st[subIndex];
13694         }
13695         st[subIndex].tpl.compile();
13696         st[subIndex].tpl.call = this.call.createDelegate(this);
13697         subIndex++;
13698     }
13699     this.subCount = subIndex;
13700     this.subs = st;
13701 };
13702 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13703     /**
13704     * The regular expression used to match sub templates
13705     * @type RegExp
13706     * @property
13707     */
13708     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13709
13710     /**
13711      * Applies the passed values to a child template.
13712      * @param {String/Number} name (optional) The name or index of the child template
13713      * @param {Array/Object} values The values to be applied to the template
13714      * @return {MasterTemplate} this
13715      */
13716      add : function(name, values){
13717         if(arguments.length == 1){
13718             values = arguments[0];
13719             name = 0;
13720         }
13721         var s = this.subs[name];
13722         s.buffer[s.buffer.length] = s.tpl.apply(values);
13723         return this;
13724     },
13725
13726     /**
13727      * Applies all the passed values to a child template.
13728      * @param {String/Number} name (optional) The name or index of the child template
13729      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13730      * @param {Boolean} reset (optional) True to reset the template first
13731      * @return {MasterTemplate} this
13732      */
13733     fill : function(name, values, reset){
13734         var a = arguments;
13735         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13736             values = a[0];
13737             name = 0;
13738             reset = a[1];
13739         }
13740         if(reset){
13741             this.reset();
13742         }
13743         for(var i = 0, len = values.length; i < len; i++){
13744             this.add(name, values[i]);
13745         }
13746         return this;
13747     },
13748
13749     /**
13750      * Resets the template for reuse
13751      * @return {MasterTemplate} this
13752      */
13753      reset : function(){
13754         var s = this.subs;
13755         for(var i = 0; i < this.subCount; i++){
13756             s[i].buffer = [];
13757         }
13758         return this;
13759     },
13760
13761     applyTemplate : function(values){
13762         var s = this.subs;
13763         var replaceIndex = -1;
13764         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13765             return s[++replaceIndex].buffer.join("");
13766         });
13767         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13768     },
13769
13770     apply : function(){
13771         return this.applyTemplate.apply(this, arguments);
13772     },
13773
13774     compile : function(){return this;}
13775 });
13776
13777 /**
13778  * Alias for fill().
13779  * @method
13780  */
13781 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13782  /**
13783  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13784  * var tpl = Roo.MasterTemplate.from('element-id');
13785  * @param {String/HTMLElement} el
13786  * @param {Object} config
13787  * @static
13788  */
13789 Roo.MasterTemplate.from = function(el, config){
13790     el = Roo.getDom(el);
13791     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13792 };/*
13793  * Based on:
13794  * Ext JS Library 1.1.1
13795  * Copyright(c) 2006-2007, Ext JS, LLC.
13796  *
13797  * Originally Released Under LGPL - original licence link has changed is not relivant.
13798  *
13799  * Fork - LGPL
13800  * <script type="text/javascript">
13801  */
13802
13803  
13804 /**
13805  * @class Roo.util.CSS
13806  * Utility class for manipulating CSS rules
13807  * @singleton
13808  */
13809 Roo.util.CSS = function(){
13810         var rules = null;
13811         var doc = document;
13812
13813     var camelRe = /(-[a-z])/gi;
13814     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13815
13816    return {
13817    /**
13818     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13819     * tag and appended to the HEAD of the document.
13820     * @param {String|Object} cssText The text containing the css rules
13821     * @param {String} id An id to add to the stylesheet for later removal
13822     * @return {StyleSheet}
13823     */
13824     createStyleSheet : function(cssText, id){
13825         var ss;
13826         var head = doc.getElementsByTagName("head")[0];
13827         var nrules = doc.createElement("style");
13828         nrules.setAttribute("type", "text/css");
13829         if(id){
13830             nrules.setAttribute("id", id);
13831         }
13832         if (typeof(cssText) != 'string') {
13833             // support object maps..
13834             // not sure if this a good idea.. 
13835             // perhaps it should be merged with the general css handling
13836             // and handle js style props.
13837             var cssTextNew = [];
13838             for(var n in cssText) {
13839                 var citems = [];
13840                 for(var k in cssText[n]) {
13841                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13842                 }
13843                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13844                 
13845             }
13846             cssText = cssTextNew.join("\n");
13847             
13848         }
13849        
13850        
13851        if(Roo.isIE){
13852            head.appendChild(nrules);
13853            ss = nrules.styleSheet;
13854            ss.cssText = cssText;
13855        }else{
13856            try{
13857                 nrules.appendChild(doc.createTextNode(cssText));
13858            }catch(e){
13859                nrules.cssText = cssText; 
13860            }
13861            head.appendChild(nrules);
13862            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13863        }
13864        this.cacheStyleSheet(ss);
13865        return ss;
13866    },
13867
13868    /**
13869     * Removes a style or link tag by id
13870     * @param {String} id The id of the tag
13871     */
13872    removeStyleSheet : function(id){
13873        var existing = doc.getElementById(id);
13874        if(existing){
13875            existing.parentNode.removeChild(existing);
13876        }
13877    },
13878
13879    /**
13880     * Dynamically swaps an existing stylesheet reference for a new one
13881     * @param {String} id The id of an existing link tag to remove
13882     * @param {String} url The href of the new stylesheet to include
13883     */
13884    swapStyleSheet : function(id, url){
13885        this.removeStyleSheet(id);
13886        var ss = doc.createElement("link");
13887        ss.setAttribute("rel", "stylesheet");
13888        ss.setAttribute("type", "text/css");
13889        ss.setAttribute("id", id);
13890        ss.setAttribute("href", url);
13891        doc.getElementsByTagName("head")[0].appendChild(ss);
13892    },
13893    
13894    /**
13895     * Refresh the rule cache if you have dynamically added stylesheets
13896     * @return {Object} An object (hash) of rules indexed by selector
13897     */
13898    refreshCache : function(){
13899        return this.getRules(true);
13900    },
13901
13902    // private
13903    cacheStyleSheet : function(stylesheet){
13904        if(!rules){
13905            rules = {};
13906        }
13907        try{// try catch for cross domain access issue
13908            var ssRules = stylesheet.cssRules || stylesheet.rules;
13909            for(var j = ssRules.length-1; j >= 0; --j){
13910                rules[ssRules[j].selectorText] = ssRules[j];
13911            }
13912        }catch(e){}
13913    },
13914    
13915    /**
13916     * Gets all css rules for the document
13917     * @param {Boolean} refreshCache true to refresh the internal cache
13918     * @return {Object} An object (hash) of rules indexed by selector
13919     */
13920    getRules : function(refreshCache){
13921                 if(rules == null || refreshCache){
13922                         rules = {};
13923                         var ds = doc.styleSheets;
13924                         for(var i =0, len = ds.length; i < len; i++){
13925                             try{
13926                         this.cacheStyleSheet(ds[i]);
13927                     }catch(e){} 
13928                 }
13929                 }
13930                 return rules;
13931         },
13932         
13933         /**
13934     * Gets an an individual CSS rule by selector(s)
13935     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13936     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13937     * @return {CSSRule} The CSS rule or null if one is not found
13938     */
13939    getRule : function(selector, refreshCache){
13940                 var rs = this.getRules(refreshCache);
13941                 if(!(selector instanceof Array)){
13942                     return rs[selector];
13943                 }
13944                 for(var i = 0; i < selector.length; i++){
13945                         if(rs[selector[i]]){
13946                                 return rs[selector[i]];
13947                         }
13948                 }
13949                 return null;
13950         },
13951         
13952         
13953         /**
13954     * Updates a rule property
13955     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13956     * @param {String} property The css property
13957     * @param {String} value The new value for the property
13958     * @return {Boolean} true If a rule was found and updated
13959     */
13960    updateRule : function(selector, property, value){
13961                 if(!(selector instanceof Array)){
13962                         var rule = this.getRule(selector);
13963                         if(rule){
13964                                 rule.style[property.replace(camelRe, camelFn)] = value;
13965                                 return true;
13966                         }
13967                 }else{
13968                         for(var i = 0; i < selector.length; i++){
13969                                 if(this.updateRule(selector[i], property, value)){
13970                                         return true;
13971                                 }
13972                         }
13973                 }
13974                 return false;
13975         }
13976    };   
13977 }();/*
13978  * Based on:
13979  * Ext JS Library 1.1.1
13980  * Copyright(c) 2006-2007, Ext JS, LLC.
13981  *
13982  * Originally Released Under LGPL - original licence link has changed is not relivant.
13983  *
13984  * Fork - LGPL
13985  * <script type="text/javascript">
13986  */
13987
13988  
13989
13990 /**
13991  * @class Roo.util.ClickRepeater
13992  * @extends Roo.util.Observable
13993  * 
13994  * A wrapper class which can be applied to any element. Fires a "click" event while the
13995  * mouse is pressed. The interval between firings may be specified in the config but
13996  * defaults to 10 milliseconds.
13997  * 
13998  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13999  * 
14000  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14001  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14002  * Similar to an autorepeat key delay.
14003  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14004  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14005  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14006  *           "interval" and "delay" are ignored. "immediate" is honored.
14007  * @cfg {Boolean} preventDefault True to prevent the default click event
14008  * @cfg {Boolean} stopDefault True to stop the default click event
14009  * 
14010  * @history
14011  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14012  *     2007-02-02 jvs Renamed to ClickRepeater
14013  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14014  *
14015  *  @constructor
14016  * @param {String/HTMLElement/Element} el The element to listen on
14017  * @param {Object} config
14018  **/
14019 Roo.util.ClickRepeater = function(el, config)
14020 {
14021     this.el = Roo.get(el);
14022     this.el.unselectable();
14023
14024     Roo.apply(this, config);
14025
14026     this.addEvents({
14027     /**
14028      * @event mousedown
14029      * Fires when the mouse button is depressed.
14030      * @param {Roo.util.ClickRepeater} this
14031      */
14032         "mousedown" : true,
14033     /**
14034      * @event click
14035      * Fires on a specified interval during the time the element is pressed.
14036      * @param {Roo.util.ClickRepeater} this
14037      */
14038         "click" : true,
14039     /**
14040      * @event mouseup
14041      * Fires when the mouse key is released.
14042      * @param {Roo.util.ClickRepeater} this
14043      */
14044         "mouseup" : true
14045     });
14046
14047     this.el.on("mousedown", this.handleMouseDown, this);
14048     if(this.preventDefault || this.stopDefault){
14049         this.el.on("click", function(e){
14050             if(this.preventDefault){
14051                 e.preventDefault();
14052             }
14053             if(this.stopDefault){
14054                 e.stopEvent();
14055             }
14056         }, this);
14057     }
14058
14059     // allow inline handler
14060     if(this.handler){
14061         this.on("click", this.handler,  this.scope || this);
14062     }
14063
14064     Roo.util.ClickRepeater.superclass.constructor.call(this);
14065 };
14066
14067 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14068     interval : 20,
14069     delay: 250,
14070     preventDefault : true,
14071     stopDefault : false,
14072     timer : 0,
14073
14074     // private
14075     handleMouseDown : function(){
14076         clearTimeout(this.timer);
14077         this.el.blur();
14078         if(this.pressClass){
14079             this.el.addClass(this.pressClass);
14080         }
14081         this.mousedownTime = new Date();
14082
14083         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14084         this.el.on("mouseout", this.handleMouseOut, this);
14085
14086         this.fireEvent("mousedown", this);
14087         this.fireEvent("click", this);
14088         
14089         this.timer = this.click.defer(this.delay || this.interval, this);
14090     },
14091
14092     // private
14093     click : function(){
14094         this.fireEvent("click", this);
14095         this.timer = this.click.defer(this.getInterval(), this);
14096     },
14097
14098     // private
14099     getInterval: function(){
14100         if(!this.accelerate){
14101             return this.interval;
14102         }
14103         var pressTime = this.mousedownTime.getElapsed();
14104         if(pressTime < 500){
14105             return 400;
14106         }else if(pressTime < 1700){
14107             return 320;
14108         }else if(pressTime < 2600){
14109             return 250;
14110         }else if(pressTime < 3500){
14111             return 180;
14112         }else if(pressTime < 4400){
14113             return 140;
14114         }else if(pressTime < 5300){
14115             return 80;
14116         }else if(pressTime < 6200){
14117             return 50;
14118         }else{
14119             return 10;
14120         }
14121     },
14122
14123     // private
14124     handleMouseOut : function(){
14125         clearTimeout(this.timer);
14126         if(this.pressClass){
14127             this.el.removeClass(this.pressClass);
14128         }
14129         this.el.on("mouseover", this.handleMouseReturn, this);
14130     },
14131
14132     // private
14133     handleMouseReturn : function(){
14134         this.el.un("mouseover", this.handleMouseReturn);
14135         if(this.pressClass){
14136             this.el.addClass(this.pressClass);
14137         }
14138         this.click();
14139     },
14140
14141     // private
14142     handleMouseUp : function(){
14143         clearTimeout(this.timer);
14144         this.el.un("mouseover", this.handleMouseReturn);
14145         this.el.un("mouseout", this.handleMouseOut);
14146         Roo.get(document).un("mouseup", this.handleMouseUp);
14147         this.el.removeClass(this.pressClass);
14148         this.fireEvent("mouseup", this);
14149     }
14150 });/*
14151  * Based on:
14152  * Ext JS Library 1.1.1
14153  * Copyright(c) 2006-2007, Ext JS, LLC.
14154  *
14155  * Originally Released Under LGPL - original licence link has changed is not relivant.
14156  *
14157  * Fork - LGPL
14158  * <script type="text/javascript">
14159  */
14160
14161  
14162 /**
14163  * @class Roo.KeyNav
14164  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14165  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14166  * way to implement custom navigation schemes for any UI component.</p>
14167  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14168  * pageUp, pageDown, del, home, end.  Usage:</p>
14169  <pre><code>
14170 var nav = new Roo.KeyNav("my-element", {
14171     "left" : function(e){
14172         this.moveLeft(e.ctrlKey);
14173     },
14174     "right" : function(e){
14175         this.moveRight(e.ctrlKey);
14176     },
14177     "enter" : function(e){
14178         this.save();
14179     },
14180     scope : this
14181 });
14182 </code></pre>
14183  * @constructor
14184  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14185  * @param {Object} config The config
14186  */
14187 Roo.KeyNav = function(el, config){
14188     this.el = Roo.get(el);
14189     Roo.apply(this, config);
14190     if(!this.disabled){
14191         this.disabled = true;
14192         this.enable();
14193     }
14194 };
14195
14196 Roo.KeyNav.prototype = {
14197     /**
14198      * @cfg {Boolean} disabled
14199      * True to disable this KeyNav instance (defaults to false)
14200      */
14201     disabled : false,
14202     /**
14203      * @cfg {String} defaultEventAction
14204      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14205      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14206      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14207      */
14208     defaultEventAction: "stopEvent",
14209     /**
14210      * @cfg {Boolean} forceKeyDown
14211      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14212      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14213      * handle keydown instead of keypress.
14214      */
14215     forceKeyDown : false,
14216
14217     // private
14218     prepareEvent : function(e){
14219         var k = e.getKey();
14220         var h = this.keyToHandler[k];
14221         //if(h && this[h]){
14222         //    e.stopPropagation();
14223         //}
14224         if(Roo.isSafari && h && k >= 37 && k <= 40){
14225             e.stopEvent();
14226         }
14227     },
14228
14229     // private
14230     relay : function(e){
14231         var k = e.getKey();
14232         var h = this.keyToHandler[k];
14233         if(h && this[h]){
14234             if(this.doRelay(e, this[h], h) !== true){
14235                 e[this.defaultEventAction]();
14236             }
14237         }
14238     },
14239
14240     // private
14241     doRelay : function(e, h, hname){
14242         return h.call(this.scope || this, e);
14243     },
14244
14245     // possible handlers
14246     enter : false,
14247     left : false,
14248     right : false,
14249     up : false,
14250     down : false,
14251     tab : false,
14252     esc : false,
14253     pageUp : false,
14254     pageDown : false,
14255     del : false,
14256     home : false,
14257     end : false,
14258
14259     // quick lookup hash
14260     keyToHandler : {
14261         37 : "left",
14262         39 : "right",
14263         38 : "up",
14264         40 : "down",
14265         33 : "pageUp",
14266         34 : "pageDown",
14267         46 : "del",
14268         36 : "home",
14269         35 : "end",
14270         13 : "enter",
14271         27 : "esc",
14272         9  : "tab"
14273     },
14274
14275         /**
14276          * Enable this KeyNav
14277          */
14278         enable: function(){
14279                 if(this.disabled){
14280             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14281             // the EventObject will normalize Safari automatically
14282             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14283                 this.el.on("keydown", this.relay,  this);
14284             }else{
14285                 this.el.on("keydown", this.prepareEvent,  this);
14286                 this.el.on("keypress", this.relay,  this);
14287             }
14288                     this.disabled = false;
14289                 }
14290         },
14291
14292         /**
14293          * Disable this KeyNav
14294          */
14295         disable: function(){
14296                 if(!this.disabled){
14297                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14298                 this.el.un("keydown", this.relay);
14299             }else{
14300                 this.el.un("keydown", this.prepareEvent);
14301                 this.el.un("keypress", this.relay);
14302             }
14303                     this.disabled = true;
14304                 }
14305         }
14306 };/*
14307  * Based on:
14308  * Ext JS Library 1.1.1
14309  * Copyright(c) 2006-2007, Ext JS, LLC.
14310  *
14311  * Originally Released Under LGPL - original licence link has changed is not relivant.
14312  *
14313  * Fork - LGPL
14314  * <script type="text/javascript">
14315  */
14316
14317  
14318 /**
14319  * @class Roo.KeyMap
14320  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14321  * The constructor accepts the same config object as defined by {@link #addBinding}.
14322  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14323  * combination it will call the function with this signature (if the match is a multi-key
14324  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14325  * A KeyMap can also handle a string representation of keys.<br />
14326  * Usage:
14327  <pre><code>
14328 // map one key by key code
14329 var map = new Roo.KeyMap("my-element", {
14330     key: 13, // or Roo.EventObject.ENTER
14331     fn: myHandler,
14332     scope: myObject
14333 });
14334
14335 // map multiple keys to one action by string
14336 var map = new Roo.KeyMap("my-element", {
14337     key: "a\r\n\t",
14338     fn: myHandler,
14339     scope: myObject
14340 });
14341
14342 // map multiple keys to multiple actions by strings and array of codes
14343 var map = new Roo.KeyMap("my-element", [
14344     {
14345         key: [10,13],
14346         fn: function(){ alert("Return was pressed"); }
14347     }, {
14348         key: "abc",
14349         fn: function(){ alert('a, b or c was pressed'); }
14350     }, {
14351         key: "\t",
14352         ctrl:true,
14353         shift:true,
14354         fn: function(){ alert('Control + shift + tab was pressed.'); }
14355     }
14356 ]);
14357 </code></pre>
14358  * <b>Note: A KeyMap starts enabled</b>
14359  * @constructor
14360  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14361  * @param {Object} config The config (see {@link #addBinding})
14362  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14363  */
14364 Roo.KeyMap = function(el, config, eventName){
14365     this.el  = Roo.get(el);
14366     this.eventName = eventName || "keydown";
14367     this.bindings = [];
14368     if(config){
14369         this.addBinding(config);
14370     }
14371     this.enable();
14372 };
14373
14374 Roo.KeyMap.prototype = {
14375     /**
14376      * True to stop the event from bubbling and prevent the default browser action if the
14377      * key was handled by the KeyMap (defaults to false)
14378      * @type Boolean
14379      */
14380     stopEvent : false,
14381
14382     /**
14383      * Add a new binding to this KeyMap. The following config object properties are supported:
14384      * <pre>
14385 Property    Type             Description
14386 ----------  ---------------  ----------------------------------------------------------------------
14387 key         String/Array     A single keycode or an array of keycodes to handle
14388 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14389 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14390 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14391 fn          Function         The function to call when KeyMap finds the expected key combination
14392 scope       Object           The scope of the callback function
14393 </pre>
14394      *
14395      * Usage:
14396      * <pre><code>
14397 // Create a KeyMap
14398 var map = new Roo.KeyMap(document, {
14399     key: Roo.EventObject.ENTER,
14400     fn: handleKey,
14401     scope: this
14402 });
14403
14404 //Add a new binding to the existing KeyMap later
14405 map.addBinding({
14406     key: 'abc',
14407     shift: true,
14408     fn: handleKey,
14409     scope: this
14410 });
14411 </code></pre>
14412      * @param {Object/Array} config A single KeyMap config or an array of configs
14413      */
14414         addBinding : function(config){
14415         if(config instanceof Array){
14416             for(var i = 0, len = config.length; i < len; i++){
14417                 this.addBinding(config[i]);
14418             }
14419             return;
14420         }
14421         var keyCode = config.key,
14422             shift = config.shift, 
14423             ctrl = config.ctrl, 
14424             alt = config.alt,
14425             fn = config.fn,
14426             scope = config.scope;
14427         if(typeof keyCode == "string"){
14428             var ks = [];
14429             var keyString = keyCode.toUpperCase();
14430             for(var j = 0, len = keyString.length; j < len; j++){
14431                 ks.push(keyString.charCodeAt(j));
14432             }
14433             keyCode = ks;
14434         }
14435         var keyArray = keyCode instanceof Array;
14436         var handler = function(e){
14437             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14438                 var k = e.getKey();
14439                 if(keyArray){
14440                     for(var i = 0, len = keyCode.length; i < len; i++){
14441                         if(keyCode[i] == k){
14442                           if(this.stopEvent){
14443                               e.stopEvent();
14444                           }
14445                           fn.call(scope || window, k, e);
14446                           return;
14447                         }
14448                     }
14449                 }else{
14450                     if(k == keyCode){
14451                         if(this.stopEvent){
14452                            e.stopEvent();
14453                         }
14454                         fn.call(scope || window, k, e);
14455                     }
14456                 }
14457             }
14458         };
14459         this.bindings.push(handler);  
14460         },
14461
14462     /**
14463      * Shorthand for adding a single key listener
14464      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14465      * following options:
14466      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14467      * @param {Function} fn The function to call
14468      * @param {Object} scope (optional) The scope of the function
14469      */
14470     on : function(key, fn, scope){
14471         var keyCode, shift, ctrl, alt;
14472         if(typeof key == "object" && !(key instanceof Array)){
14473             keyCode = key.key;
14474             shift = key.shift;
14475             ctrl = key.ctrl;
14476             alt = key.alt;
14477         }else{
14478             keyCode = key;
14479         }
14480         this.addBinding({
14481             key: keyCode,
14482             shift: shift,
14483             ctrl: ctrl,
14484             alt: alt,
14485             fn: fn,
14486             scope: scope
14487         })
14488     },
14489
14490     // private
14491     handleKeyDown : function(e){
14492             if(this.enabled){ //just in case
14493             var b = this.bindings;
14494             for(var i = 0, len = b.length; i < len; i++){
14495                 b[i].call(this, e);
14496             }
14497             }
14498         },
14499         
14500         /**
14501          * Returns true if this KeyMap is enabled
14502          * @return {Boolean} 
14503          */
14504         isEnabled : function(){
14505             return this.enabled;  
14506         },
14507         
14508         /**
14509          * Enables this KeyMap
14510          */
14511         enable: function(){
14512                 if(!this.enabled){
14513                     this.el.on(this.eventName, this.handleKeyDown, this);
14514                     this.enabled = true;
14515                 }
14516         },
14517
14518         /**
14519          * Disable this KeyMap
14520          */
14521         disable: function(){
14522                 if(this.enabled){
14523                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14524                     this.enabled = false;
14525                 }
14526         }
14527 };/*
14528  * Based on:
14529  * Ext JS Library 1.1.1
14530  * Copyright(c) 2006-2007, Ext JS, LLC.
14531  *
14532  * Originally Released Under LGPL - original licence link has changed is not relivant.
14533  *
14534  * Fork - LGPL
14535  * <script type="text/javascript">
14536  */
14537
14538  
14539 /**
14540  * @class Roo.util.TextMetrics
14541  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14542  * wide, in pixels, a given block of text will be.
14543  * @singleton
14544  */
14545 Roo.util.TextMetrics = function(){
14546     var shared;
14547     return {
14548         /**
14549          * Measures the size of the specified text
14550          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14551          * that can affect the size of the rendered text
14552          * @param {String} text The text to measure
14553          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14554          * in order to accurately measure the text height
14555          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14556          */
14557         measure : function(el, text, fixedWidth){
14558             if(!shared){
14559                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14560             }
14561             shared.bind(el);
14562             shared.setFixedWidth(fixedWidth || 'auto');
14563             return shared.getSize(text);
14564         },
14565
14566         /**
14567          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14568          * the overhead of multiple calls to initialize the style properties on each measurement.
14569          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14570          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14571          * in order to accurately measure the text height
14572          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14573          */
14574         createInstance : function(el, fixedWidth){
14575             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14576         }
14577     };
14578 }();
14579
14580  
14581
14582 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14583     var ml = new Roo.Element(document.createElement('div'));
14584     document.body.appendChild(ml.dom);
14585     ml.position('absolute');
14586     ml.setLeftTop(-1000, -1000);
14587     ml.hide();
14588
14589     if(fixedWidth){
14590         ml.setWidth(fixedWidth);
14591     }
14592      
14593     var instance = {
14594         /**
14595          * Returns the size of the specified text based on the internal element's style and width properties
14596          * @memberOf Roo.util.TextMetrics.Instance#
14597          * @param {String} text The text to measure
14598          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14599          */
14600         getSize : function(text){
14601             ml.update(text);
14602             var s = ml.getSize();
14603             ml.update('');
14604             return s;
14605         },
14606
14607         /**
14608          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14609          * that can affect the size of the rendered text
14610          * @memberOf Roo.util.TextMetrics.Instance#
14611          * @param {String/HTMLElement} el The element, dom node or id
14612          */
14613         bind : function(el){
14614             ml.setStyle(
14615                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14616             );
14617         },
14618
14619         /**
14620          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14621          * to set a fixed width in order to accurately measure the text height.
14622          * @memberOf Roo.util.TextMetrics.Instance#
14623          * @param {Number} width The width to set on the element
14624          */
14625         setFixedWidth : function(width){
14626             ml.setWidth(width);
14627         },
14628
14629         /**
14630          * Returns the measured width of the specified text
14631          * @memberOf Roo.util.TextMetrics.Instance#
14632          * @param {String} text The text to measure
14633          * @return {Number} width The width in pixels
14634          */
14635         getWidth : function(text){
14636             ml.dom.style.width = 'auto';
14637             return this.getSize(text).width;
14638         },
14639
14640         /**
14641          * Returns the measured height of the specified text.  For multiline text, be sure to call
14642          * {@link #setFixedWidth} if necessary.
14643          * @memberOf Roo.util.TextMetrics.Instance#
14644          * @param {String} text The text to measure
14645          * @return {Number} height The height in pixels
14646          */
14647         getHeight : function(text){
14648             return this.getSize(text).height;
14649         }
14650     };
14651
14652     instance.bind(bindTo);
14653
14654     return instance;
14655 };
14656
14657 // backwards compat
14658 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14659  * Based on:
14660  * Ext JS Library 1.1.1
14661  * Copyright(c) 2006-2007, Ext JS, LLC.
14662  *
14663  * Originally Released Under LGPL - original licence link has changed is not relivant.
14664  *
14665  * Fork - LGPL
14666  * <script type="text/javascript">
14667  */
14668
14669 /**
14670  * @class Roo.state.Provider
14671  * Abstract base class for state provider implementations. This class provides methods
14672  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14673  * Provider interface.
14674  */
14675 Roo.state.Provider = function(){
14676     /**
14677      * @event statechange
14678      * Fires when a state change occurs.
14679      * @param {Provider} this This state provider
14680      * @param {String} key The state key which was changed
14681      * @param {String} value The encoded value for the state
14682      */
14683     this.addEvents({
14684         "statechange": true
14685     });
14686     this.state = {};
14687     Roo.state.Provider.superclass.constructor.call(this);
14688 };
14689 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14690     /**
14691      * Returns the current value for a key
14692      * @param {String} name The key name
14693      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14694      * @return {Mixed} The state data
14695      */
14696     get : function(name, defaultValue){
14697         return typeof this.state[name] == "undefined" ?
14698             defaultValue : this.state[name];
14699     },
14700     
14701     /**
14702      * Clears a value from the state
14703      * @param {String} name The key name
14704      */
14705     clear : function(name){
14706         delete this.state[name];
14707         this.fireEvent("statechange", this, name, null);
14708     },
14709     
14710     /**
14711      * Sets the value for a key
14712      * @param {String} name The key name
14713      * @param {Mixed} value The value to set
14714      */
14715     set : function(name, value){
14716         this.state[name] = value;
14717         this.fireEvent("statechange", this, name, value);
14718     },
14719     
14720     /**
14721      * Decodes a string previously encoded with {@link #encodeValue}.
14722      * @param {String} value The value to decode
14723      * @return {Mixed} The decoded value
14724      */
14725     decodeValue : function(cookie){
14726         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14727         var matches = re.exec(unescape(cookie));
14728         if(!matches || !matches[1]) return; // non state cookie
14729         var type = matches[1];
14730         var v = matches[2];
14731         switch(type){
14732             case "n":
14733                 return parseFloat(v);
14734             case "d":
14735                 return new Date(Date.parse(v));
14736             case "b":
14737                 return (v == "1");
14738             case "a":
14739                 var all = [];
14740                 var values = v.split("^");
14741                 for(var i = 0, len = values.length; i < len; i++){
14742                     all.push(this.decodeValue(values[i]));
14743                 }
14744                 return all;
14745            case "o":
14746                 var all = {};
14747                 var values = v.split("^");
14748                 for(var i = 0, len = values.length; i < len; i++){
14749                     var kv = values[i].split("=");
14750                     all[kv[0]] = this.decodeValue(kv[1]);
14751                 }
14752                 return all;
14753            default:
14754                 return v;
14755         }
14756     },
14757     
14758     /**
14759      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14760      * @param {Mixed} value The value to encode
14761      * @return {String} The encoded value
14762      */
14763     encodeValue : function(v){
14764         var enc;
14765         if(typeof v == "number"){
14766             enc = "n:" + v;
14767         }else if(typeof v == "boolean"){
14768             enc = "b:" + (v ? "1" : "0");
14769         }else if(v instanceof Date){
14770             enc = "d:" + v.toGMTString();
14771         }else if(v instanceof Array){
14772             var flat = "";
14773             for(var i = 0, len = v.length; i < len; i++){
14774                 flat += this.encodeValue(v[i]);
14775                 if(i != len-1) flat += "^";
14776             }
14777             enc = "a:" + flat;
14778         }else if(typeof v == "object"){
14779             var flat = "";
14780             for(var key in v){
14781                 if(typeof v[key] != "function"){
14782                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14783                 }
14784             }
14785             enc = "o:" + flat.substring(0, flat.length-1);
14786         }else{
14787             enc = "s:" + v;
14788         }
14789         return escape(enc);        
14790     }
14791 });
14792
14793 /*
14794  * Based on:
14795  * Ext JS Library 1.1.1
14796  * Copyright(c) 2006-2007, Ext JS, LLC.
14797  *
14798  * Originally Released Under LGPL - original licence link has changed is not relivant.
14799  *
14800  * Fork - LGPL
14801  * <script type="text/javascript">
14802  */
14803 /**
14804  * @class Roo.state.Manager
14805  * This is the global state manager. By default all components that are "state aware" check this class
14806  * for state information if you don't pass them a custom state provider. In order for this class
14807  * to be useful, it must be initialized with a provider when your application initializes.
14808  <pre><code>
14809 // in your initialization function
14810 init : function(){
14811    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14812    ...
14813    // supposed you have a {@link Roo.BorderLayout}
14814    var layout = new Roo.BorderLayout(...);
14815    layout.restoreState();
14816    // or a {Roo.BasicDialog}
14817    var dialog = new Roo.BasicDialog(...);
14818    dialog.restoreState();
14819  </code></pre>
14820  * @singleton
14821  */
14822 Roo.state.Manager = function(){
14823     var provider = new Roo.state.Provider();
14824     
14825     return {
14826         /**
14827          * Configures the default state provider for your application
14828          * @param {Provider} stateProvider The state provider to set
14829          */
14830         setProvider : function(stateProvider){
14831             provider = stateProvider;
14832         },
14833         
14834         /**
14835          * Returns the current value for a key
14836          * @param {String} name The key name
14837          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14838          * @return {Mixed} The state data
14839          */
14840         get : function(key, defaultValue){
14841             return provider.get(key, defaultValue);
14842         },
14843         
14844         /**
14845          * Sets the value for a key
14846          * @param {String} name The key name
14847          * @param {Mixed} value The state data
14848          */
14849          set : function(key, value){
14850             provider.set(key, value);
14851         },
14852         
14853         /**
14854          * Clears a value from the state
14855          * @param {String} name The key name
14856          */
14857         clear : function(key){
14858             provider.clear(key);
14859         },
14860         
14861         /**
14862          * Gets the currently configured state provider
14863          * @return {Provider} The state provider
14864          */
14865         getProvider : function(){
14866             return provider;
14867         }
14868     };
14869 }();
14870 /*
14871  * Based on:
14872  * Ext JS Library 1.1.1
14873  * Copyright(c) 2006-2007, Ext JS, LLC.
14874  *
14875  * Originally Released Under LGPL - original licence link has changed is not relivant.
14876  *
14877  * Fork - LGPL
14878  * <script type="text/javascript">
14879  */
14880 /**
14881  * @class Roo.state.CookieProvider
14882  * @extends Roo.state.Provider
14883  * The default Provider implementation which saves state via cookies.
14884  * <br />Usage:
14885  <pre><code>
14886    var cp = new Roo.state.CookieProvider({
14887        path: "/cgi-bin/",
14888        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14889        domain: "roojs.com"
14890    })
14891    Roo.state.Manager.setProvider(cp);
14892  </code></pre>
14893  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14894  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14895  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14896  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14897  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14898  * domain the page is running on including the 'www' like 'www.roojs.com')
14899  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14900  * @constructor
14901  * Create a new CookieProvider
14902  * @param {Object} config The configuration object
14903  */
14904 Roo.state.CookieProvider = function(config){
14905     Roo.state.CookieProvider.superclass.constructor.call(this);
14906     this.path = "/";
14907     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14908     this.domain = null;
14909     this.secure = false;
14910     Roo.apply(this, config);
14911     this.state = this.readCookies();
14912 };
14913
14914 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14915     // private
14916     set : function(name, value){
14917         if(typeof value == "undefined" || value === null){
14918             this.clear(name);
14919             return;
14920         }
14921         this.setCookie(name, value);
14922         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14923     },
14924
14925     // private
14926     clear : function(name){
14927         this.clearCookie(name);
14928         Roo.state.CookieProvider.superclass.clear.call(this, name);
14929     },
14930
14931     // private
14932     readCookies : function(){
14933         var cookies = {};
14934         var c = document.cookie + ";";
14935         var re = /\s?(.*?)=(.*?);/g;
14936         var matches;
14937         while((matches = re.exec(c)) != null){
14938             var name = matches[1];
14939             var value = matches[2];
14940             if(name && name.substring(0,3) == "ys-"){
14941                 cookies[name.substr(3)] = this.decodeValue(value);
14942             }
14943         }
14944         return cookies;
14945     },
14946
14947     // private
14948     setCookie : function(name, value){
14949         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14950            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14951            ((this.path == null) ? "" : ("; path=" + this.path)) +
14952            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14953            ((this.secure == true) ? "; secure" : "");
14954     },
14955
14956     // private
14957     clearCookie : function(name){
14958         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14959            ((this.path == null) ? "" : ("; path=" + this.path)) +
14960            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14961            ((this.secure == true) ? "; secure" : "");
14962     }
14963 });/*
14964  * Based on:
14965  * Ext JS Library 1.1.1
14966  * Copyright(c) 2006-2007, Ext JS, LLC.
14967  *
14968  * Originally Released Under LGPL - original licence link has changed is not relivant.
14969  *
14970  * Fork - LGPL
14971  * <script type="text/javascript">
14972  */
14973  
14974
14975 /**
14976  * @class Roo.ComponentMgr
14977  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14978  * @singleton
14979  */
14980 Roo.ComponentMgr = function(){
14981     var all = new Roo.util.MixedCollection();
14982
14983     return {
14984         /**
14985          * Registers a component.
14986          * @param {Roo.Component} c The component
14987          */
14988         register : function(c){
14989             all.add(c);
14990         },
14991
14992         /**
14993          * Unregisters a component.
14994          * @param {Roo.Component} c The component
14995          */
14996         unregister : function(c){
14997             all.remove(c);
14998         },
14999
15000         /**
15001          * Returns a component by id
15002          * @param {String} id The component id
15003          */
15004         get : function(id){
15005             return all.get(id);
15006         },
15007
15008         /**
15009          * Registers a function that will be called when a specified component is added to ComponentMgr
15010          * @param {String} id The component id
15011          * @param {Funtction} fn The callback function
15012          * @param {Object} scope The scope of the callback
15013          */
15014         onAvailable : function(id, fn, scope){
15015             all.on("add", function(index, o){
15016                 if(o.id == id){
15017                     fn.call(scope || o, o);
15018                     all.un("add", fn, scope);
15019                 }
15020             });
15021         }
15022     };
15023 }();/*
15024  * Based on:
15025  * Ext JS Library 1.1.1
15026  * Copyright(c) 2006-2007, Ext JS, LLC.
15027  *
15028  * Originally Released Under LGPL - original licence link has changed is not relivant.
15029  *
15030  * Fork - LGPL
15031  * <script type="text/javascript">
15032  */
15033  
15034 /**
15035  * @class Roo.Component
15036  * @extends Roo.util.Observable
15037  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15038  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15039  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15040  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15041  * All visual components (widgets) that require rendering into a layout should subclass Component.
15042  * @constructor
15043  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15044  * 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
15045  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15046  */
15047 Roo.Component = function(config){
15048     config = config || {};
15049     if(config.tagName || config.dom || typeof config == "string"){ // element object
15050         config = {el: config, id: config.id || config};
15051     }
15052     this.initialConfig = config;
15053
15054     Roo.apply(this, config);
15055     this.addEvents({
15056         /**
15057          * @event disable
15058          * Fires after the component is disabled.
15059              * @param {Roo.Component} this
15060              */
15061         disable : true,
15062         /**
15063          * @event enable
15064          * Fires after the component is enabled.
15065              * @param {Roo.Component} this
15066              */
15067         enable : true,
15068         /**
15069          * @event beforeshow
15070          * Fires before the component is shown.  Return false to stop the show.
15071              * @param {Roo.Component} this
15072              */
15073         beforeshow : true,
15074         /**
15075          * @event show
15076          * Fires after the component is shown.
15077              * @param {Roo.Component} this
15078              */
15079         show : true,
15080         /**
15081          * @event beforehide
15082          * Fires before the component is hidden. Return false to stop the hide.
15083              * @param {Roo.Component} this
15084              */
15085         beforehide : true,
15086         /**
15087          * @event hide
15088          * Fires after the component is hidden.
15089              * @param {Roo.Component} this
15090              */
15091         hide : true,
15092         /**
15093          * @event beforerender
15094          * Fires before the component is rendered. Return false to stop the render.
15095              * @param {Roo.Component} this
15096              */
15097         beforerender : true,
15098         /**
15099          * @event render
15100          * Fires after the component is rendered.
15101              * @param {Roo.Component} this
15102              */
15103         render : true,
15104         /**
15105          * @event beforedestroy
15106          * Fires before the component is destroyed. Return false to stop the destroy.
15107              * @param {Roo.Component} this
15108              */
15109         beforedestroy : true,
15110         /**
15111          * @event destroy
15112          * Fires after the component is destroyed.
15113              * @param {Roo.Component} this
15114              */
15115         destroy : true
15116     });
15117     if(!this.id){
15118         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15119     }
15120     Roo.ComponentMgr.register(this);
15121     Roo.Component.superclass.constructor.call(this);
15122     this.initComponent();
15123     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15124         this.render(this.renderTo);
15125         delete this.renderTo;
15126     }
15127 };
15128
15129 /** @private */
15130 Roo.Component.AUTO_ID = 1000;
15131
15132 Roo.extend(Roo.Component, Roo.util.Observable, {
15133     /**
15134      * @scope Roo.Component.prototype
15135      * @type {Boolean}
15136      * true if this component is hidden. Read-only.
15137      */
15138     hidden : false,
15139     /**
15140      * @type {Boolean}
15141      * true if this component is disabled. Read-only.
15142      */
15143     disabled : false,
15144     /**
15145      * @type {Boolean}
15146      * true if this component has been rendered. Read-only.
15147      */
15148     rendered : false,
15149     
15150     /** @cfg {String} disableClass
15151      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15152      */
15153     disabledClass : "x-item-disabled",
15154         /** @cfg {Boolean} allowDomMove
15155          * Whether the component can move the Dom node when rendering (defaults to true).
15156          */
15157     allowDomMove : true,
15158     /** @cfg {String} hideMode
15159      * How this component should hidden. Supported values are
15160      * "visibility" (css visibility), "offsets" (negative offset position) and
15161      * "display" (css display) - defaults to "display".
15162      */
15163     hideMode: 'display',
15164
15165     /** @private */
15166     ctype : "Roo.Component",
15167
15168     /**
15169      * @cfg {String} actionMode 
15170      * which property holds the element that used for  hide() / show() / disable() / enable()
15171      * default is 'el' 
15172      */
15173     actionMode : "el",
15174
15175     /** @private */
15176     getActionEl : function(){
15177         return this[this.actionMode];
15178     },
15179
15180     initComponent : Roo.emptyFn,
15181     /**
15182      * If this is a lazy rendering component, render it to its container element.
15183      * @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.
15184      */
15185     render : function(container, position){
15186         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15187             if(!container && this.el){
15188                 this.el = Roo.get(this.el);
15189                 container = this.el.dom.parentNode;
15190                 this.allowDomMove = false;
15191             }
15192             this.container = Roo.get(container);
15193             this.rendered = true;
15194             if(position !== undefined){
15195                 if(typeof position == 'number'){
15196                     position = this.container.dom.childNodes[position];
15197                 }else{
15198                     position = Roo.getDom(position);
15199                 }
15200             }
15201             this.onRender(this.container, position || null);
15202             if(this.cls){
15203                 this.el.addClass(this.cls);
15204                 delete this.cls;
15205             }
15206             if(this.style){
15207                 this.el.applyStyles(this.style);
15208                 delete this.style;
15209             }
15210             this.fireEvent("render", this);
15211             this.afterRender(this.container);
15212             if(this.hidden){
15213                 this.hide();
15214             }
15215             if(this.disabled){
15216                 this.disable();
15217             }
15218         }
15219         return this;
15220     },
15221
15222     /** @private */
15223     // default function is not really useful
15224     onRender : function(ct, position){
15225         if(this.el){
15226             this.el = Roo.get(this.el);
15227             if(this.allowDomMove !== false){
15228                 ct.dom.insertBefore(this.el.dom, position);
15229             }
15230         }
15231     },
15232
15233     /** @private */
15234     getAutoCreate : function(){
15235         var cfg = typeof this.autoCreate == "object" ?
15236                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15237         if(this.id && !cfg.id){
15238             cfg.id = this.id;
15239         }
15240         return cfg;
15241     },
15242
15243     /** @private */
15244     afterRender : Roo.emptyFn,
15245
15246     /**
15247      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15248      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15249      */
15250     destroy : function(){
15251         if(this.fireEvent("beforedestroy", this) !== false){
15252             this.purgeListeners();
15253             this.beforeDestroy();
15254             if(this.rendered){
15255                 this.el.removeAllListeners();
15256                 this.el.remove();
15257                 if(this.actionMode == "container"){
15258                     this.container.remove();
15259                 }
15260             }
15261             this.onDestroy();
15262             Roo.ComponentMgr.unregister(this);
15263             this.fireEvent("destroy", this);
15264         }
15265     },
15266
15267         /** @private */
15268     beforeDestroy : function(){
15269
15270     },
15271
15272         /** @private */
15273         onDestroy : function(){
15274
15275     },
15276
15277     /**
15278      * Returns the underlying {@link Roo.Element}.
15279      * @return {Roo.Element} The element
15280      */
15281     getEl : function(){
15282         return this.el;
15283     },
15284
15285     /**
15286      * Returns the id of this component.
15287      * @return {String}
15288      */
15289     getId : function(){
15290         return this.id;
15291     },
15292
15293     /**
15294      * Try to focus this component.
15295      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15296      * @return {Roo.Component} this
15297      */
15298     focus : function(selectText){
15299         if(this.rendered){
15300             this.el.focus();
15301             if(selectText === true){
15302                 this.el.dom.select();
15303             }
15304         }
15305         return this;
15306     },
15307
15308     /** @private */
15309     blur : function(){
15310         if(this.rendered){
15311             this.el.blur();
15312         }
15313         return this;
15314     },
15315
15316     /**
15317      * Disable this component.
15318      * @return {Roo.Component} this
15319      */
15320     disable : function(){
15321         if(this.rendered){
15322             this.onDisable();
15323         }
15324         this.disabled = true;
15325         this.fireEvent("disable", this);
15326         return this;
15327     },
15328
15329         // private
15330     onDisable : function(){
15331         this.getActionEl().addClass(this.disabledClass);
15332         this.el.dom.disabled = true;
15333     },
15334
15335     /**
15336      * Enable this component.
15337      * @return {Roo.Component} this
15338      */
15339     enable : function(){
15340         if(this.rendered){
15341             this.onEnable();
15342         }
15343         this.disabled = false;
15344         this.fireEvent("enable", this);
15345         return this;
15346     },
15347
15348         // private
15349     onEnable : function(){
15350         this.getActionEl().removeClass(this.disabledClass);
15351         this.el.dom.disabled = false;
15352     },
15353
15354     /**
15355      * Convenience function for setting disabled/enabled by boolean.
15356      * @param {Boolean} disabled
15357      */
15358     setDisabled : function(disabled){
15359         this[disabled ? "disable" : "enable"]();
15360     },
15361
15362     /**
15363      * Show this component.
15364      * @return {Roo.Component} this
15365      */
15366     show: function(){
15367         if(this.fireEvent("beforeshow", this) !== false){
15368             this.hidden = false;
15369             if(this.rendered){
15370                 this.onShow();
15371             }
15372             this.fireEvent("show", this);
15373         }
15374         return this;
15375     },
15376
15377     // private
15378     onShow : function(){
15379         var ae = this.getActionEl();
15380         if(this.hideMode == 'visibility'){
15381             ae.dom.style.visibility = "visible";
15382         }else if(this.hideMode == 'offsets'){
15383             ae.removeClass('x-hidden');
15384         }else{
15385             ae.dom.style.display = "";
15386         }
15387     },
15388
15389     /**
15390      * Hide this component.
15391      * @return {Roo.Component} this
15392      */
15393     hide: function(){
15394         if(this.fireEvent("beforehide", this) !== false){
15395             this.hidden = true;
15396             if(this.rendered){
15397                 this.onHide();
15398             }
15399             this.fireEvent("hide", this);
15400         }
15401         return this;
15402     },
15403
15404     // private
15405     onHide : function(){
15406         var ae = this.getActionEl();
15407         if(this.hideMode == 'visibility'){
15408             ae.dom.style.visibility = "hidden";
15409         }else if(this.hideMode == 'offsets'){
15410             ae.addClass('x-hidden');
15411         }else{
15412             ae.dom.style.display = "none";
15413         }
15414     },
15415
15416     /**
15417      * Convenience function to hide or show this component by boolean.
15418      * @param {Boolean} visible True to show, false to hide
15419      * @return {Roo.Component} this
15420      */
15421     setVisible: function(visible){
15422         if(visible) {
15423             this.show();
15424         }else{
15425             this.hide();
15426         }
15427         return this;
15428     },
15429
15430     /**
15431      * Returns true if this component is visible.
15432      */
15433     isVisible : function(){
15434         return this.getActionEl().isVisible();
15435     },
15436
15437     cloneConfig : function(overrides){
15438         overrides = overrides || {};
15439         var id = overrides.id || Roo.id();
15440         var cfg = Roo.applyIf(overrides, this.initialConfig);
15441         cfg.id = id; // prevent dup id
15442         return new this.constructor(cfg);
15443     }
15444 });/*
15445  * Based on:
15446  * Ext JS Library 1.1.1
15447  * Copyright(c) 2006-2007, Ext JS, LLC.
15448  *
15449  * Originally Released Under LGPL - original licence link has changed is not relivant.
15450  *
15451  * Fork - LGPL
15452  * <script type="text/javascript">
15453  */
15454
15455 /**
15456  * @class Roo.BoxComponent
15457  * @extends Roo.Component
15458  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15459  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15460  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15461  * layout containers.
15462  * @constructor
15463  * @param {Roo.Element/String/Object} config The configuration options.
15464  */
15465 Roo.BoxComponent = function(config){
15466     Roo.Component.call(this, config);
15467     this.addEvents({
15468         /**
15469          * @event resize
15470          * Fires after the component is resized.
15471              * @param {Roo.Component} this
15472              * @param {Number} adjWidth The box-adjusted width that was set
15473              * @param {Number} adjHeight The box-adjusted height that was set
15474              * @param {Number} rawWidth The width that was originally specified
15475              * @param {Number} rawHeight The height that was originally specified
15476              */
15477         resize : true,
15478         /**
15479          * @event move
15480          * Fires after the component is moved.
15481              * @param {Roo.Component} this
15482              * @param {Number} x The new x position
15483              * @param {Number} y The new y position
15484              */
15485         move : true
15486     });
15487 };
15488
15489 Roo.extend(Roo.BoxComponent, Roo.Component, {
15490     // private, set in afterRender to signify that the component has been rendered
15491     boxReady : false,
15492     // private, used to defer height settings to subclasses
15493     deferHeight: false,
15494     /** @cfg {Number} width
15495      * width (optional) size of component
15496      */
15497      /** @cfg {Number} height
15498      * height (optional) size of component
15499      */
15500      
15501     /**
15502      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15503      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15504      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15505      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15506      * @return {Roo.BoxComponent} this
15507      */
15508     setSize : function(w, h){
15509         // support for standard size objects
15510         if(typeof w == 'object'){
15511             h = w.height;
15512             w = w.width;
15513         }
15514         // not rendered
15515         if(!this.boxReady){
15516             this.width = w;
15517             this.height = h;
15518             return this;
15519         }
15520
15521         // prevent recalcs when not needed
15522         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15523             return this;
15524         }
15525         this.lastSize = {width: w, height: h};
15526
15527         var adj = this.adjustSize(w, h);
15528         var aw = adj.width, ah = adj.height;
15529         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15530             var rz = this.getResizeEl();
15531             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15532                 rz.setSize(aw, ah);
15533             }else if(!this.deferHeight && ah !== undefined){
15534                 rz.setHeight(ah);
15535             }else if(aw !== undefined){
15536                 rz.setWidth(aw);
15537             }
15538             this.onResize(aw, ah, w, h);
15539             this.fireEvent('resize', this, aw, ah, w, h);
15540         }
15541         return this;
15542     },
15543
15544     /**
15545      * Gets the current size of the component's underlying element.
15546      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15547      */
15548     getSize : function(){
15549         return this.el.getSize();
15550     },
15551
15552     /**
15553      * Gets the current XY position of the component's underlying element.
15554      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15555      * @return {Array} The XY position of the element (e.g., [100, 200])
15556      */
15557     getPosition : function(local){
15558         if(local === true){
15559             return [this.el.getLeft(true), this.el.getTop(true)];
15560         }
15561         return this.xy || this.el.getXY();
15562     },
15563
15564     /**
15565      * Gets the current box measurements of the component's underlying element.
15566      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15567      * @returns {Object} box An object in the format {x, y, width, height}
15568      */
15569     getBox : function(local){
15570         var s = this.el.getSize();
15571         if(local){
15572             s.x = this.el.getLeft(true);
15573             s.y = this.el.getTop(true);
15574         }else{
15575             var xy = this.xy || this.el.getXY();
15576             s.x = xy[0];
15577             s.y = xy[1];
15578         }
15579         return s;
15580     },
15581
15582     /**
15583      * Sets the current box measurements of the component's underlying element.
15584      * @param {Object} box An object in the format {x, y, width, height}
15585      * @returns {Roo.BoxComponent} this
15586      */
15587     updateBox : function(box){
15588         this.setSize(box.width, box.height);
15589         this.setPagePosition(box.x, box.y);
15590         return this;
15591     },
15592
15593     // protected
15594     getResizeEl : function(){
15595         return this.resizeEl || this.el;
15596     },
15597
15598     // protected
15599     getPositionEl : function(){
15600         return this.positionEl || this.el;
15601     },
15602
15603     /**
15604      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15605      * This method fires the move event.
15606      * @param {Number} left The new left
15607      * @param {Number} top The new top
15608      * @returns {Roo.BoxComponent} this
15609      */
15610     setPosition : function(x, y){
15611         this.x = x;
15612         this.y = y;
15613         if(!this.boxReady){
15614             return this;
15615         }
15616         var adj = this.adjustPosition(x, y);
15617         var ax = adj.x, ay = adj.y;
15618
15619         var el = this.getPositionEl();
15620         if(ax !== undefined || ay !== undefined){
15621             if(ax !== undefined && ay !== undefined){
15622                 el.setLeftTop(ax, ay);
15623             }else if(ax !== undefined){
15624                 el.setLeft(ax);
15625             }else if(ay !== undefined){
15626                 el.setTop(ay);
15627             }
15628             this.onPosition(ax, ay);
15629             this.fireEvent('move', this, ax, ay);
15630         }
15631         return this;
15632     },
15633
15634     /**
15635      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15636      * This method fires the move event.
15637      * @param {Number} x The new x position
15638      * @param {Number} y The new y position
15639      * @returns {Roo.BoxComponent} this
15640      */
15641     setPagePosition : function(x, y){
15642         this.pageX = x;
15643         this.pageY = y;
15644         if(!this.boxReady){
15645             return;
15646         }
15647         if(x === undefined || y === undefined){ // cannot translate undefined points
15648             return;
15649         }
15650         var p = this.el.translatePoints(x, y);
15651         this.setPosition(p.left, p.top);
15652         return this;
15653     },
15654
15655     // private
15656     onRender : function(ct, position){
15657         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15658         if(this.resizeEl){
15659             this.resizeEl = Roo.get(this.resizeEl);
15660         }
15661         if(this.positionEl){
15662             this.positionEl = Roo.get(this.positionEl);
15663         }
15664     },
15665
15666     // private
15667     afterRender : function(){
15668         Roo.BoxComponent.superclass.afterRender.call(this);
15669         this.boxReady = true;
15670         this.setSize(this.width, this.height);
15671         if(this.x || this.y){
15672             this.setPosition(this.x, this.y);
15673         }
15674         if(this.pageX || this.pageY){
15675             this.setPagePosition(this.pageX, this.pageY);
15676         }
15677     },
15678
15679     /**
15680      * Force the component's size to recalculate based on the underlying element's current height and width.
15681      * @returns {Roo.BoxComponent} this
15682      */
15683     syncSize : function(){
15684         delete this.lastSize;
15685         this.setSize(this.el.getWidth(), this.el.getHeight());
15686         return this;
15687     },
15688
15689     /**
15690      * Called after the component is resized, this method is empty by default but can be implemented by any
15691      * subclass that needs to perform custom logic after a resize occurs.
15692      * @param {Number} adjWidth The box-adjusted width that was set
15693      * @param {Number} adjHeight The box-adjusted height that was set
15694      * @param {Number} rawWidth The width that was originally specified
15695      * @param {Number} rawHeight The height that was originally specified
15696      */
15697     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15698
15699     },
15700
15701     /**
15702      * Called after the component is moved, this method is empty by default but can be implemented by any
15703      * subclass that needs to perform custom logic after a move occurs.
15704      * @param {Number} x The new x position
15705      * @param {Number} y The new y position
15706      */
15707     onPosition : function(x, y){
15708
15709     },
15710
15711     // private
15712     adjustSize : function(w, h){
15713         if(this.autoWidth){
15714             w = 'auto';
15715         }
15716         if(this.autoHeight){
15717             h = 'auto';
15718         }
15719         return {width : w, height: h};
15720     },
15721
15722     // private
15723     adjustPosition : function(x, y){
15724         return {x : x, y: y};
15725     }
15726 });/*
15727  * Original code for Roojs - LGPL
15728  * <script type="text/javascript">
15729  */
15730  
15731 /**
15732  * @class Roo.XComponent
15733  * A delayed Element creator...
15734  * Or a way to group chunks of interface together.
15735  * 
15736  * Mypart.xyx = new Roo.XComponent({
15737
15738     parent : 'Mypart.xyz', // empty == document.element.!!
15739     order : '001',
15740     name : 'xxxx'
15741     region : 'xxxx'
15742     disabled : function() {} 
15743      
15744     tree : function() { // return an tree of xtype declared components
15745         var MODULE = this;
15746         return 
15747         {
15748             xtype : 'NestedLayoutPanel',
15749             // technicall
15750         }
15751      ]
15752  *})
15753  *
15754  *
15755  * It can be used to build a big heiracy, with parent etc.
15756  * or you can just use this to render a single compoent to a dom element
15757  * MYPART.render(Roo.Element | String(id) | dom_element )
15758  * 
15759  * @extends Roo.util.Observable
15760  * @constructor
15761  * @param cfg {Object} configuration of component
15762  * 
15763  */
15764 Roo.XComponent = function(cfg) {
15765     Roo.apply(this, cfg);
15766     this.addEvents({ 
15767         /**
15768              * @event built
15769              * Fires when this the componnt is built
15770              * @param {Roo.XComponent} c the component
15771              */
15772         'built' : true
15773         
15774     });
15775     this.region = this.region || 'center'; // default..
15776     Roo.XComponent.register(this);
15777     this.modules = false;
15778     this.el = false; // where the layout goes..
15779     
15780     
15781 }
15782 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15783     /**
15784      * @property el
15785      * The created element (with Roo.factory())
15786      * @type {Roo.Layout}
15787      */
15788     el  : false,
15789     
15790     /**
15791      * @property el
15792      * for BC  - use el in new code
15793      * @type {Roo.Layout}
15794      */
15795     panel : false,
15796     
15797     /**
15798      * @property layout
15799      * for BC  - use el in new code
15800      * @type {Roo.Layout}
15801      */
15802     layout : false,
15803     
15804      /**
15805      * @cfg {Function|boolean} disabled
15806      * If this module is disabled by some rule, return true from the funtion
15807      */
15808     disabled : false,
15809     
15810     /**
15811      * @cfg {String} parent 
15812      * Name of parent element which it get xtype added to..
15813      */
15814     parent: false,
15815     
15816     /**
15817      * @cfg {String} order
15818      * Used to set the order in which elements are created (usefull for multiple tabs)
15819      */
15820     
15821     order : false,
15822     /**
15823      * @cfg {String} name
15824      * String to display while loading.
15825      */
15826     name : false,
15827     /**
15828      * @cfg {String} region
15829      * Region to render component to (defaults to center)
15830      */
15831     region : 'center',
15832     
15833     /**
15834      * @cfg {Array} items
15835      * A single item array - the first element is the root of the tree..
15836      * It's done this way to stay compatible with the Xtype system...
15837      */
15838     items : false,
15839     
15840     /**
15841      * @property _tree
15842      * The method that retuns the tree of parts that make up this compoennt 
15843      * @type {function}
15844      */
15845     _tree  : false,
15846     
15847      /**
15848      * render
15849      * render element to dom or tree
15850      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15851      */
15852     
15853     render : function(el)
15854     {
15855         
15856         el = el || false;
15857         var hp = this.parent ? 1 : 0;
15858         
15859         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15860             // if parent is a '#.....' string, then let's use that..
15861             var ename = this.parent.substr(1)
15862             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15863             el = Roo.get(ename);
15864             if (!el && !this.parent) {
15865                 Roo.log("Warning - element can not be found :#" + ename );
15866                 return;
15867             }
15868         }
15869         
15870         
15871         if (!this.parent) {
15872             
15873             el = el ? Roo.get(el) : false;      
15874             
15875             // it's a top level one..
15876             this.parent =  {
15877                 el : new Roo.BorderLayout(el || document.body, {
15878                 
15879                      center: {
15880                          titlebar: false,
15881                          autoScroll:false,
15882                          closeOnTab: true,
15883                          tabPosition: 'top',
15884                           //resizeTabs: true,
15885                          alwaysShowTabs: el && hp? false :  true,
15886                          hideTabs: el || !hp ? true :  false,
15887                          minTabWidth: 140
15888                      }
15889                  })
15890             }
15891         }
15892         
15893                 if (!this.parent.el) {
15894                         // probably an old style ctor, which has been disabled.
15895                         return;
15896                         
15897                 }
15898                 // The 'tree' method is  '_tree now' 
15899             
15900         var tree = this._tree ? this._tree() : this.tree();
15901         tree.region = tree.region || this.region;
15902         
15903         if (this.parent.el === true) {
15904             // bootstrap... - body..
15905             this.parent.el = Roo.factory(tree);
15906         }
15907         
15908         this.el = this.parent.el.addxtype(tree);
15909         this.fireEvent('built', this);
15910         
15911         this.panel = this.el;
15912         this.layout = this.panel.layout;
15913                 this.parentLayout = this.parent.layout  || false;  
15914          
15915     }
15916     
15917 });
15918
15919 Roo.apply(Roo.XComponent, {
15920     /**
15921      * @property  hideProgress
15922      * true to disable the building progress bar.. usefull on single page renders.
15923      * @type Boolean
15924      */
15925     hideProgress : false,
15926     /**
15927      * @property  buildCompleted
15928      * True when the builder has completed building the interface.
15929      * @type Boolean
15930      */
15931     buildCompleted : false,
15932      
15933     /**
15934      * @property  topModule
15935      * the upper most module - uses document.element as it's constructor.
15936      * @type Object
15937      */
15938      
15939     topModule  : false,
15940       
15941     /**
15942      * @property  modules
15943      * array of modules to be created by registration system.
15944      * @type {Array} of Roo.XComponent
15945      */
15946     
15947     modules : [],
15948     /**
15949      * @property  elmodules
15950      * array of modules to be created by which use #ID 
15951      * @type {Array} of Roo.XComponent
15952      */
15953      
15954     elmodules : [],
15955
15956      /**
15957      * @property  build_from_html
15958      * Build elements from html - used by bootstrap HTML stuff 
15959      *    - this is cleared after build is completed
15960      * @type {boolean} true  (default false)
15961      */
15962      
15963     build_from_html : false,
15964
15965     /**
15966      * Register components to be built later.
15967      *
15968      * This solves the following issues
15969      * - Building is not done on page load, but after an authentication process has occured.
15970      * - Interface elements are registered on page load
15971      * - Parent Interface elements may not be loaded before child, so this handles that..
15972      * 
15973      *
15974      * example:
15975      * 
15976      * MyApp.register({
15977           order : '000001',
15978           module : 'Pman.Tab.projectMgr',
15979           region : 'center',
15980           parent : 'Pman.layout',
15981           disabled : false,  // or use a function..
15982         })
15983      
15984      * * @param {Object} details about module
15985      */
15986     register : function(obj) {
15987                 
15988         Roo.XComponent.event.fireEvent('register', obj);
15989         switch(typeof(obj.disabled) ) {
15990                 
15991             case 'undefined':
15992                 break;
15993             
15994             case 'function':
15995                 if ( obj.disabled() ) {
15996                         return;
15997                 }
15998                 break;
15999             
16000             default:
16001                 if (obj.disabled) {
16002                         return;
16003                 }
16004                 break;
16005         }
16006                 
16007         this.modules.push(obj);
16008          
16009     },
16010     /**
16011      * convert a string to an object..
16012      * eg. 'AAA.BBB' -> finds AAA.BBB
16013
16014      */
16015     
16016     toObject : function(str)
16017     {
16018         if (!str || typeof(str) == 'object') {
16019             return str;
16020         }
16021         if (str.substring(0,1) == '#') {
16022             return str;
16023         }
16024
16025         var ar = str.split('.');
16026         var rt, o;
16027         rt = ar.shift();
16028             /** eval:var:o */
16029         try {
16030             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16031         } catch (e) {
16032             throw "Module not found : " + str;
16033         }
16034         
16035         if (o === false) {
16036             throw "Module not found : " + str;
16037         }
16038         Roo.each(ar, function(e) {
16039             if (typeof(o[e]) == 'undefined') {
16040                 throw "Module not found : " + str;
16041             }
16042             o = o[e];
16043         });
16044         
16045         return o;
16046         
16047     },
16048     
16049     
16050     /**
16051      * move modules into their correct place in the tree..
16052      * 
16053      */
16054     preBuild : function ()
16055     {
16056         var _t = this;
16057         Roo.each(this.modules , function (obj)
16058         {
16059             Roo.XComponent.event.fireEvent('beforebuild', obj);
16060             
16061             var opar = obj.parent;
16062             try { 
16063                 obj.parent = this.toObject(opar);
16064             } catch(e) {
16065                 Roo.log("parent:toObject failed: " + e.toString());
16066                 return;
16067             }
16068             
16069             if (!obj.parent) {
16070                 Roo.debug && Roo.log("GOT top level module");
16071                 Roo.debug && Roo.log(obj);
16072                 obj.modules = new Roo.util.MixedCollection(false, 
16073                     function(o) { return o.order + '' }
16074                 );
16075                 this.topModule = obj;
16076                 return;
16077             }
16078                         // parent is a string (usually a dom element name..)
16079             if (typeof(obj.parent) == 'string') {
16080                 this.elmodules.push(obj);
16081                 return;
16082             }
16083             if (obj.parent.constructor != Roo.XComponent) {
16084                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16085             }
16086             if (!obj.parent.modules) {
16087                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16088                     function(o) { return o.order + '' }
16089                 );
16090             }
16091             if (obj.parent.disabled) {
16092                 obj.disabled = true;
16093             }
16094             obj.parent.modules.add(obj);
16095         }, this);
16096     },
16097     
16098      /**
16099      * make a list of modules to build.
16100      * @return {Array} list of modules. 
16101      */ 
16102     
16103     buildOrder : function()
16104     {
16105         var _this = this;
16106         var cmp = function(a,b) {   
16107             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16108         };
16109         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16110             throw "No top level modules to build";
16111         }
16112         
16113         // make a flat list in order of modules to build.
16114         var mods = this.topModule ? [ this.topModule ] : [];
16115                 
16116         
16117         // elmodules (is a list of DOM based modules )
16118         Roo.each(this.elmodules, function(e) {
16119             mods.push(e);
16120             if (!this.topModule &&
16121                 typeof(e.parent) == 'string' &&
16122                 e.parent.substring(0,1) == '#' &&
16123                 Roo.get(e.parent.substr(1))
16124                ) {
16125                 
16126                 _this.topModule = e;
16127             }
16128             
16129         });
16130
16131         
16132         // add modules to their parents..
16133         var addMod = function(m) {
16134             Roo.debug && Roo.log("build Order: add: " + m.name);
16135                 
16136             mods.push(m);
16137             if (m.modules && !m.disabled) {
16138                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16139                 m.modules.keySort('ASC',  cmp );
16140                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16141     
16142                 m.modules.each(addMod);
16143             } else {
16144                 Roo.debug && Roo.log("build Order: no child modules");
16145             }
16146             // not sure if this is used any more..
16147             if (m.finalize) {
16148                 m.finalize.name = m.name + " (clean up) ";
16149                 mods.push(m.finalize);
16150             }
16151             
16152         }
16153         if (this.topModule && this.topModule.modules) { 
16154             this.topModule.modules.keySort('ASC',  cmp );
16155             this.topModule.modules.each(addMod);
16156         } 
16157         return mods;
16158     },
16159     
16160      /**
16161      * Build the registered modules.
16162      * @param {Object} parent element.
16163      * @param {Function} optional method to call after module has been added.
16164      * 
16165      */ 
16166    
16167     build : function(opts) 
16168     {
16169         
16170         if (typeof(opts) != 'undefined') {
16171             Roo.apply(this,opts);
16172         }
16173         
16174         this.preBuild();
16175         var mods = this.buildOrder();
16176       
16177         //this.allmods = mods;
16178         //Roo.debug && Roo.log(mods);
16179         //return;
16180         if (!mods.length) { // should not happen
16181             throw "NO modules!!!";
16182         }
16183         
16184         
16185         var msg = "Building Interface...";
16186         // flash it up as modal - so we store the mask!?
16187         if (!this.hideProgress && Roo.MessageBox) {
16188             Roo.MessageBox.show({ title: 'loading' });
16189             Roo.MessageBox.show({
16190                title: "Please wait...",
16191                msg: msg,
16192                width:450,
16193                progress:true,
16194                closable:false,
16195                modal: false
16196               
16197             });
16198         }
16199         var total = mods.length;
16200         
16201         var _this = this;
16202         var progressRun = function() {
16203             if (!mods.length) {
16204                 Roo.debug && Roo.log('hide?');
16205                 if (!this.hideProgress && Roo.MessageBox) {
16206                     Roo.MessageBox.hide();
16207                 }
16208                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16209                 
16210                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16211                 
16212                 // THE END...
16213                 return false;   
16214             }
16215             
16216             var m = mods.shift();
16217             
16218             
16219             Roo.debug && Roo.log(m);
16220             // not sure if this is supported any more.. - modules that are are just function
16221             if (typeof(m) == 'function') { 
16222                 m.call(this);
16223                 return progressRun.defer(10, _this);
16224             } 
16225             
16226             
16227             msg = "Building Interface " + (total  - mods.length) + 
16228                     " of " + total + 
16229                     (m.name ? (' - ' + m.name) : '');
16230                         Roo.debug && Roo.log(msg);
16231             if (!this.hideProgress &&  Roo.MessageBox) { 
16232                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16233             }
16234             
16235          
16236             // is the module disabled?
16237             var disabled = (typeof(m.disabled) == 'function') ?
16238                 m.disabled.call(m.module.disabled) : m.disabled;    
16239             
16240             
16241             if (disabled) {
16242                 return progressRun(); // we do not update the display!
16243             }
16244             
16245             // now build 
16246             
16247                         
16248                         
16249             m.render();
16250             // it's 10 on top level, and 1 on others??? why...
16251             return progressRun.defer(10, _this);
16252              
16253         }
16254         progressRun.defer(1, _this);
16255      
16256         
16257         
16258     },
16259         
16260         
16261         /**
16262          * Event Object.
16263          *
16264          *
16265          */
16266         event: false, 
16267     /**
16268          * wrapper for event.on - aliased later..  
16269          * Typically use to register a event handler for register:
16270          *
16271          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16272          *
16273          */
16274     on : false
16275    
16276     
16277     
16278 });
16279
16280 Roo.XComponent.event = new Roo.util.Observable({
16281                 events : { 
16282                         /**
16283                          * @event register
16284                          * Fires when an Component is registered,
16285                          * set the disable property on the Component to stop registration.
16286                          * @param {Roo.XComponent} c the component being registerd.
16287                          * 
16288                          */
16289                         'register' : true,
16290             /**
16291                          * @event beforebuild
16292                          * Fires before each Component is built
16293                          * can be used to apply permissions.
16294                          * @param {Roo.XComponent} c the component being registerd.
16295                          * 
16296                          */
16297                         'beforebuild' : true,
16298                         /**
16299                          * @event buildcomplete
16300                          * Fires on the top level element when all elements have been built
16301                          * @param {Roo.XComponent} the top level component.
16302                          */
16303                         'buildcomplete' : true
16304                         
16305                 }
16306 });
16307
16308 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16309