roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64         isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123         
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618         /** @type Boolean */
619         isTouch : isTouch,
620
621         /**
622          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623          * you may want to set this to true.
624          * @type Boolean
625          */
626         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
627         
628         
629                 
630         /**
631          * Selects a single element as a Roo Element
632          * This is about as close as you can get to jQuery's $('do crazy stuff')
633          * @param {String} selector The selector/xpath query
634          * @param {Node} root (optional) The start of the query (defaults to document).
635          * @return {Roo.Element}
636          */
637         selectNode : function(selector, root) 
638         {
639             var node = Roo.DomQuery.selectNode(selector,root);
640             return node ? Roo.get(node) : new Roo.Element(false);
641         }
642         
643     });
644
645
646 })();
647
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 /*
651  * Based on:
652  * Ext JS Library 1.1.1
653  * Copyright(c) 2006-2007, Ext JS, LLC.
654  *
655  * Originally Released Under LGPL - original licence link has changed is not relivant.
656  *
657  * Fork - LGPL
658  * <script type="text/javascript">
659  */
660
661 (function() {    
662     // wrappedn so fnCleanup is not in global scope...
663     if(Roo.isIE) {
664         function fnCleanUp() {
665             var p = Function.prototype;
666             delete p.createSequence;
667             delete p.defer;
668             delete p.createDelegate;
669             delete p.createCallback;
670             delete p.createInterceptor;
671
672             window.detachEvent("onunload", fnCleanUp);
673         }
674         window.attachEvent("onunload", fnCleanUp);
675     }
676 })();
677
678
679 /**
680  * @class Function
681  * These functions are available on every Function object (any JavaScript function).
682  */
683 Roo.apply(Function.prototype, {
684      /**
685      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687      * Will create a function that is bound to those 2 args.
688      * @return {Function} The new function
689     */
690     createCallback : function(/*args...*/){
691         // make args available, in function below
692         var args = arguments;
693         var method = this;
694         return function() {
695             return method.apply(window, args);
696         };
697     },
698
699     /**
700      * Creates a delegate (callback) that sets the scope to obj.
701      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702      * Will create a function that is automatically scoped to this.
703      * @param {Object} obj (optional) The object for which the scope is set
704      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706      *                                             if a number the args are inserted at the specified position
707      * @return {Function} The new function
708      */
709     createDelegate : function(obj, args, appendArgs){
710         var method = this;
711         return function() {
712             var callArgs = args || arguments;
713             if(appendArgs === true){
714                 callArgs = Array.prototype.slice.call(arguments, 0);
715                 callArgs = callArgs.concat(args);
716             }else if(typeof appendArgs == "number"){
717                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
720             }
721             return method.apply(obj || window, callArgs);
722         };
723     },
724
725     /**
726      * Calls this function after the number of millseconds specified.
727      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728      * @param {Object} obj (optional) The object for which the scope is set
729      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731      *                                             if a number the args are inserted at the specified position
732      * @return {Number} The timeout id that can be used with clearTimeout
733      */
734     defer : function(millis, obj, args, appendArgs){
735         var fn = this.createDelegate(obj, args, appendArgs);
736         if(millis){
737             return setTimeout(fn, millis);
738         }
739         fn();
740         return 0;
741     },
742     /**
743      * Create a combined function call sequence of the original function + the passed function.
744      * The resulting function returns the results of the original function.
745      * The passed fcn is called with the parameters of the original function
746      * @param {Function} fcn The function to sequence
747      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748      * @return {Function} The new function
749      */
750     createSequence : function(fcn, scope){
751         if(typeof fcn != "function"){
752             return this;
753         }
754         var method = this;
755         return function() {
756             var retval = method.apply(this || window, arguments);
757             fcn.apply(scope || this || window, arguments);
758             return retval;
759         };
760     },
761
762     /**
763      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function.
766      * @addon
767      * @param {Function} fcn The function to call before the original
768      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769      * @return {Function} The new function
770      */
771     createInterceptor : function(fcn, scope){
772         if(typeof fcn != "function"){
773             return this;
774         }
775         var method = this;
776         return function() {
777             fcn.target = this;
778             fcn.method = method;
779             if(fcn.apply(scope || this || window, arguments) === false){
780                 return;
781             }
782             return method.apply(this || window, arguments);
783         };
784     }
785 });
786 /*
787  * Based on:
788  * Ext JS Library 1.1.1
789  * Copyright(c) 2006-2007, Ext JS, LLC.
790  *
791  * Originally Released Under LGPL - original licence link has changed is not relivant.
792  *
793  * Fork - LGPL
794  * <script type="text/javascript">
795  */
796
797 Roo.applyIf(String, {
798     
799     /** @scope String */
800     
801     /**
802      * Escapes the passed string for ' and \
803      * @param {String} string The string to escape
804      * @return {String} The escaped string
805      * @static
806      */
807     escape : function(string) {
808         return string.replace(/('|\\)/g, "\\$1");
809     },
810
811     /**
812      * Pads the left side of a string with a specified character.  This is especially useful
813      * for normalizing number and date strings.  Example usage:
814      * <pre><code>
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
817 </code></pre>
818      * @param {String} string The original string
819      * @param {Number} size The total length of the output string
820      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821      * @return {String} The padded string
822      * @static
823      */
824     leftPad : function (val, size, ch) {
825         var result = new String(val);
826         if(ch === null || ch === undefined || ch === '') {
827             ch = " ";
828         }
829         while (result.length < size) {
830             result = ch + result;
831         }
832         return result;
833     },
834
835     /**
836      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
837      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
838      * <pre><code>
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
842 </code></pre>
843      * @param {String} string The tokenized string to be formatted
844      * @param {String} value1 The value to replace token {0}
845      * @param {String} value2 Etc...
846      * @return {String} The formatted string
847      * @static
848      */
849     format : function(format){
850         var args = Array.prototype.slice.call(arguments, 1);
851         return format.replace(/\{(\d+)\}/g, function(m, i){
852             return Roo.util.Format.htmlEncode(args[i]);
853         });
854     }
855 });
856
857 /**
858  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
859  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
860  * they are already different, the first value passed in is returned.  Note that this method returns the new value
861  * but does not change the current string.
862  * <pre><code>
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
865
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
868 </code></pre>
869  * @param {String} value The value to compare to the current string
870  * @param {String} other The new value to use if the string already equals the first value passed in
871  * @return {String} The new value
872  */
873  
874 String.prototype.toggle = function(value, other){
875     return this == value ? other : value;
876 };/*
877  * Based on:
878  * Ext JS Library 1.1.1
879  * Copyright(c) 2006-2007, Ext JS, LLC.
880  *
881  * Originally Released Under LGPL - original licence link has changed is not relivant.
882  *
883  * Fork - LGPL
884  * <script type="text/javascript">
885  */
886
887  /**
888  * @class Number
889  */
890 Roo.applyIf(Number.prototype, {
891     /**
892      * Checks whether or not the current number is within a desired range.  If the number is already within the
893      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894      * exceeded.  Note that this method returns the constrained value but does not change the current number.
895      * @param {Number} min The minimum number in the range
896      * @param {Number} max The maximum number in the range
897      * @return {Number} The constrained value if outside the range, otherwise the current value
898      */
899     constrain : function(min, max){
900         return Math.min(Math.max(this, min), max);
901     }
902 });/*
903  * Based on:
904  * Ext JS Library 1.1.1
905  * Copyright(c) 2006-2007, Ext JS, LLC.
906  *
907  * Originally Released Under LGPL - original licence link has changed is not relivant.
908  *
909  * Fork - LGPL
910  * <script type="text/javascript">
911  */
912  /**
913  * @class Array
914  */
915 Roo.applyIf(Array.prototype, {
916     /**
917      * Checks whether or not the specified object exists in the array.
918      * @param {Object} o The object to check for
919      * @return {Number} The index of o in the array (or -1 if it is not found)
920      */
921     indexOf : function(o){
922        for (var i = 0, len = this.length; i < len; i++){
923               if(this[i] == o) return i;
924        }
925            return -1;
926     },
927
928     /**
929      * Removes the specified object from the array.  If the object is not found nothing happens.
930      * @param {Object} o The object to remove
931      */
932     remove : function(o){
933        var index = this.indexOf(o);
934        if(index != -1){
935            this.splice(index, 1);
936        }
937     },
938     /**
939      * Map (JS 1.6 compatibility)
940      * @param {Function} function  to call
941      */
942     map : function(fun )
943     {
944         var len = this.length >>> 0;
945         if (typeof fun != "function")
946             throw new TypeError();
947
948         var res = new Array(len);
949         var thisp = arguments[1];
950         for (var i = 0; i < len; i++)
951         {
952             if (i in this)
953                 res[i] = fun.call(thisp, this[i], i, this);
954         }
955
956         return res;
957     }
958     
959 });
960
961
962  /*
963  * Based on:
964  * Ext JS Library 1.1.1
965  * Copyright(c) 2006-2007, Ext JS, LLC.
966  *
967  * Originally Released Under LGPL - original licence link has changed is not relivant.
968  *
969  * Fork - LGPL
970  * <script type="text/javascript">
971  */
972
973 /**
974  * @class Date
975  *
976  * The date parsing and format syntax is a subset of
977  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978  * supported will provide results equivalent to their PHP versions.
979  *
980  * Following is the list of all currently supported formats:
981  *<pre>
982 Sample date:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
984
985 Format  Output      Description
986 ------  ----------  --------------------------------------------------------------
987   d      10         Day of the month, 2 digits with leading zeros
988   D      Wed        A textual representation of a day, three letters
989   j      10         Day of the month without leading zeros
990   l      Wednesday  A full textual representation of the day of the week
991   S      th         English ordinal day of month suffix, 2 chars (use with j)
992   w      3          Numeric representation of the day of the week
993   z      9          The julian date, or day of the year (0-365)
994   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995   F      January    A full textual representation of the month
996   m      01         Numeric representation of a month, with leading zeros
997   M      Jan        Month name abbreviation, three letters
998   n      1          Numeric representation of a month, without leading zeros
999   t      31         Number of days in the given month
1000   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1001   Y      2007       A full numeric representation of a year, 4 digits
1002   y      07         A two digit representation of a year
1003   a      pm         Lowercase Ante meridiem and Post meridiem
1004   A      PM         Uppercase Ante meridiem and Post meridiem
1005   g      3          12-hour format of an hour without leading zeros
1006   G      15         24-hour format of an hour without leading zeros
1007   h      03         12-hour format of an hour with leading zeros
1008   H      15         24-hour format of an hour with leading zeros
1009   i      05         Minutes with leading zeros
1010   s      01         Seconds, with leading zeros
1011   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1013   T      CST        Timezone setting of the machine running the code
1014   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1015 </pre>
1016  *
1017  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1018  * <pre><code>
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d'));                         //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1023  </code></pre>
1024  *
1025  * Here are some standard date/time patterns that you might find helpful.  They
1026  * are not part of the source of Date.js, but to use them you can simply copy this
1027  * block of code into any script that is included after Date.js and they will also become
1028  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1029  * <pre><code>
1030 Date.patterns = {
1031     ISO8601Long:"Y-m-d H:i:s",
1032     ISO8601Short:"Y-m-d",
1033     ShortDate: "n/j/Y",
1034     LongDate: "l, F d, Y",
1035     FullDateTime: "l, F d, Y g:i:s A",
1036     MonthDay: "F d",
1037     ShortTime: "g:i A",
1038     LongTime: "g:i:s A",
1039     SortableDateTime: "Y-m-d\\TH:i:s",
1040     UniversalSortableDateTime: "Y-m-d H:i:sO",
1041     YearMonth: "F, Y"
1042 };
1043 </code></pre>
1044  *
1045  * Example usage:
1046  * <pre><code>
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1049  </code></pre>
1050  */
1051
1052 /*
1053  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054  * They generate precompiled functions from date formats instead of parsing and
1055  * processing the pattern every time you format a date.  These functions are available
1056  * on every Date object (any javascript function).
1057  *
1058  * The original article and download are here:
1059  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1060  *
1061  */
1062  
1063  
1064  // was in core
1065 /**
1066  Returns the number of milliseconds between this date and date
1067  @param {Date} date (optional) Defaults to now
1068  @return {Number} The diff in milliseconds
1069  @member Date getElapsed
1070  */
1071 Date.prototype.getElapsed = function(date) {
1072         return Math.abs((date || new Date()).getTime()-this.getTime());
1073 };
1074 // was in date file..
1075
1076
1077 // private
1078 Date.parseFunctions = {count:0};
1079 // private
1080 Date.parseRegexes = [];
1081 // private
1082 Date.formatFunctions = {count:0};
1083
1084 // private
1085 Date.prototype.dateFormat = function(format) {
1086     if (Date.formatFunctions[format] == null) {
1087         Date.createNewFormat(format);
1088     }
1089     var func = Date.formatFunctions[format];
1090     return this[func]();
1091 };
1092
1093
1094 /**
1095  * Formats a date given the supplied format string
1096  * @param {String} format The format string
1097  * @return {String} The formatted date
1098  * @method
1099  */
1100 Date.prototype.format = Date.prototype.dateFormat;
1101
1102 // private
1103 Date.createNewFormat = function(format) {
1104     var funcName = "format" + Date.formatFunctions.count++;
1105     Date.formatFunctions[format] = funcName;
1106     var code = "Date.prototype." + funcName + " = function(){return ";
1107     var special = false;
1108     var ch = '';
1109     for (var i = 0; i < format.length; ++i) {
1110         ch = format.charAt(i);
1111         if (!special && ch == "\\") {
1112             special = true;
1113         }
1114         else if (special) {
1115             special = false;
1116             code += "'" + String.escape(ch) + "' + ";
1117         }
1118         else {
1119             code += Date.getFormatCode(ch);
1120         }
1121     }
1122     /** eval:var:zzzzzzzzzzzzz */
1123     eval(code.substring(0, code.length - 3) + ";}");
1124 };
1125
1126 // private
1127 Date.getFormatCode = function(character) {
1128     switch (character) {
1129     case "d":
1130         return "String.leftPad(this.getDate(), 2, '0') + ";
1131     case "D":
1132         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1133     case "j":
1134         return "this.getDate() + ";
1135     case "l":
1136         return "Date.dayNames[this.getDay()] + ";
1137     case "S":
1138         return "this.getSuffix() + ";
1139     case "w":
1140         return "this.getDay() + ";
1141     case "z":
1142         return "this.getDayOfYear() + ";
1143     case "W":
1144         return "this.getWeekOfYear() + ";
1145     case "F":
1146         return "Date.monthNames[this.getMonth()] + ";
1147     case "m":
1148         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1149     case "M":
1150         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1151     case "n":
1152         return "(this.getMonth() + 1) + ";
1153     case "t":
1154         return "this.getDaysInMonth() + ";
1155     case "L":
1156         return "(this.isLeapYear() ? 1 : 0) + ";
1157     case "Y":
1158         return "this.getFullYear() + ";
1159     case "y":
1160         return "('' + this.getFullYear()).substring(2, 4) + ";
1161     case "a":
1162         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1163     case "A":
1164         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1165     case "g":
1166         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1167     case "G":
1168         return "this.getHours() + ";
1169     case "h":
1170         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1171     case "H":
1172         return "String.leftPad(this.getHours(), 2, '0') + ";
1173     case "i":
1174         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1175     case "s":
1176         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1177     case "O":
1178         return "this.getGMTOffset() + ";
1179     case "P":
1180         return "this.getGMTColonOffset() + ";
1181     case "T":
1182         return "this.getTimezone() + ";
1183     case "Z":
1184         return "(this.getTimezoneOffset() * -60) + ";
1185     default:
1186         return "'" + String.escape(character) + "' + ";
1187     }
1188 };
1189
1190 /**
1191  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1193  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1194  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1195  * string or the parse operation will fail.
1196  * Example Usage:
1197 <pre><code>
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1200
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1203
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1206
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1209 </code></pre>
1210  * @param {String} input The unparsed date as a string
1211  * @param {String} format The format the date is in
1212  * @return {Date} The parsed date
1213  * @static
1214  */
1215 Date.parseDate = function(input, format) {
1216     if (Date.parseFunctions[format] == null) {
1217         Date.createParser(format);
1218     }
1219     var func = Date.parseFunctions[format];
1220     return Date[func](input);
1221 };
1222 /**
1223  * @private
1224  */
1225 Date.createParser = function(format) {
1226     var funcName = "parse" + Date.parseFunctions.count++;
1227     var regexNum = Date.parseRegexes.length;
1228     var currentGroup = 1;
1229     Date.parseFunctions[format] = funcName;
1230
1231     var code = "Date." + funcName + " = function(input){\n"
1232         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233         + "var d = new Date();\n"
1234         + "y = d.getFullYear();\n"
1235         + "m = d.getMonth();\n"
1236         + "d = d.getDate();\n"
1237         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238         + "if (results && results.length > 0) {";
1239     var regex = "";
1240
1241     var special = false;
1242     var ch = '';
1243     for (var i = 0; i < format.length; ++i) {
1244         ch = format.charAt(i);
1245         if (!special && ch == "\\") {
1246             special = true;
1247         }
1248         else if (special) {
1249             special = false;
1250             regex += String.escape(ch);
1251         }
1252         else {
1253             var obj = Date.formatCodeToRegex(ch, currentGroup);
1254             currentGroup += obj.g;
1255             regex += obj.s;
1256             if (obj.g && obj.c) {
1257                 code += obj.c;
1258             }
1259         }
1260     }
1261
1262     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i, s);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265         + "{v = new Date(y, m, d, h, i);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267         + "{v = new Date(y, m, d, h);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269         + "{v = new Date(y, m, d);}\n"
1270         + "else if (y >= 0 && m >= 0)\n"
1271         + "{v = new Date(y, m);}\n"
1272         + "else if (y >= 0)\n"
1273         + "{v = new Date(y);}\n"
1274         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277         + ";}";
1278
1279     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280     /** eval:var:zzzzzzzzzzzzz */
1281     eval(code);
1282 };
1283
1284 // private
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286     switch (character) {
1287     case "D":
1288         return {g:0,
1289         c:null,
1290         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291     case "j":
1292         return {g:1,
1293             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294             s:"(\\d{1,2})"}; // day of month without leading zeroes
1295     case "d":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{2})"}; // day of month with leading zeroes
1299     case "l":
1300         return {g:0,
1301             c:null,
1302             s:"(?:" + Date.dayNames.join("|") + ")"};
1303     case "S":
1304         return {g:0,
1305             c:null,
1306             s:"(?:st|nd|rd|th)"};
1307     case "w":
1308         return {g:0,
1309             c:null,
1310             s:"\\d"};
1311     case "z":
1312         return {g:0,
1313             c:null,
1314             s:"(?:\\d{1,3})"};
1315     case "W":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{2})"};
1319     case "F":
1320         return {g:1,
1321             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322             s:"(" + Date.monthNames.join("|") + ")"};
1323     case "M":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327     case "n":
1328         return {g:1,
1329             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331     case "m":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1335     case "t":
1336         return {g:0,
1337             c:null,
1338             s:"\\d{1,2}"};
1339     case "L":
1340         return {g:0,
1341             c:null,
1342             s:"(?:1|0)"};
1343     case "Y":
1344         return {g:1,
1345             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1346             s:"(\\d{4})"};
1347     case "y":
1348         return {g:1,
1349             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1351             s:"(\\d{1,2})"};
1352     case "a":
1353         return {g:1,
1354             c:"if (results[" + currentGroup + "] == 'am') {\n"
1355                 + "if (h == 12) { h = 0; }\n"
1356                 + "} else { if (h < 12) { h += 12; }}",
1357             s:"(am|pm)"};
1358     case "A":
1359         return {g:1,
1360             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361                 + "if (h == 12) { h = 0; }\n"
1362                 + "} else { if (h < 12) { h += 12; }}",
1363             s:"(AM|PM)"};
1364     case "g":
1365     case "G":
1366         return {g:1,
1367             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1369     case "h":
1370     case "H":
1371         return {g:1,
1372             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1374     case "i":
1375         return {g:1,
1376             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"};
1378     case "s":
1379         return {g:1,
1380             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "O":
1383         return {g:1,
1384             c:[
1385                 "o = results[", currentGroup, "];\n",
1386                 "var sn = o.substring(0,1);\n", // get + / - sign
1387                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391             ].join(""),
1392             s:"([+\-]\\d{2,4})"};
1393     
1394     
1395     case "P":
1396         return {g:1,
1397                 c:[
1398                    "o = results[", currentGroup, "];\n",
1399                    "var sn = o.substring(0,1);\n",
1400                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401                    "var mn = o.substring(4,6) % 60;\n",
1402                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1404             ].join(""),
1405             s:"([+\-]\\d{4})"};
1406     case "T":
1407         return {g:0,
1408             c:null,
1409             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410     case "Z":
1411         return {g:1,
1412             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1415     default:
1416         return {g:0,
1417             c:null,
1418             s:String.escape(character)};
1419     }
1420 };
1421
1422 /**
1423  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424  * @return {String} The abbreviated timezone name (e.g. 'CST')
1425  */
1426 Date.prototype.getTimezone = function() {
1427     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1428 };
1429
1430 /**
1431  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1433  */
1434 Date.prototype.getGMTOffset = function() {
1435     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1438 };
1439
1440 /**
1441  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442  * @return {String} 2-characters representing hours and 2-characters representing minutes
1443  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1444  */
1445 Date.prototype.getGMTColonOffset = function() {
1446         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1448                 + ":"
1449                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1450 }
1451
1452 /**
1453  * Get the numeric day number of the year, adjusted for leap year.
1454  * @return {Number} 0 through 364 (365 in leap years)
1455  */
1456 Date.prototype.getDayOfYear = function() {
1457     var num = 0;
1458     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459     for (var i = 0; i < this.getMonth(); ++i) {
1460         num += Date.daysInMonth[i];
1461     }
1462     return num + this.getDate() - 1;
1463 };
1464
1465 /**
1466  * Get the string representation of the numeric week number of the year
1467  * (equivalent to the format specifier 'W').
1468  * @return {String} '00' through '52'
1469  */
1470 Date.prototype.getWeekOfYear = function() {
1471     // Skip to Thursday of this week
1472     var now = this.getDayOfYear() + (4 - this.getDay());
1473     // Find the first Thursday of the year
1474     var jan1 = new Date(this.getFullYear(), 0, 1);
1475     var then = (7 - jan1.getDay() + 4);
1476     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1477 };
1478
1479 /**
1480  * Whether or not the current date is in a leap year.
1481  * @return {Boolean} True if the current date is in a leap year, else false
1482  */
1483 Date.prototype.isLeapYear = function() {
1484     var year = this.getFullYear();
1485     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1486 };
1487
1488 /**
1489  * Get the first day of the current month, adjusted for leap year.  The returned value
1490  * is the numeric day index within the week (0-6) which can be used in conjunction with
1491  * the {@link #monthNames} array to retrieve the textual day name.
1492  * Example:
1493  *<pre><code>
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1496 </code></pre>
1497  * @return {Number} The day number (0-6)
1498  */
1499 Date.prototype.getFirstDayOfMonth = function() {
1500     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501     return (day < 0) ? (day + 7) : day;
1502 };
1503
1504 /**
1505  * Get the last day of the current month, adjusted for leap year.  The returned value
1506  * is the numeric day index within the week (0-6) which can be used in conjunction with
1507  * the {@link #monthNames} array to retrieve the textual day name.
1508  * Example:
1509  *<pre><code>
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1512 </code></pre>
1513  * @return {Number} The day number (0-6)
1514  */
1515 Date.prototype.getLastDayOfMonth = function() {
1516     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517     return (day < 0) ? (day + 7) : day;
1518 };
1519
1520
1521 /**
1522  * Get the first date of this date's month
1523  * @return {Date}
1524  */
1525 Date.prototype.getFirstDateOfMonth = function() {
1526     return new Date(this.getFullYear(), this.getMonth(), 1);
1527 };
1528
1529 /**
1530  * Get the last date of this date's month
1531  * @return {Date}
1532  */
1533 Date.prototype.getLastDateOfMonth = function() {
1534     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 };
1536 /**
1537  * Get the number of days in the current month, adjusted for leap year.
1538  * @return {Number} The number of days in the month
1539  */
1540 Date.prototype.getDaysInMonth = function() {
1541     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542     return Date.daysInMonth[this.getMonth()];
1543 };
1544
1545 /**
1546  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547  * @return {String} 'st, 'nd', 'rd' or 'th'
1548  */
1549 Date.prototype.getSuffix = function() {
1550     switch (this.getDate()) {
1551         case 1:
1552         case 21:
1553         case 31:
1554             return "st";
1555         case 2:
1556         case 22:
1557             return "nd";
1558         case 3:
1559         case 23:
1560             return "rd";
1561         default:
1562             return "th";
1563     }
1564 };
1565
1566 // private
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568
1569 /**
1570  * An array of textual month names.
1571  * Override these values for international dates, for example...
1572  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1573  * @type Array
1574  * @static
1575  */
1576 Date.monthNames =
1577    ["January",
1578     "February",
1579     "March",
1580     "April",
1581     "May",
1582     "June",
1583     "July",
1584     "August",
1585     "September",
1586     "October",
1587     "November",
1588     "December"];
1589
1590 /**
1591  * An array of textual day names.
1592  * Override these values for international dates, for example...
1593  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1594  * @type Array
1595  * @static
1596  */
1597 Date.dayNames =
1598    ["Sunday",
1599     "Monday",
1600     "Tuesday",
1601     "Wednesday",
1602     "Thursday",
1603     "Friday",
1604     "Saturday"];
1605
1606 // private
1607 Date.y2kYear = 50;
1608 // private
1609 Date.monthNumbers = {
1610     Jan:0,
1611     Feb:1,
1612     Mar:2,
1613     Apr:3,
1614     May:4,
1615     Jun:5,
1616     Jul:6,
1617     Aug:7,
1618     Sep:8,
1619     Oct:9,
1620     Nov:10,
1621     Dec:11};
1622
1623 /**
1624  * Creates and returns a new Date instance with the exact same date value as the called instance.
1625  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626  * variable will also be changed.  When the intention is to create a new variable that will not
1627  * modify the original instance, you should create a clone.
1628  *
1629  * Example of correctly cloning a date:
1630  * <pre><code>
1631 //wrong way:
1632 var orig = new Date('10/1/2006');
1633 var copy = orig;
1634 copy.setDate(5);
1635 document.write(orig);  //returns 'Thu Oct 05 2006'!
1636
1637 //correct way:
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1640 copy.setDate(5);
1641 document.write(orig);  //returns 'Thu Oct 01 2006'
1642 </code></pre>
1643  * @return {Date} The new Date instance
1644  */
1645 Date.prototype.clone = function() {
1646         return new Date(this.getTime());
1647 };
1648
1649 /**
1650  * Clears any time information from this date
1651  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652  @return {Date} this or the clone
1653  */
1654 Date.prototype.clearTime = function(clone){
1655     if(clone){
1656         return this.clone().clearTime();
1657     }
1658     this.setHours(0);
1659     this.setMinutes(0);
1660     this.setSeconds(0);
1661     this.setMilliseconds(0);
1662     return this;
1663 };
1664
1665 // private
1666 // safari setMonth is broken
1667 if(Roo.isSafari){
1668     Date.brokenSetMonth = Date.prototype.setMonth;
1669         Date.prototype.setMonth = function(num){
1670                 if(num <= -1){
1671                         var n = Math.ceil(-num);
1672                         var back_year = Math.ceil(n/12);
1673                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1674                         this.setFullYear(this.getFullYear() - back_year);
1675                         return Date.brokenSetMonth.call(this, month);
1676                 } else {
1677                         return Date.brokenSetMonth.apply(this, arguments);
1678                 }
1679         };
1680 }
1681
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.MILLI = "ms";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.SECOND = "s";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.MINUTE = "mi";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.HOUR = "h";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.DAY = "d";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MONTH = "mo";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.YEAR = "y";
1710
1711 /**
1712  * Provides a convenient method of performing basic date arithmetic.  This method
1713  * does not modify the Date instance being called - it creates and returns
1714  * a new Date instance containing the resulting date value.
1715  *
1716  * Examples:
1717  * <pre><code>
1718 //Basic usage:
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1721
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1725
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729  </code></pre>
1730  *
1731  * @param {String} interval   A valid date interval enum value
1732  * @param {Number} value      The amount to add to the current date
1733  * @return {Date} The new Date instance
1734  */
1735 Date.prototype.add = function(interval, value){
1736   var d = this.clone();
1737   if (!interval || value === 0) return d;
1738   switch(interval.toLowerCase()){
1739     case Date.MILLI:
1740       d.setMilliseconds(this.getMilliseconds() + value);
1741       break;
1742     case Date.SECOND:
1743       d.setSeconds(this.getSeconds() + value);
1744       break;
1745     case Date.MINUTE:
1746       d.setMinutes(this.getMinutes() + value);
1747       break;
1748     case Date.HOUR:
1749       d.setHours(this.getHours() + value);
1750       break;
1751     case Date.DAY:
1752       d.setDate(this.getDate() + value);
1753       break;
1754     case Date.MONTH:
1755       var day = this.getDate();
1756       if(day > 28){
1757           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758       }
1759       d.setDate(day);
1760       d.setMonth(this.getMonth() + value);
1761       break;
1762     case Date.YEAR:
1763       d.setFullYear(this.getFullYear() + value);
1764       break;
1765   }
1766   return d;
1767 };
1768 /*
1769  * Based on:
1770  * Ext JS Library 1.1.1
1771  * Copyright(c) 2006-2007, Ext JS, LLC.
1772  *
1773  * Originally Released Under LGPL - original licence link has changed is not relivant.
1774  *
1775  * Fork - LGPL
1776  * <script type="text/javascript">
1777  */
1778
1779 /**
1780  * @class Roo.lib.Dom
1781  * @static
1782  * 
1783  * Dom utils (from YIU afaik)
1784  * 
1785  **/
1786 Roo.lib.Dom = {
1787     /**
1788      * Get the view width
1789      * @param {Boolean} full True will get the full document, otherwise it's the view width
1790      * @return {Number} The width
1791      */
1792      
1793     getViewWidth : function(full) {
1794         return full ? this.getDocumentWidth() : this.getViewportWidth();
1795     },
1796     /**
1797      * Get the view height
1798      * @param {Boolean} full True will get the full document, otherwise it's the view height
1799      * @return {Number} The height
1800      */
1801     getViewHeight : function(full) {
1802         return full ? this.getDocumentHeight() : this.getViewportHeight();
1803     },
1804
1805     getDocumentHeight: function() {
1806         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807         return Math.max(scrollHeight, this.getViewportHeight());
1808     },
1809
1810     getDocumentWidth: function() {
1811         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812         return Math.max(scrollWidth, this.getViewportWidth());
1813     },
1814
1815     getViewportHeight: function() {
1816         var height = self.innerHeight;
1817         var mode = document.compatMode;
1818
1819         if ((mode || Roo.isIE) && !Roo.isOpera) {
1820             height = (mode == "CSS1Compat") ?
1821                      document.documentElement.clientHeight :
1822                      document.body.clientHeight;
1823         }
1824
1825         return height;
1826     },
1827
1828     getViewportWidth: function() {
1829         var width = self.innerWidth;
1830         var mode = document.compatMode;
1831
1832         if (mode || Roo.isIE) {
1833             width = (mode == "CSS1Compat") ?
1834                     document.documentElement.clientWidth :
1835                     document.body.clientWidth;
1836         }
1837         return width;
1838     },
1839
1840     isAncestor : function(p, c) {
1841         p = Roo.getDom(p);
1842         c = Roo.getDom(c);
1843         if (!p || !c) {
1844             return false;
1845         }
1846
1847         if (p.contains && !Roo.isSafari) {
1848             return p.contains(c);
1849         } else if (p.compareDocumentPosition) {
1850             return !!(p.compareDocumentPosition(c) & 16);
1851         } else {
1852             var parent = c.parentNode;
1853             while (parent) {
1854                 if (parent == p) {
1855                     return true;
1856                 }
1857                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858                     return false;
1859                 }
1860                 parent = parent.parentNode;
1861             }
1862             return false;
1863         }
1864     },
1865
1866     getRegion : function(el) {
1867         return Roo.lib.Region.getRegion(el);
1868     },
1869
1870     getY : function(el) {
1871         return this.getXY(el)[1];
1872     },
1873
1874     getX : function(el) {
1875         return this.getXY(el)[0];
1876     },
1877
1878     getXY : function(el) {
1879         var p, pe, b, scroll, bd = document.body;
1880         el = Roo.getDom(el);
1881         var fly = Roo.lib.AnimBase.fly;
1882         if (el.getBoundingClientRect) {
1883             b = el.getBoundingClientRect();
1884             scroll = fly(document).getScroll();
1885             return [b.left + scroll.left, b.top + scroll.top];
1886         }
1887         var x = 0, y = 0;
1888
1889         p = el;
1890
1891         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1892
1893         while (p) {
1894
1895             x += p.offsetLeft;
1896             y += p.offsetTop;
1897
1898             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1899                 hasAbsolute = true;
1900             }
1901
1902             if (Roo.isGecko) {
1903                 pe = fly(p);
1904
1905                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1907
1908
1909                 x += bl;
1910                 y += bt;
1911
1912
1913                 if (p != el && pe.getStyle('overflow') != 'visible') {
1914                     x += bl;
1915                     y += bt;
1916                 }
1917             }
1918             p = p.offsetParent;
1919         }
1920
1921         if (Roo.isSafari && hasAbsolute) {
1922             x -= bd.offsetLeft;
1923             y -= bd.offsetTop;
1924         }
1925
1926         if (Roo.isGecko && !hasAbsolute) {
1927             var dbd = fly(bd);
1928             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1930         }
1931
1932         p = el.parentNode;
1933         while (p && p != bd) {
1934             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1935                 x -= p.scrollLeft;
1936                 y -= p.scrollTop;
1937             }
1938             p = p.parentNode;
1939         }
1940         return [x, y];
1941     },
1942  
1943   
1944
1945
1946     setXY : function(el, xy) {
1947         el = Roo.fly(el, '_setXY');
1948         el.position();
1949         var pts = el.translatePoints(xy);
1950         if (xy[0] !== false) {
1951             el.dom.style.left = pts.left + "px";
1952         }
1953         if (xy[1] !== false) {
1954             el.dom.style.top = pts.top + "px";
1955         }
1956     },
1957
1958     setX : function(el, x) {
1959         this.setXY(el, [x, false]);
1960     },
1961
1962     setY : function(el, y) {
1963         this.setXY(el, [false, y]);
1964     }
1965 };
1966 /*
1967  * Portions of this file are based on pieces of Yahoo User Interface Library
1968  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969  * YUI licensed under the BSD License:
1970  * http://developer.yahoo.net/yui/license.txt
1971  * <script type="text/javascript">
1972  *
1973  */
1974
1975 Roo.lib.Event = function() {
1976     var loadComplete = false;
1977     var listeners = [];
1978     var unloadListeners = [];
1979     var retryCount = 0;
1980     var onAvailStack = [];
1981     var counter = 0;
1982     var lastError = null;
1983
1984     return {
1985         POLL_RETRYS: 200,
1986         POLL_INTERVAL: 20,
1987         EL: 0,
1988         TYPE: 1,
1989         FN: 2,
1990         WFN: 3,
1991         OBJ: 3,
1992         ADJ_SCOPE: 4,
1993         _interval: null,
1994
1995         startInterval: function() {
1996             if (!this._interval) {
1997                 var self = this;
1998                 var callback = function() {
1999                     self._tryPreloadAttach();
2000                 };
2001                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2002
2003             }
2004         },
2005
2006         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007             onAvailStack.push({ id:         p_id,
2008                 fn:         p_fn,
2009                 obj:        p_obj,
2010                 override:   p_override,
2011                 checkReady: false    });
2012
2013             retryCount = this.POLL_RETRYS;
2014             this.startInterval();
2015         },
2016
2017
2018         addListener: function(el, eventName, fn) {
2019             el = Roo.getDom(el);
2020             if (!el || !fn) {
2021                 return false;
2022             }
2023
2024             if ("unload" == eventName) {
2025                 unloadListeners[unloadListeners.length] =
2026                 [el, eventName, fn];
2027                 return true;
2028             }
2029
2030             var wrappedFn = function(e) {
2031                 return fn(Roo.lib.Event.getEvent(e));
2032             };
2033
2034             var li = [el, eventName, fn, wrappedFn];
2035
2036             var index = listeners.length;
2037             listeners[index] = li;
2038
2039             this.doAdd(el, eventName, wrappedFn, false);
2040             return true;
2041
2042         },
2043
2044
2045         removeListener: function(el, eventName, fn) {
2046             var i, len;
2047
2048             el = Roo.getDom(el);
2049
2050             if(!fn) {
2051                 return this.purgeElement(el, false, eventName);
2052             }
2053
2054
2055             if ("unload" == eventName) {
2056
2057                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058                     var li = unloadListeners[i];
2059                     if (li &&
2060                         li[0] == el &&
2061                         li[1] == eventName &&
2062                         li[2] == fn) {
2063                         unloadListeners.splice(i, 1);
2064                         return true;
2065                     }
2066                 }
2067
2068                 return false;
2069             }
2070
2071             var cacheItem = null;
2072
2073
2074             var index = arguments[3];
2075
2076             if ("undefined" == typeof index) {
2077                 index = this._getCacheIndex(el, eventName, fn);
2078             }
2079
2080             if (index >= 0) {
2081                 cacheItem = listeners[index];
2082             }
2083
2084             if (!el || !cacheItem) {
2085                 return false;
2086             }
2087
2088             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2089
2090             delete listeners[index][this.WFN];
2091             delete listeners[index][this.FN];
2092             listeners.splice(index, 1);
2093
2094             return true;
2095
2096         },
2097
2098
2099         getTarget: function(ev, resolveTextNode) {
2100             ev = ev.browserEvent || ev;
2101             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2102             var t = ev.target || ev.srcElement;
2103             return this.resolveTextNode(t);
2104         },
2105
2106
2107         resolveTextNode: function(node) {
2108             if (Roo.isSafari && node && 3 == node.nodeType) {
2109                 return node.parentNode;
2110             } else {
2111                 return node;
2112             }
2113         },
2114
2115
2116         getPageX: function(ev) {
2117             ev = ev.browserEvent || ev;
2118             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2119             var x = ev.pageX;
2120             if (!x && 0 !== x) {
2121                 x = ev.clientX || 0;
2122
2123                 if (Roo.isIE) {
2124                     x += this.getScroll()[1];
2125                 }
2126             }
2127
2128             return x;
2129         },
2130
2131
2132         getPageY: function(ev) {
2133             ev = ev.browserEvent || ev;
2134             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2135             var y = ev.pageY;
2136             if (!y && 0 !== y) {
2137                 y = ev.clientY || 0;
2138
2139                 if (Roo.isIE) {
2140                     y += this.getScroll()[0];
2141                 }
2142             }
2143
2144
2145             return y;
2146         },
2147
2148
2149         getXY: function(ev) {
2150             ev = ev.browserEvent || ev;
2151             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2152             return [this.getPageX(ev), this.getPageY(ev)];
2153         },
2154
2155
2156         getRelatedTarget: function(ev) {
2157             ev = ev.browserEvent || ev;
2158             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2159             var t = ev.relatedTarget;
2160             if (!t) {
2161                 if (ev.type == "mouseout") {
2162                     t = ev.toElement;
2163                 } else if (ev.type == "mouseover") {
2164                     t = ev.fromElement;
2165                 }
2166             }
2167
2168             return this.resolveTextNode(t);
2169         },
2170
2171
2172         getTime: function(ev) {
2173             ev = ev.browserEvent || ev;
2174             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2175             if (!ev.time) {
2176                 var t = new Date().getTime();
2177                 try {
2178                     ev.time = t;
2179                 } catch(ex) {
2180                     this.lastError = ex;
2181                     return t;
2182                 }
2183             }
2184
2185             return ev.time;
2186         },
2187
2188
2189         stopEvent: function(ev) {
2190             this.stopPropagation(ev);
2191             this.preventDefault(ev);
2192         },
2193
2194
2195         stopPropagation: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             if (ev.stopPropagation) {
2198                 ev.stopPropagation();
2199             } else {
2200                 ev.cancelBubble = true;
2201             }
2202         },
2203
2204
2205         preventDefault: function(ev) {
2206             ev = ev.browserEvent || ev;
2207             if(ev.preventDefault) {
2208                 ev.preventDefault();
2209             } else {
2210                 ev.returnValue = false;
2211             }
2212         },
2213
2214
2215         getEvent: function(e) {
2216             var ev = e || window.event;
2217             if (!ev) {
2218                 var c = this.getEvent.caller;
2219                 while (c) {
2220                     ev = c.arguments[0];
2221                     if (ev && Event == ev.constructor) {
2222                         break;
2223                     }
2224                     c = c.caller;
2225                 }
2226             }
2227             return ev;
2228         },
2229
2230
2231         getCharCode: function(ev) {
2232             ev = ev.browserEvent || ev;
2233             return ev.charCode || ev.keyCode || 0;
2234         },
2235
2236
2237         _getCacheIndex: function(el, eventName, fn) {
2238             for (var i = 0,len = listeners.length; i < len; ++i) {
2239                 var li = listeners[i];
2240                 if (li &&
2241                     li[this.FN] == fn &&
2242                     li[this.EL] == el &&
2243                     li[this.TYPE] == eventName) {
2244                     return i;
2245                 }
2246             }
2247
2248             return -1;
2249         },
2250
2251
2252         elCache: {},
2253
2254
2255         getEl: function(id) {
2256             return document.getElementById(id);
2257         },
2258
2259
2260         clearCache: function() {
2261         },
2262
2263
2264         _load: function(e) {
2265             loadComplete = true;
2266             var EU = Roo.lib.Event;
2267
2268
2269             if (Roo.isIE) {
2270                 EU.doRemove(window, "load", EU._load);
2271             }
2272         },
2273
2274
2275         _tryPreloadAttach: function() {
2276
2277             if (this.locked) {
2278                 return false;
2279             }
2280
2281             this.locked = true;
2282
2283
2284             var tryAgain = !loadComplete;
2285             if (!tryAgain) {
2286                 tryAgain = (retryCount > 0);
2287             }
2288
2289
2290             var notAvail = [];
2291             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292                 var item = onAvailStack[i];
2293                 if (item) {
2294                     var el = this.getEl(item.id);
2295
2296                     if (el) {
2297                         if (!item.checkReady ||
2298                             loadComplete ||
2299                             el.nextSibling ||
2300                             (document && document.body)) {
2301
2302                             var scope = el;
2303                             if (item.override) {
2304                                 if (item.override === true) {
2305                                     scope = item.obj;
2306                                 } else {
2307                                     scope = item.override;
2308                                 }
2309                             }
2310                             item.fn.call(scope, item.obj);
2311                             onAvailStack[i] = null;
2312                         }
2313                     } else {
2314                         notAvail.push(item);
2315                     }
2316                 }
2317             }
2318
2319             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2320
2321             if (tryAgain) {
2322
2323                 this.startInterval();
2324             } else {
2325                 clearInterval(this._interval);
2326                 this._interval = null;
2327             }
2328
2329             this.locked = false;
2330
2331             return true;
2332
2333         },
2334
2335
2336         purgeElement: function(el, recurse, eventName) {
2337             var elListeners = this.getListeners(el, eventName);
2338             if (elListeners) {
2339                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340                     var l = elListeners[i];
2341                     this.removeListener(el, l.type, l.fn);
2342                 }
2343             }
2344
2345             if (recurse && el && el.childNodes) {
2346                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347                     this.purgeElement(el.childNodes[i], recurse, eventName);
2348                 }
2349             }
2350         },
2351
2352
2353         getListeners: function(el, eventName) {
2354             var results = [], searchLists;
2355             if (!eventName) {
2356                 searchLists = [listeners, unloadListeners];
2357             } else if (eventName == "unload") {
2358                 searchLists = [unloadListeners];
2359             } else {
2360                 searchLists = [listeners];
2361             }
2362
2363             for (var j = 0; j < searchLists.length; ++j) {
2364                 var searchList = searchLists[j];
2365                 if (searchList && searchList.length > 0) {
2366                     for (var i = 0,len = searchList.length; i < len; ++i) {
2367                         var l = searchList[i];
2368                         if (l && l[this.EL] === el &&
2369                             (!eventName || eventName === l[this.TYPE])) {
2370                             results.push({
2371                                 type:   l[this.TYPE],
2372                                 fn:     l[this.FN],
2373                                 obj:    l[this.OBJ],
2374                                 adjust: l[this.ADJ_SCOPE],
2375                                 index:  i
2376                             });
2377                         }
2378                     }
2379                 }
2380             }
2381
2382             return (results.length) ? results : null;
2383         },
2384
2385
2386         _unload: function(e) {
2387
2388             var EU = Roo.lib.Event, i, j, l, len, index;
2389
2390             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391                 l = unloadListeners[i];
2392                 if (l) {
2393                     var scope = window;
2394                     if (l[EU.ADJ_SCOPE]) {
2395                         if (l[EU.ADJ_SCOPE] === true) {
2396                             scope = l[EU.OBJ];
2397                         } else {
2398                             scope = l[EU.ADJ_SCOPE];
2399                         }
2400                     }
2401                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402                     unloadListeners[i] = null;
2403                     l = null;
2404                     scope = null;
2405                 }
2406             }
2407
2408             unloadListeners = null;
2409
2410             if (listeners && listeners.length > 0) {
2411                 j = listeners.length;
2412                 while (j) {
2413                     index = j - 1;
2414                     l = listeners[index];
2415                     if (l) {
2416                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2417                                 l[EU.FN], index);
2418                     }
2419                     j = j - 1;
2420                 }
2421                 l = null;
2422
2423                 EU.clearCache();
2424             }
2425
2426             EU.doRemove(window, "unload", EU._unload);
2427
2428         },
2429
2430
2431         getScroll: function() {
2432             var dd = document.documentElement, db = document.body;
2433             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434                 return [dd.scrollTop, dd.scrollLeft];
2435             } else if (db) {
2436                 return [db.scrollTop, db.scrollLeft];
2437             } else {
2438                 return [0, 0];
2439             }
2440         },
2441
2442
2443         doAdd: function () {
2444             if (window.addEventListener) {
2445                 return function(el, eventName, fn, capture) {
2446                     el.addEventListener(eventName, fn, (capture));
2447                 };
2448             } else if (window.attachEvent) {
2449                 return function(el, eventName, fn, capture) {
2450                     el.attachEvent("on" + eventName, fn);
2451                 };
2452             } else {
2453                 return function() {
2454                 };
2455             }
2456         }(),
2457
2458
2459         doRemove: function() {
2460             if (window.removeEventListener) {
2461                 return function (el, eventName, fn, capture) {
2462                     el.removeEventListener(eventName, fn, (capture));
2463                 };
2464             } else if (window.detachEvent) {
2465                 return function (el, eventName, fn) {
2466                     el.detachEvent("on" + eventName, fn);
2467                 };
2468             } else {
2469                 return function() {
2470                 };
2471             }
2472         }()
2473     };
2474     
2475 }();
2476 (function() {     
2477    
2478     var E = Roo.lib.Event;
2479     E.on = E.addListener;
2480     E.un = E.removeListener;
2481
2482     if (document && document.body) {
2483         E._load();
2484     } else {
2485         E.doAdd(window, "load", E._load);
2486     }
2487     E.doAdd(window, "unload", E._unload);
2488     E._tryPreloadAttach();
2489 })();
2490
2491 /*
2492  * Portions of this file are based on pieces of Yahoo User Interface Library
2493  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494  * YUI licensed under the BSD License:
2495  * http://developer.yahoo.net/yui/license.txt
2496  * <script type="text/javascript">
2497  *
2498  */
2499
2500 (function() {
2501     /**
2502      * @class Roo.lib.Ajax
2503      *
2504      */
2505     Roo.lib.Ajax = {
2506         /**
2507          * @static 
2508          */
2509         request : function(method, uri, cb, data, options) {
2510             if(options){
2511                 var hs = options.headers;
2512                 if(hs){
2513                     for(var h in hs){
2514                         if(hs.hasOwnProperty(h)){
2515                             this.initHeader(h, hs[h], false);
2516                         }
2517                     }
2518                 }
2519                 if(options.xmlData){
2520                     this.initHeader('Content-Type', 'text/xml', false);
2521                     method = 'POST';
2522                     data = options.xmlData;
2523                 }
2524             }
2525
2526             return this.asyncRequest(method, uri, cb, data);
2527         },
2528
2529         serializeForm : function(form) {
2530             if(typeof form == 'string') {
2531                 form = (document.getElementById(form) || document.forms[form]);
2532             }
2533
2534             var el, name, val, disabled, data = '', hasSubmit = false;
2535             for (var i = 0; i < form.elements.length; i++) {
2536                 el = form.elements[i];
2537                 disabled = form.elements[i].disabled;
2538                 name = form.elements[i].name;
2539                 val = form.elements[i].value;
2540
2541                 if (!disabled && name){
2542                     switch (el.type)
2543                             {
2544                         case 'select-one':
2545                         case 'select-multiple':
2546                             for (var j = 0; j < el.options.length; j++) {
2547                                 if (el.options[j].selected) {
2548                                     if (Roo.isIE) {
2549                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2550                                     }
2551                                     else {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                 }
2555                             }
2556                             break;
2557                         case 'radio':
2558                         case 'checkbox':
2559                             if (el.checked) {
2560                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2561                             }
2562                             break;
2563                         case 'file':
2564
2565                         case undefined:
2566
2567                         case 'reset':
2568
2569                         case 'button':
2570
2571                             break;
2572                         case 'submit':
2573                             if(hasSubmit == false) {
2574                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2575                                 hasSubmit = true;
2576                             }
2577                             break;
2578                         default:
2579                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2580                             break;
2581                     }
2582                 }
2583             }
2584             data = data.substr(0, data.length - 1);
2585             return data;
2586         },
2587
2588         headers:{},
2589
2590         hasHeaders:false,
2591
2592         useDefaultHeader:true,
2593
2594         defaultPostHeader:'application/x-www-form-urlencoded',
2595
2596         useDefaultXhrHeader:true,
2597
2598         defaultXhrHeader:'XMLHttpRequest',
2599
2600         hasDefaultHeaders:true,
2601
2602         defaultHeaders:{},
2603
2604         poll:{},
2605
2606         timeout:{},
2607
2608         pollInterval:50,
2609
2610         transactionId:0,
2611
2612         setProgId:function(id)
2613         {
2614             this.activeX.unshift(id);
2615         },
2616
2617         setDefaultPostHeader:function(b)
2618         {
2619             this.useDefaultHeader = b;
2620         },
2621
2622         setDefaultXhrHeader:function(b)
2623         {
2624             this.useDefaultXhrHeader = b;
2625         },
2626
2627         setPollingInterval:function(i)
2628         {
2629             if (typeof i == 'number' && isFinite(i)) {
2630                 this.pollInterval = i;
2631             }
2632         },
2633
2634         createXhrObject:function(transactionId)
2635         {
2636             var obj,http;
2637             try
2638             {
2639
2640                 http = new XMLHttpRequest();
2641
2642                 obj = { conn:http, tId:transactionId };
2643             }
2644             catch(e)
2645             {
2646                 for (var i = 0; i < this.activeX.length; ++i) {
2647                     try
2648                     {
2649
2650                         http = new ActiveXObject(this.activeX[i]);
2651
2652                         obj = { conn:http, tId:transactionId };
2653                         break;
2654                     }
2655                     catch(e) {
2656                     }
2657                 }
2658             }
2659             finally
2660             {
2661                 return obj;
2662             }
2663         },
2664
2665         getConnectionObject:function()
2666         {
2667             var o;
2668             var tId = this.transactionId;
2669
2670             try
2671             {
2672                 o = this.createXhrObject(tId);
2673                 if (o) {
2674                     this.transactionId++;
2675                 }
2676             }
2677             catch(e) {
2678             }
2679             finally
2680             {
2681                 return o;
2682             }
2683         },
2684
2685         asyncRequest:function(method, uri, callback, postData)
2686         {
2687             var o = this.getConnectionObject();
2688
2689             if (!o) {
2690                 return null;
2691             }
2692             else {
2693                 o.conn.open(method, uri, true);
2694
2695                 if (this.useDefaultXhrHeader) {
2696                     if (!this.defaultHeaders['X-Requested-With']) {
2697                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2698                     }
2699                 }
2700
2701                 if(postData && this.useDefaultHeader){
2702                     this.initHeader('Content-Type', this.defaultPostHeader);
2703                 }
2704
2705                  if (this.hasDefaultHeaders || this.hasHeaders) {
2706                     this.setHeader(o);
2707                 }
2708
2709                 this.handleReadyState(o, callback);
2710                 o.conn.send(postData || null);
2711
2712                 return o;
2713             }
2714         },
2715
2716         handleReadyState:function(o, callback)
2717         {
2718             var oConn = this;
2719
2720             if (callback && callback.timeout) {
2721                 
2722                 this.timeout[o.tId] = window.setTimeout(function() {
2723                     oConn.abort(o, callback, true);
2724                 }, callback.timeout);
2725             }
2726
2727             this.poll[o.tId] = window.setInterval(
2728                     function() {
2729                         if (o.conn && o.conn.readyState == 4) {
2730                             window.clearInterval(oConn.poll[o.tId]);
2731                             delete oConn.poll[o.tId];
2732
2733                             if(callback && callback.timeout) {
2734                                 window.clearTimeout(oConn.timeout[o.tId]);
2735                                 delete oConn.timeout[o.tId];
2736                             }
2737
2738                             oConn.handleTransactionResponse(o, callback);
2739                         }
2740                     }
2741                     , this.pollInterval);
2742         },
2743
2744         handleTransactionResponse:function(o, callback, isAbort)
2745         {
2746
2747             if (!callback) {
2748                 this.releaseObject(o);
2749                 return;
2750             }
2751
2752             var httpStatus, responseObject;
2753
2754             try
2755             {
2756                 if (o.conn.status !== undefined && o.conn.status != 0) {
2757                     httpStatus = o.conn.status;
2758                 }
2759                 else {
2760                     httpStatus = 13030;
2761                 }
2762             }
2763             catch(e) {
2764
2765
2766                 httpStatus = 13030;
2767             }
2768
2769             if (httpStatus >= 200 && httpStatus < 300) {
2770                 responseObject = this.createResponseObject(o, callback.argument);
2771                 if (callback.success) {
2772                     if (!callback.scope) {
2773                         callback.success(responseObject);
2774                     }
2775                     else {
2776
2777
2778                         callback.success.apply(callback.scope, [responseObject]);
2779                     }
2780                 }
2781             }
2782             else {
2783                 switch (httpStatus) {
2784
2785                     case 12002:
2786                     case 12029:
2787                     case 12030:
2788                     case 12031:
2789                     case 12152:
2790                     case 13030:
2791                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792                         if (callback.failure) {
2793                             if (!callback.scope) {
2794                                 callback.failure(responseObject);
2795                             }
2796                             else {
2797                                 callback.failure.apply(callback.scope, [responseObject]);
2798                             }
2799                         }
2800                         break;
2801                     default:
2802                         responseObject = this.createResponseObject(o, callback.argument);
2803                         if (callback.failure) {
2804                             if (!callback.scope) {
2805                                 callback.failure(responseObject);
2806                             }
2807                             else {
2808                                 callback.failure.apply(callback.scope, [responseObject]);
2809                             }
2810                         }
2811                 }
2812             }
2813
2814             this.releaseObject(o);
2815             responseObject = null;
2816         },
2817
2818         createResponseObject:function(o, callbackArg)
2819         {
2820             var obj = {};
2821             var headerObj = {};
2822
2823             try
2824             {
2825                 var headerStr = o.conn.getAllResponseHeaders();
2826                 var header = headerStr.split('\n');
2827                 for (var i = 0; i < header.length; i++) {
2828                     var delimitPos = header[i].indexOf(':');
2829                     if (delimitPos != -1) {
2830                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2831                     }
2832                 }
2833             }
2834             catch(e) {
2835             }
2836
2837             obj.tId = o.tId;
2838             obj.status = o.conn.status;
2839             obj.statusText = o.conn.statusText;
2840             obj.getResponseHeader = headerObj;
2841             obj.getAllResponseHeaders = headerStr;
2842             obj.responseText = o.conn.responseText;
2843             obj.responseXML = o.conn.responseXML;
2844
2845             if (typeof callbackArg !== undefined) {
2846                 obj.argument = callbackArg;
2847             }
2848
2849             return obj;
2850         },
2851
2852         createExceptionObject:function(tId, callbackArg, isAbort)
2853         {
2854             var COMM_CODE = 0;
2855             var COMM_ERROR = 'communication failure';
2856             var ABORT_CODE = -1;
2857             var ABORT_ERROR = 'transaction aborted';
2858
2859             var obj = {};
2860
2861             obj.tId = tId;
2862             if (isAbort) {
2863                 obj.status = ABORT_CODE;
2864                 obj.statusText = ABORT_ERROR;
2865             }
2866             else {
2867                 obj.status = COMM_CODE;
2868                 obj.statusText = COMM_ERROR;
2869             }
2870
2871             if (callbackArg) {
2872                 obj.argument = callbackArg;
2873             }
2874
2875             return obj;
2876         },
2877
2878         initHeader:function(label, value, isDefault)
2879         {
2880             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2881
2882             if (headerObj[label] === undefined) {
2883                 headerObj[label] = value;
2884             }
2885             else {
2886
2887
2888                 headerObj[label] = value + "," + headerObj[label];
2889             }
2890
2891             if (isDefault) {
2892                 this.hasDefaultHeaders = true;
2893             }
2894             else {
2895                 this.hasHeaders = true;
2896             }
2897         },
2898
2899
2900         setHeader:function(o)
2901         {
2902             if (this.hasDefaultHeaders) {
2903                 for (var prop in this.defaultHeaders) {
2904                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2905                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2906                     }
2907                 }
2908             }
2909
2910             if (this.hasHeaders) {
2911                 for (var prop in this.headers) {
2912                     if (this.headers.hasOwnProperty(prop)) {
2913                         o.conn.setRequestHeader(prop, this.headers[prop]);
2914                     }
2915                 }
2916                 this.headers = {};
2917                 this.hasHeaders = false;
2918             }
2919         },
2920
2921         resetDefaultHeaders:function() {
2922             delete this.defaultHeaders;
2923             this.defaultHeaders = {};
2924             this.hasDefaultHeaders = false;
2925         },
2926
2927         abort:function(o, callback, isTimeout)
2928         {
2929             if(this.isCallInProgress(o)) {
2930                 o.conn.abort();
2931                 window.clearInterval(this.poll[o.tId]);
2932                 delete this.poll[o.tId];
2933                 if (isTimeout) {
2934                     delete this.timeout[o.tId];
2935                 }
2936
2937                 this.handleTransactionResponse(o, callback, true);
2938
2939                 return true;
2940             }
2941             else {
2942                 return false;
2943             }
2944         },
2945
2946
2947         isCallInProgress:function(o)
2948         {
2949             if (o && o.conn) {
2950                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2951             }
2952             else {
2953
2954                 return false;
2955             }
2956         },
2957
2958
2959         releaseObject:function(o)
2960         {
2961
2962             o.conn = null;
2963
2964             o = null;
2965         },
2966
2967         activeX:[
2968         'MSXML2.XMLHTTP.3.0',
2969         'MSXML2.XMLHTTP',
2970         'Microsoft.XMLHTTP'
2971         ]
2972
2973
2974     };
2975 })();/*
2976  * Portions of this file are based on pieces of Yahoo User Interface Library
2977  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978  * YUI licensed under the BSD License:
2979  * http://developer.yahoo.net/yui/license.txt
2980  * <script type="text/javascript">
2981  *
2982  */
2983
2984 Roo.lib.Region = function(t, r, b, l) {
2985     this.top = t;
2986     this[1] = t;
2987     this.right = r;
2988     this.bottom = b;
2989     this.left = l;
2990     this[0] = l;
2991 };
2992
2993
2994 Roo.lib.Region.prototype = {
2995     contains : function(region) {
2996         return ( region.left >= this.left &&
2997                  region.right <= this.right &&
2998                  region.top >= this.top &&
2999                  region.bottom <= this.bottom    );
3000
3001     },
3002
3003     getArea : function() {
3004         return ( (this.bottom - this.top) * (this.right - this.left) );
3005     },
3006
3007     intersect : function(region) {
3008         var t = Math.max(this.top, region.top);
3009         var r = Math.min(this.right, region.right);
3010         var b = Math.min(this.bottom, region.bottom);
3011         var l = Math.max(this.left, region.left);
3012
3013         if (b >= t && r >= l) {
3014             return new Roo.lib.Region(t, r, b, l);
3015         } else {
3016             return null;
3017         }
3018     },
3019     union : function(region) {
3020         var t = Math.min(this.top, region.top);
3021         var r = Math.max(this.right, region.right);
3022         var b = Math.max(this.bottom, region.bottom);
3023         var l = Math.min(this.left, region.left);
3024
3025         return new Roo.lib.Region(t, r, b, l);
3026     },
3027
3028     adjust : function(t, l, b, r) {
3029         this.top += t;
3030         this.left += l;
3031         this.right += r;
3032         this.bottom += b;
3033         return this;
3034     }
3035 };
3036
3037 Roo.lib.Region.getRegion = function(el) {
3038     var p = Roo.lib.Dom.getXY(el);
3039
3040     var t = p[1];
3041     var r = p[0] + el.offsetWidth;
3042     var b = p[1] + el.offsetHeight;
3043     var l = p[0];
3044
3045     return new Roo.lib.Region(t, r, b, l);
3046 };
3047 /*
3048  * Portions of this file are based on pieces of Yahoo User Interface Library
3049  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050  * YUI licensed under the BSD License:
3051  * http://developer.yahoo.net/yui/license.txt
3052  * <script type="text/javascript">
3053  *
3054  */
3055 //@@dep Roo.lib.Region
3056
3057
3058 Roo.lib.Point = function(x, y) {
3059     if (x instanceof Array) {
3060         y = x[1];
3061         x = x[0];
3062     }
3063     this.x = this.right = this.left = this[0] = x;
3064     this.y = this.top = this.bottom = this[1] = y;
3065 };
3066
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3068 /*
3069  * Portions of this file are based on pieces of Yahoo User Interface Library
3070  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071  * YUI licensed under the BSD License:
3072  * http://developer.yahoo.net/yui/license.txt
3073  * <script type="text/javascript">
3074  *
3075  */
3076  
3077 (function() {   
3078
3079     Roo.lib.Anim = {
3080         scroll : function(el, args, duration, easing, cb, scope) {
3081             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3082         },
3083
3084         motion : function(el, args, duration, easing, cb, scope) {
3085             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3086         },
3087
3088         color : function(el, args, duration, easing, cb, scope) {
3089             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3090         },
3091
3092         run : function(el, args, duration, easing, cb, scope, type) {
3093             type = type || Roo.lib.AnimBase;
3094             if (typeof easing == "string") {
3095                 easing = Roo.lib.Easing[easing];
3096             }
3097             var anim = new type(el, args, duration, easing);
3098             anim.animateX(function() {
3099                 Roo.callback(cb, scope);
3100             });
3101             return anim;
3102         }
3103     };
3104 })();/*
3105  * Portions of this file are based on pieces of Yahoo User Interface Library
3106  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107  * YUI licensed under the BSD License:
3108  * http://developer.yahoo.net/yui/license.txt
3109  * <script type="text/javascript">
3110  *
3111  */
3112
3113 (function() {    
3114     var libFlyweight;
3115     
3116     function fly(el) {
3117         if (!libFlyweight) {
3118             libFlyweight = new Roo.Element.Flyweight();
3119         }
3120         libFlyweight.dom = el;
3121         return libFlyweight;
3122     }
3123
3124     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3125     
3126    
3127     
3128     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3129         if (el) {
3130             this.init(el, attributes, duration, method);
3131         }
3132     };
3133
3134     Roo.lib.AnimBase.fly = fly;
3135     
3136     
3137     
3138     Roo.lib.AnimBase.prototype = {
3139
3140         toString: function() {
3141             var el = this.getEl();
3142             var id = el.id || el.tagName;
3143             return ("Anim " + id);
3144         },
3145
3146         patterns: {
3147             noNegatives:        /width|height|opacity|padding/i,
3148             offsetAttribute:  /^((width|height)|(top|left))$/,
3149             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3150             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3151         },
3152
3153
3154         doMethod: function(attr, start, end) {
3155             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3156         },
3157
3158
3159         setAttribute: function(attr, val, unit) {
3160             if (this.patterns.noNegatives.test(attr)) {
3161                 val = (val > 0) ? val : 0;
3162             }
3163
3164             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3165         },
3166
3167
3168         getAttribute: function(attr) {
3169             var el = this.getEl();
3170             var val = fly(el).getStyle(attr);
3171
3172             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173                 return parseFloat(val);
3174             }
3175
3176             var a = this.patterns.offsetAttribute.exec(attr) || [];
3177             var pos = !!( a[3] );
3178             var box = !!( a[2] );
3179
3180
3181             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3183             } else {
3184                 val = 0;
3185             }
3186
3187             return val;
3188         },
3189
3190
3191         getDefaultUnit: function(attr) {
3192             if (this.patterns.defaultUnit.test(attr)) {
3193                 return 'px';
3194             }
3195
3196             return '';
3197         },
3198
3199         animateX : function(callback, scope) {
3200             var f = function() {
3201                 this.onComplete.removeListener(f);
3202                 if (typeof callback == "function") {
3203                     callback.call(scope || this, this);
3204                 }
3205             };
3206             this.onComplete.addListener(f, this);
3207             this.animate();
3208         },
3209
3210
3211         setRuntimeAttribute: function(attr) {
3212             var start;
3213             var end;
3214             var attributes = this.attributes;
3215
3216             this.runtimeAttributes[attr] = {};
3217
3218             var isset = function(prop) {
3219                 return (typeof prop !== 'undefined');
3220             };
3221
3222             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3223                 return false;
3224             }
3225
3226             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3227
3228
3229             if (isset(attributes[attr]['to'])) {
3230                 end = attributes[attr]['to'];
3231             } else if (isset(attributes[attr]['by'])) {
3232                 if (start.constructor == Array) {
3233                     end = [];
3234                     for (var i = 0, len = start.length; i < len; ++i) {
3235                         end[i] = start[i] + attributes[attr]['by'][i];
3236                     }
3237                 } else {
3238                     end = start + attributes[attr]['by'];
3239                 }
3240             }
3241
3242             this.runtimeAttributes[attr].start = start;
3243             this.runtimeAttributes[attr].end = end;
3244
3245
3246             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3247         },
3248
3249
3250         init: function(el, attributes, duration, method) {
3251
3252             var isAnimated = false;
3253
3254
3255             var startTime = null;
3256
3257
3258             var actualFrames = 0;
3259
3260
3261             el = Roo.getDom(el);
3262
3263
3264             this.attributes = attributes || {};
3265
3266
3267             this.duration = duration || 1;
3268
3269
3270             this.method = method || Roo.lib.Easing.easeNone;
3271
3272
3273             this.useSeconds = true;
3274
3275
3276             this.currentFrame = 0;
3277
3278
3279             this.totalFrames = Roo.lib.AnimMgr.fps;
3280
3281
3282             this.getEl = function() {
3283                 return el;
3284             };
3285
3286
3287             this.isAnimated = function() {
3288                 return isAnimated;
3289             };
3290
3291
3292             this.getStartTime = function() {
3293                 return startTime;
3294             };
3295
3296             this.runtimeAttributes = {};
3297
3298
3299             this.animate = function() {
3300                 if (this.isAnimated()) {
3301                     return false;
3302                 }
3303
3304                 this.currentFrame = 0;
3305
3306                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3307
3308                 Roo.lib.AnimMgr.registerElement(this);
3309             };
3310
3311
3312             this.stop = function(finish) {
3313                 if (finish) {
3314                     this.currentFrame = this.totalFrames;
3315                     this._onTween.fire();
3316                 }
3317                 Roo.lib.AnimMgr.stop(this);
3318             };
3319
3320             var onStart = function() {
3321                 this.onStart.fire();
3322
3323                 this.runtimeAttributes = {};
3324                 for (var attr in this.attributes) {
3325                     this.setRuntimeAttribute(attr);
3326                 }
3327
3328                 isAnimated = true;
3329                 actualFrames = 0;
3330                 startTime = new Date();
3331             };
3332
3333
3334             var onTween = function() {
3335                 var data = {
3336                     duration: new Date() - this.getStartTime(),
3337                     currentFrame: this.currentFrame
3338                 };
3339
3340                 data.toString = function() {
3341                     return (
3342                             'duration: ' + data.duration +
3343                             ', currentFrame: ' + data.currentFrame
3344                             );
3345                 };
3346
3347                 this.onTween.fire(data);
3348
3349                 var runtimeAttributes = this.runtimeAttributes;
3350
3351                 for (var attr in runtimeAttributes) {
3352                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3353                 }
3354
3355                 actualFrames += 1;
3356             };
3357
3358             var onComplete = function() {
3359                 var actual_duration = (new Date() - startTime) / 1000 ;
3360
3361                 var data = {
3362                     duration: actual_duration,
3363                     frames: actualFrames,
3364                     fps: actualFrames / actual_duration
3365                 };
3366
3367                 data.toString = function() {
3368                     return (
3369                             'duration: ' + data.duration +
3370                             ', frames: ' + data.frames +
3371                             ', fps: ' + data.fps
3372                             );
3373                 };
3374
3375                 isAnimated = false;
3376                 actualFrames = 0;
3377                 this.onComplete.fire(data);
3378             };
3379
3380
3381             this._onStart = new Roo.util.Event(this);
3382             this.onStart = new Roo.util.Event(this);
3383             this.onTween = new Roo.util.Event(this);
3384             this._onTween = new Roo.util.Event(this);
3385             this.onComplete = new Roo.util.Event(this);
3386             this._onComplete = new Roo.util.Event(this);
3387             this._onStart.addListener(onStart);
3388             this._onTween.addListener(onTween);
3389             this._onComplete.addListener(onComplete);
3390         }
3391     };
3392 })();
3393 /*
3394  * Portions of this file are based on pieces of Yahoo User Interface Library
3395  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396  * YUI licensed under the BSD License:
3397  * http://developer.yahoo.net/yui/license.txt
3398  * <script type="text/javascript">
3399  *
3400  */
3401
3402 Roo.lib.AnimMgr = new function() {
3403
3404     var thread = null;
3405
3406
3407     var queue = [];
3408
3409
3410     var tweenCount = 0;
3411
3412
3413     this.fps = 1000;
3414
3415
3416     this.delay = 1;
3417
3418
3419     this.registerElement = function(tween) {
3420         queue[queue.length] = tween;
3421         tweenCount += 1;
3422         tween._onStart.fire();
3423         this.start();
3424     };
3425
3426
3427     this.unRegister = function(tween, index) {
3428         tween._onComplete.fire();
3429         index = index || getIndex(tween);
3430         if (index != -1) {
3431             queue.splice(index, 1);
3432         }
3433
3434         tweenCount -= 1;
3435         if (tweenCount <= 0) {
3436             this.stop();
3437         }
3438     };
3439
3440
3441     this.start = function() {
3442         if (thread === null) {
3443             thread = setInterval(this.run, this.delay);
3444         }
3445     };
3446
3447
3448     this.stop = function(tween) {
3449         if (!tween) {
3450             clearInterval(thread);
3451
3452             for (var i = 0, len = queue.length; i < len; ++i) {
3453                 if (queue[0].isAnimated()) {
3454                     this.unRegister(queue[0], 0);
3455                 }
3456             }
3457
3458             queue = [];
3459             thread = null;
3460             tweenCount = 0;
3461         }
3462         else {
3463             this.unRegister(tween);
3464         }
3465     };
3466
3467
3468     this.run = function() {
3469         for (var i = 0, len = queue.length; i < len; ++i) {
3470             var tween = queue[i];
3471             if (!tween || !tween.isAnimated()) {
3472                 continue;
3473             }
3474
3475             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3476             {
3477                 tween.currentFrame += 1;
3478
3479                 if (tween.useSeconds) {
3480                     correctFrame(tween);
3481                 }
3482                 tween._onTween.fire();
3483             }
3484             else {
3485                 Roo.lib.AnimMgr.stop(tween, i);
3486             }
3487         }
3488     };
3489
3490     var getIndex = function(anim) {
3491         for (var i = 0, len = queue.length; i < len; ++i) {
3492             if (queue[i] == anim) {
3493                 return i;
3494             }
3495         }
3496         return -1;
3497     };
3498
3499
3500     var correctFrame = function(tween) {
3501         var frames = tween.totalFrames;
3502         var frame = tween.currentFrame;
3503         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504         var elapsed = (new Date() - tween.getStartTime());
3505         var tweak = 0;
3506
3507         if (elapsed < tween.duration * 1000) {
3508             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3509         } else {
3510             tweak = frames - (frame + 1);
3511         }
3512         if (tweak > 0 && isFinite(tweak)) {
3513             if (tween.currentFrame + tweak >= frames) {
3514                 tweak = frames - (frame + 1);
3515             }
3516
3517             tween.currentFrame += tweak;
3518         }
3519     };
3520 };
3521
3522     /*
3523  * Portions of this file are based on pieces of Yahoo User Interface Library
3524  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525  * YUI licensed under the BSD License:
3526  * http://developer.yahoo.net/yui/license.txt
3527  * <script type="text/javascript">
3528  *
3529  */
3530 Roo.lib.Bezier = new function() {
3531
3532         this.getPosition = function(points, t) {
3533             var n = points.length;
3534             var tmp = [];
3535
3536             for (var i = 0; i < n; ++i) {
3537                 tmp[i] = [points[i][0], points[i][1]];
3538             }
3539
3540             for (var j = 1; j < n; ++j) {
3541                 for (i = 0; i < n - j; ++i) {
3542                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3544                 }
3545             }
3546
3547             return [ tmp[0][0], tmp[0][1] ];
3548
3549         };
3550     };/*
3551  * Portions of this file are based on pieces of Yahoo User Interface Library
3552  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553  * YUI licensed under the BSD License:
3554  * http://developer.yahoo.net/yui/license.txt
3555  * <script type="text/javascript">
3556  *
3557  */
3558 (function() {
3559
3560     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3562     };
3563
3564     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3565
3566     var fly = Roo.lib.AnimBase.fly;
3567     var Y = Roo.lib;
3568     var superclass = Y.ColorAnim.superclass;
3569     var proto = Y.ColorAnim.prototype;
3570
3571     proto.toString = function() {
3572         var el = this.getEl();
3573         var id = el.id || el.tagName;
3574         return ("ColorAnim " + id);
3575     };
3576
3577     proto.patterns.color = /color$/i;
3578     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3582
3583
3584     proto.parseColor = function(s) {
3585         if (s.length == 3) {
3586             return s;
3587         }
3588
3589         var c = this.patterns.hex.exec(s);
3590         if (c && c.length == 4) {
3591             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3592         }
3593
3594         c = this.patterns.rgb.exec(s);
3595         if (c && c.length == 4) {
3596             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3597         }
3598
3599         c = this.patterns.hex3.exec(s);
3600         if (c && c.length == 4) {
3601             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3602         }
3603
3604         return null;
3605     };
3606     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607     proto.getAttribute = function(attr) {
3608         var el = this.getEl();
3609         if (this.patterns.color.test(attr)) {
3610             var val = fly(el).getStyle(attr);
3611
3612             if (this.patterns.transparent.test(val)) {
3613                 var parent = el.parentNode;
3614                 val = fly(parent).getStyle(attr);
3615
3616                 while (parent && this.patterns.transparent.test(val)) {
3617                     parent = parent.parentNode;
3618                     val = fly(parent).getStyle(attr);
3619                     if (parent.tagName.toUpperCase() == 'HTML') {
3620                         val = '#fff';
3621                     }
3622                 }
3623             }
3624         } else {
3625             val = superclass.getAttribute.call(this, attr);
3626         }
3627
3628         return val;
3629     };
3630     proto.getAttribute = function(attr) {
3631         var el = this.getEl();
3632         if (this.patterns.color.test(attr)) {
3633             var val = fly(el).getStyle(attr);
3634
3635             if (this.patterns.transparent.test(val)) {
3636                 var parent = el.parentNode;
3637                 val = fly(parent).getStyle(attr);
3638
3639                 while (parent && this.patterns.transparent.test(val)) {
3640                     parent = parent.parentNode;
3641                     val = fly(parent).getStyle(attr);
3642                     if (parent.tagName.toUpperCase() == 'HTML') {
3643                         val = '#fff';
3644                     }
3645                 }
3646             }
3647         } else {
3648             val = superclass.getAttribute.call(this, attr);
3649         }
3650
3651         return val;
3652     };
3653
3654     proto.doMethod = function(attr, start, end) {
3655         var val;
3656
3657         if (this.patterns.color.test(attr)) {
3658             val = [];
3659             for (var i = 0, len = start.length; i < len; ++i) {
3660                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3661             }
3662
3663             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3664         }
3665         else {
3666             val = superclass.doMethod.call(this, attr, start, end);
3667         }
3668
3669         return val;
3670     };
3671
3672     proto.setRuntimeAttribute = function(attr) {
3673         superclass.setRuntimeAttribute.call(this, attr);
3674
3675         if (this.patterns.color.test(attr)) {
3676             var attributes = this.attributes;
3677             var start = this.parseColor(this.runtimeAttributes[attr].start);
3678             var end = this.parseColor(this.runtimeAttributes[attr].end);
3679
3680             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681                 end = this.parseColor(attributes[attr].by);
3682
3683                 for (var i = 0, len = start.length; i < len; ++i) {
3684                     end[i] = start[i] + end[i];
3685                 }
3686             }
3687
3688             this.runtimeAttributes[attr].start = start;
3689             this.runtimeAttributes[attr].end = end;
3690         }
3691     };
3692 })();
3693
3694 /*
3695  * Portions of this file are based on pieces of Yahoo User Interface Library
3696  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697  * YUI licensed under the BSD License:
3698  * http://developer.yahoo.net/yui/license.txt
3699  * <script type="text/javascript">
3700  *
3701  */
3702 Roo.lib.Easing = {
3703
3704
3705     easeNone: function (t, b, c, d) {
3706         return c * t / d + b;
3707     },
3708
3709
3710     easeIn: function (t, b, c, d) {
3711         return c * (t /= d) * t + b;
3712     },
3713
3714
3715     easeOut: function (t, b, c, d) {
3716         return -c * (t /= d) * (t - 2) + b;
3717     },
3718
3719
3720     easeBoth: function (t, b, c, d) {
3721         if ((t /= d / 2) < 1) {
3722             return c / 2 * t * t + b;
3723         }
3724
3725         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3726     },
3727
3728
3729     easeInStrong: function (t, b, c, d) {
3730         return c * (t /= d) * t * t * t + b;
3731     },
3732
3733
3734     easeOutStrong: function (t, b, c, d) {
3735         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3736     },
3737
3738
3739     easeBothStrong: function (t, b, c, d) {
3740         if ((t /= d / 2) < 1) {
3741             return c / 2 * t * t * t * t + b;
3742         }
3743
3744         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3745     },
3746
3747
3748
3749     elasticIn: function (t, b, c, d, a, p) {
3750         if (t == 0) {
3751             return b;
3752         }
3753         if ((t /= d) == 1) {
3754             return b + c;
3755         }
3756         if (!p) {
3757             p = d * .3;
3758         }
3759
3760         if (!a || a < Math.abs(c)) {
3761             a = c;
3762             var s = p / 4;
3763         }
3764         else {
3765             var s = p / (2 * Math.PI) * Math.asin(c / a);
3766         }
3767
3768         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3769     },
3770
3771
3772     elasticOut: function (t, b, c, d, a, p) {
3773         if (t == 0) {
3774             return b;
3775         }
3776         if ((t /= d) == 1) {
3777             return b + c;
3778         }
3779         if (!p) {
3780             p = d * .3;
3781         }
3782
3783         if (!a || a < Math.abs(c)) {
3784             a = c;
3785             var s = p / 4;
3786         }
3787         else {
3788             var s = p / (2 * Math.PI) * Math.asin(c / a);
3789         }
3790
3791         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3792     },
3793
3794
3795     elasticBoth: function (t, b, c, d, a, p) {
3796         if (t == 0) {
3797             return b;
3798         }
3799
3800         if ((t /= d / 2) == 2) {
3801             return b + c;
3802         }
3803
3804         if (!p) {
3805             p = d * (.3 * 1.5);
3806         }
3807
3808         if (!a || a < Math.abs(c)) {
3809             a = c;
3810             var s = p / 4;
3811         }
3812         else {
3813             var s = p / (2 * Math.PI) * Math.asin(c / a);
3814         }
3815
3816         if (t < 1) {
3817             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3819         }
3820         return a * Math.pow(2, -10 * (t -= 1)) *
3821                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3822     },
3823
3824
3825
3826     backIn: function (t, b, c, d, s) {
3827         if (typeof s == 'undefined') {
3828             s = 1.70158;
3829         }
3830         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3831     },
3832
3833
3834     backOut: function (t, b, c, d, s) {
3835         if (typeof s == 'undefined') {
3836             s = 1.70158;
3837         }
3838         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3839     },
3840
3841
3842     backBoth: function (t, b, c, d, s) {
3843         if (typeof s == 'undefined') {
3844             s = 1.70158;
3845         }
3846
3847         if ((t /= d / 2 ) < 1) {
3848             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3849         }
3850         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3851     },
3852
3853
3854     bounceIn: function (t, b, c, d) {
3855         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3856     },
3857
3858
3859     bounceOut: function (t, b, c, d) {
3860         if ((t /= d) < (1 / 2.75)) {
3861             return c * (7.5625 * t * t) + b;
3862         } else if (t < (2 / 2.75)) {
3863             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864         } else if (t < (2.5 / 2.75)) {
3865             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3866         }
3867         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3868     },
3869
3870
3871     bounceBoth: function (t, b, c, d) {
3872         if (t < d / 2) {
3873             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3874         }
3875         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3876     }
3877 };/*
3878  * Portions of this file are based on pieces of Yahoo User Interface Library
3879  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880  * YUI licensed under the BSD License:
3881  * http://developer.yahoo.net/yui/license.txt
3882  * <script type="text/javascript">
3883  *
3884  */
3885     (function() {
3886         Roo.lib.Motion = function(el, attributes, duration, method) {
3887             if (el) {
3888                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3889             }
3890         };
3891
3892         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3893
3894
3895         var Y = Roo.lib;
3896         var superclass = Y.Motion.superclass;
3897         var proto = Y.Motion.prototype;
3898
3899         proto.toString = function() {
3900             var el = this.getEl();
3901             var id = el.id || el.tagName;
3902             return ("Motion " + id);
3903         };
3904
3905         proto.patterns.points = /^points$/i;
3906
3907         proto.setAttribute = function(attr, val, unit) {
3908             if (this.patterns.points.test(attr)) {
3909                 unit = unit || 'px';
3910                 superclass.setAttribute.call(this, 'left', val[0], unit);
3911                 superclass.setAttribute.call(this, 'top', val[1], unit);
3912             } else {
3913                 superclass.setAttribute.call(this, attr, val, unit);
3914             }
3915         };
3916
3917         proto.getAttribute = function(attr) {
3918             if (this.patterns.points.test(attr)) {
3919                 var val = [
3920                         superclass.getAttribute.call(this, 'left'),
3921                         superclass.getAttribute.call(this, 'top')
3922                         ];
3923             } else {
3924                 val = superclass.getAttribute.call(this, attr);
3925             }
3926
3927             return val;
3928         };
3929
3930         proto.doMethod = function(attr, start, end) {
3931             var val = null;
3932
3933             if (this.patterns.points.test(attr)) {
3934                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3936             } else {
3937                 val = superclass.doMethod.call(this, attr, start, end);
3938             }
3939             return val;
3940         };
3941
3942         proto.setRuntimeAttribute = function(attr) {
3943             if (this.patterns.points.test(attr)) {
3944                 var el = this.getEl();
3945                 var attributes = this.attributes;
3946                 var start;
3947                 var control = attributes['points']['control'] || [];
3948                 var end;
3949                 var i, len;
3950
3951                 if (control.length > 0 && !(control[0] instanceof Array)) {
3952                     control = [control];
3953                 } else {
3954                     var tmp = [];
3955                     for (i = 0,len = control.length; i < len; ++i) {
3956                         tmp[i] = control[i];
3957                     }
3958                     control = tmp;
3959                 }
3960
3961                 Roo.fly(el).position();
3962
3963                 if (isset(attributes['points']['from'])) {
3964                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3965                 }
3966                 else {
3967                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3968                 }
3969
3970                 start = this.getAttribute('points');
3971
3972
3973                 if (isset(attributes['points']['to'])) {
3974                     end = translateValues.call(this, attributes['points']['to'], start);
3975
3976                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977                     for (i = 0,len = control.length; i < len; ++i) {
3978                         control[i] = translateValues.call(this, control[i], start);
3979                     }
3980
3981
3982                 } else if (isset(attributes['points']['by'])) {
3983                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3984
3985                     for (i = 0,len = control.length; i < len; ++i) {
3986                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3987                     }
3988                 }
3989
3990                 this.runtimeAttributes[attr] = [start];
3991
3992                 if (control.length > 0) {
3993                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3994                 }
3995
3996                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3997             }
3998             else {
3999                 superclass.setRuntimeAttribute.call(this, attr);
4000             }
4001         };
4002
4003         var translateValues = function(val, start) {
4004             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4006
4007             return val;
4008         };
4009
4010         var isset = function(prop) {
4011             return (typeof prop !== 'undefined');
4012         };
4013     })();
4014 /*
4015  * Portions of this file are based on pieces of Yahoo User Interface Library
4016  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017  * YUI licensed under the BSD License:
4018  * http://developer.yahoo.net/yui/license.txt
4019  * <script type="text/javascript">
4020  *
4021  */
4022     (function() {
4023         Roo.lib.Scroll = function(el, attributes, duration, method) {
4024             if (el) {
4025                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4026             }
4027         };
4028
4029         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4030
4031
4032         var Y = Roo.lib;
4033         var superclass = Y.Scroll.superclass;
4034         var proto = Y.Scroll.prototype;
4035
4036         proto.toString = function() {
4037             var el = this.getEl();
4038             var id = el.id || el.tagName;
4039             return ("Scroll " + id);
4040         };
4041
4042         proto.doMethod = function(attr, start, end) {
4043             var val = null;
4044
4045             if (attr == 'scroll') {
4046                 val = [
4047                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4049                         ];
4050
4051             } else {
4052                 val = superclass.doMethod.call(this, attr, start, end);
4053             }
4054             return val;
4055         };
4056
4057         proto.getAttribute = function(attr) {
4058             var val = null;
4059             var el = this.getEl();
4060
4061             if (attr == 'scroll') {
4062                 val = [ el.scrollLeft, el.scrollTop ];
4063             } else {
4064                 val = superclass.getAttribute.call(this, attr);
4065             }
4066
4067             return val;
4068         };
4069
4070         proto.setAttribute = function(attr, val, unit) {
4071             var el = this.getEl();
4072
4073             if (attr == 'scroll') {
4074                 el.scrollLeft = val[0];
4075                 el.scrollTop = val[1];
4076             } else {
4077                 superclass.setAttribute.call(this, attr, val, unit);
4078             }
4079         };
4080     })();
4081 /*
4082  * Based on:
4083  * Ext JS Library 1.1.1
4084  * Copyright(c) 2006-2007, Ext JS, LLC.
4085  *
4086  * Originally Released Under LGPL - original licence link has changed is not relivant.
4087  *
4088  * Fork - LGPL
4089  * <script type="text/javascript">
4090  */
4091
4092
4093 // nasty IE9 hack - what a pile of crap that is..
4094
4095  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096     Range.prototype.createContextualFragment = function (html) {
4097         var doc = window.document;
4098         var container = doc.createElement("div");
4099         container.innerHTML = html;
4100         var frag = doc.createDocumentFragment(), n;
4101         while ((n = container.firstChild)) {
4102             frag.appendChild(n);
4103         }
4104         return frag;
4105     };
4106 }
4107
4108 /**
4109  * @class Roo.DomHelper
4110  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4112  * @singleton
4113  */
4114 Roo.DomHelper = function(){
4115     var tempTableEl = null;
4116     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117     var tableRe = /^table|tbody|tr|td$/i;
4118     var xmlns = {};
4119     // build as innerHTML where available
4120     /** @ignore */
4121     var createHtml = function(o){
4122         if(typeof o == 'string'){
4123             return o;
4124         }
4125         var b = "";
4126         if(!o.tag){
4127             o.tag = "div";
4128         }
4129         b += "<" + o.tag;
4130         for(var attr in o){
4131             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132             if(attr == "style"){
4133                 var s = o["style"];
4134                 if(typeof s == "function"){
4135                     s = s.call();
4136                 }
4137                 if(typeof s == "string"){
4138                     b += ' style="' + s + '"';
4139                 }else if(typeof s == "object"){
4140                     b += ' style="';
4141                     for(var key in s){
4142                         if(typeof s[key] != "function"){
4143                             b += key + ":" + s[key] + ";";
4144                         }
4145                     }
4146                     b += '"';
4147                 }
4148             }else{
4149                 if(attr == "cls"){
4150                     b += ' class="' + o["cls"] + '"';
4151                 }else if(attr == "htmlFor"){
4152                     b += ' for="' + o["htmlFor"] + '"';
4153                 }else{
4154                     b += " " + attr + '="' + o[attr] + '"';
4155                 }
4156             }
4157         }
4158         if(emptyTags.test(o.tag)){
4159             b += "/>";
4160         }else{
4161             b += ">";
4162             var cn = o.children || o.cn;
4163             if(cn){
4164                 //http://bugs.kde.org/show_bug.cgi?id=71506
4165                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166                     for(var i = 0, len = cn.length; i < len; i++) {
4167                         b += createHtml(cn[i], b);
4168                     }
4169                 }else{
4170                     b += createHtml(cn, b);
4171                 }
4172             }
4173             if(o.html){
4174                 b += o.html;
4175             }
4176             b += "</" + o.tag + ">";
4177         }
4178         return b;
4179     };
4180
4181     // build as dom
4182     /** @ignore */
4183     var createDom = function(o, parentNode){
4184          
4185         // defininition craeted..
4186         var ns = false;
4187         if (o.ns && o.ns != 'html') {
4188                
4189             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190                 xmlns[o.ns] = o.xmlns;
4191                 ns = o.xmlns;
4192             }
4193             if (typeof(xmlns[o.ns]) == 'undefined') {
4194                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4195             }
4196             ns = xmlns[o.ns];
4197         }
4198         
4199         
4200         if (typeof(o) == 'string') {
4201             return parentNode.appendChild(document.createTextNode(o));
4202         }
4203         o.tag = o.tag || div;
4204         if (o.ns && Roo.isIE) {
4205             ns = false;
4206             o.tag = o.ns + ':' + o.tag;
4207             
4208         }
4209         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4210         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4211         for(var attr in o){
4212             
4213             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4214                     attr == "style" || typeof o[attr] == "function") continue;
4215                     
4216             if(attr=="cls" && Roo.isIE){
4217                 el.className = o["cls"];
4218             }else{
4219                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220                 else el[attr] = o[attr];
4221             }
4222         }
4223         Roo.DomHelper.applyStyles(el, o.style);
4224         var cn = o.children || o.cn;
4225         if(cn){
4226             //http://bugs.kde.org/show_bug.cgi?id=71506
4227              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228                 for(var i = 0, len = cn.length; i < len; i++) {
4229                     createDom(cn[i], el);
4230                 }
4231             }else{
4232                 createDom(cn, el);
4233             }
4234         }
4235         if(o.html){
4236             el.innerHTML = o.html;
4237         }
4238         if(parentNode){
4239            parentNode.appendChild(el);
4240         }
4241         return el;
4242     };
4243
4244     var ieTable = function(depth, s, h, e){
4245         tempTableEl.innerHTML = [s, h, e].join('');
4246         var i = -1, el = tempTableEl;
4247         while(++i < depth){
4248             el = el.firstChild;
4249         }
4250         return el;
4251     };
4252
4253     // kill repeat to save bytes
4254     var ts = '<table>',
4255         te = '</table>',
4256         tbs = ts+'<tbody>',
4257         tbe = '</tbody>'+te,
4258         trs = tbs + '<tr>',
4259         tre = '</tr>'+tbe;
4260
4261     /**
4262      * @ignore
4263      * Nasty code for IE's broken table implementation
4264      */
4265     var insertIntoTable = function(tag, where, el, html){
4266         if(!tempTableEl){
4267             tempTableEl = document.createElement('div');
4268         }
4269         var node;
4270         var before = null;
4271         if(tag == 'td'){
4272             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4273                 return;
4274             }
4275             if(where == 'beforebegin'){
4276                 before = el;
4277                 el = el.parentNode;
4278             } else{
4279                 before = el.nextSibling;
4280                 el = el.parentNode;
4281             }
4282             node = ieTable(4, trs, html, tre);
4283         }
4284         else if(tag == 'tr'){
4285             if(where == 'beforebegin'){
4286                 before = el;
4287                 el = el.parentNode;
4288                 node = ieTable(3, tbs, html, tbe);
4289             } else if(where == 'afterend'){
4290                 before = el.nextSibling;
4291                 el = el.parentNode;
4292                 node = ieTable(3, tbs, html, tbe);
4293             } else{ // INTO a TR
4294                 if(where == 'afterbegin'){
4295                     before = el.firstChild;
4296                 }
4297                 node = ieTable(4, trs, html, tre);
4298             }
4299         } else if(tag == 'tbody'){
4300             if(where == 'beforebegin'){
4301                 before = el;
4302                 el = el.parentNode;
4303                 node = ieTable(2, ts, html, te);
4304             } else if(where == 'afterend'){
4305                 before = el.nextSibling;
4306                 el = el.parentNode;
4307                 node = ieTable(2, ts, html, te);
4308             } else{
4309                 if(where == 'afterbegin'){
4310                     before = el.firstChild;
4311                 }
4312                 node = ieTable(3, tbs, html, tbe);
4313             }
4314         } else{ // TABLE
4315             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4316                 return;
4317             }
4318             if(where == 'afterbegin'){
4319                 before = el.firstChild;
4320             }
4321             node = ieTable(2, ts, html, te);
4322         }
4323         el.insertBefore(node, before);
4324         return node;
4325     };
4326
4327     return {
4328     /** True to force the use of DOM instead of html fragments @type Boolean */
4329     useDom : false,
4330
4331     /**
4332      * Returns the markup for the passed Element(s) config
4333      * @param {Object} o The Dom object spec (and children)
4334      * @return {String}
4335      */
4336     markup : function(o){
4337         return createHtml(o);
4338     },
4339
4340     /**
4341      * Applies a style specification to an element
4342      * @param {String/HTMLElement} el The element to apply styles to
4343      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344      * a function which returns such a specification.
4345      */
4346     applyStyles : function(el, styles){
4347         if(styles){
4348            el = Roo.fly(el);
4349            if(typeof styles == "string"){
4350                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4351                var matches;
4352                while ((matches = re.exec(styles)) != null){
4353                    el.setStyle(matches[1], matches[2]);
4354                }
4355            }else if (typeof styles == "object"){
4356                for (var style in styles){
4357                   el.setStyle(style, styles[style]);
4358                }
4359            }else if (typeof styles == "function"){
4360                 Roo.DomHelper.applyStyles(el, styles.call());
4361            }
4362         }
4363     },
4364
4365     /**
4366      * Inserts an HTML fragment into the Dom
4367      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368      * @param {HTMLElement} el The context element
4369      * @param {String} html The HTML fragmenet
4370      * @return {HTMLElement} The new node
4371      */
4372     insertHtml : function(where, el, html){
4373         where = where.toLowerCase();
4374         if(el.insertAdjacentHTML){
4375             if(tableRe.test(el.tagName)){
4376                 var rs;
4377                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4378                     return rs;
4379                 }
4380             }
4381             switch(where){
4382                 case "beforebegin":
4383                     el.insertAdjacentHTML('BeforeBegin', html);
4384                     return el.previousSibling;
4385                 case "afterbegin":
4386                     el.insertAdjacentHTML('AfterBegin', html);
4387                     return el.firstChild;
4388                 case "beforeend":
4389                     el.insertAdjacentHTML('BeforeEnd', html);
4390                     return el.lastChild;
4391                 case "afterend":
4392                     el.insertAdjacentHTML('AfterEnd', html);
4393                     return el.nextSibling;
4394             }
4395             throw 'Illegal insertion point -> "' + where + '"';
4396         }
4397         var range = el.ownerDocument.createRange();
4398         var frag;
4399         switch(where){
4400              case "beforebegin":
4401                 range.setStartBefore(el);
4402                 frag = range.createContextualFragment(html);
4403                 el.parentNode.insertBefore(frag, el);
4404                 return el.previousSibling;
4405              case "afterbegin":
4406                 if(el.firstChild){
4407                     range.setStartBefore(el.firstChild);
4408                     frag = range.createContextualFragment(html);
4409                     el.insertBefore(frag, el.firstChild);
4410                     return el.firstChild;
4411                 }else{
4412                     el.innerHTML = html;
4413                     return el.firstChild;
4414                 }
4415             case "beforeend":
4416                 if(el.lastChild){
4417                     range.setStartAfter(el.lastChild);
4418                     frag = range.createContextualFragment(html);
4419                     el.appendChild(frag);
4420                     return el.lastChild;
4421                 }else{
4422                     el.innerHTML = html;
4423                     return el.lastChild;
4424                 }
4425             case "afterend":
4426                 range.setStartAfter(el);
4427                 frag = range.createContextualFragment(html);
4428                 el.parentNode.insertBefore(frag, el.nextSibling);
4429                 return el.nextSibling;
4430             }
4431             throw 'Illegal insertion point -> "' + where + '"';
4432     },
4433
4434     /**
4435      * Creates new Dom element(s) and inserts them before el
4436      * @param {String/HTMLElement/Element} el The context element
4437      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439      * @return {HTMLElement/Roo.Element} The new node
4440      */
4441     insertBefore : function(el, o, returnElement){
4442         return this.doInsert(el, o, returnElement, "beforeBegin");
4443     },
4444
4445     /**
4446      * Creates new Dom element(s) and inserts them after el
4447      * @param {String/HTMLElement/Element} el The context element
4448      * @param {Object} o The Dom object spec (and children)
4449      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450      * @return {HTMLElement/Roo.Element} The new node
4451      */
4452     insertAfter : function(el, o, returnElement){
4453         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4454     },
4455
4456     /**
4457      * Creates new Dom element(s) and inserts them as the first child of el
4458      * @param {String/HTMLElement/Element} el The context element
4459      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461      * @return {HTMLElement/Roo.Element} The new node
4462      */
4463     insertFirst : function(el, o, returnElement){
4464         return this.doInsert(el, o, returnElement, "afterBegin");
4465     },
4466
4467     // private
4468     doInsert : function(el, o, returnElement, pos, sibling){
4469         el = Roo.getDom(el);
4470         var newNode;
4471         if(this.useDom || o.ns){
4472             newNode = createDom(o, null);
4473             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4474         }else{
4475             var html = createHtml(o);
4476             newNode = this.insertHtml(pos, el, html);
4477         }
4478         return returnElement ? Roo.get(newNode, true) : newNode;
4479     },
4480
4481     /**
4482      * Creates new Dom element(s) and appends them to el
4483      * @param {String/HTMLElement/Element} el The context element
4484      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486      * @return {HTMLElement/Roo.Element} The new node
4487      */
4488     append : function(el, o, returnElement){
4489         el = Roo.getDom(el);
4490         var newNode;
4491         if(this.useDom || o.ns){
4492             newNode = createDom(o, null);
4493             el.appendChild(newNode);
4494         }else{
4495             var html = createHtml(o);
4496             newNode = this.insertHtml("beforeEnd", el, html);
4497         }
4498         return returnElement ? Roo.get(newNode, true) : newNode;
4499     },
4500
4501     /**
4502      * Creates new Dom element(s) and overwrites the contents of el with them
4503      * @param {String/HTMLElement/Element} el The context element
4504      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506      * @return {HTMLElement/Roo.Element} The new node
4507      */
4508     overwrite : function(el, o, returnElement){
4509         el = Roo.getDom(el);
4510         if (o.ns) {
4511           
4512             while (el.childNodes.length) {
4513                 el.removeChild(el.firstChild);
4514             }
4515             createDom(o, el);
4516         } else {
4517             el.innerHTML = createHtml(o);   
4518         }
4519         
4520         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4521     },
4522
4523     /**
4524      * Creates a new Roo.DomHelper.Template from the Dom object spec
4525      * @param {Object} o The Dom object spec (and children)
4526      * @return {Roo.DomHelper.Template} The new template
4527      */
4528     createTemplate : function(o){
4529         var html = createHtml(o);
4530         return new Roo.Template(html);
4531     }
4532     };
4533 }();
4534 /*
4535  * Based on:
4536  * Ext JS Library 1.1.1
4537  * Copyright(c) 2006-2007, Ext JS, LLC.
4538  *
4539  * Originally Released Under LGPL - original licence link has changed is not relivant.
4540  *
4541  * Fork - LGPL
4542  * <script type="text/javascript">
4543  */
4544  
4545 /**
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4549 * Usage:
4550 <pre><code>
4551 var t = new Roo.Template({
4552     html :  '&lt;div name="{id}"&gt;' + 
4553         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4554         '&lt;/div&gt;',
4555     myformat: function (value, allValues) {
4556         return 'XX' + value;
4557     }
4558 });
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4560 </code></pre>
4561 * For more information see this blog post with examples:
4562 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563      - Create Elements using DOM, HTML fragments and Templates</a>. 
4564 * @constructor
4565 * @param {Object} cfg - Configuration object.
4566 */
4567 Roo.Template = function(cfg){
4568     // BC!
4569     if(cfg instanceof Array){
4570         cfg = cfg.join("");
4571     }else if(arguments.length > 1){
4572         cfg = Array.prototype.join.call(arguments, "");
4573     }
4574     
4575     
4576     if (typeof(cfg) == 'object') {
4577         Roo.apply(this,cfg)
4578     } else {
4579         // bc
4580         this.html = cfg;
4581     }
4582     if (this.url) {
4583         this.load();
4584     }
4585     
4586 };
4587 Roo.Template.prototype = {
4588     
4589     /**
4590      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591      *                    it should be fixed so that template is observable...
4592      */
4593     url : false,
4594     /**
4595      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4596      */
4597     html : '',
4598     /**
4599      * Returns an HTML fragment of this template with the specified values applied.
4600      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601      * @return {String} The HTML fragment
4602      */
4603     applyTemplate : function(values){
4604         try {
4605            
4606             if(this.compiled){
4607                 return this.compiled(values);
4608             }
4609             var useF = this.disableFormats !== true;
4610             var fm = Roo.util.Format, tpl = this;
4611             var fn = function(m, name, format, args){
4612                 if(format && useF){
4613                     if(format.substr(0, 5) == "this."){
4614                         return tpl.call(format.substr(5), values[name], values);
4615                     }else{
4616                         if(args){
4617                             // quoted values are required for strings in compiled templates, 
4618                             // but for non compiled we need to strip them
4619                             // quoted reversed for jsmin
4620                             var re = /^\s*['"](.*)["']\s*$/;
4621                             args = args.split(',');
4622                             for(var i = 0, len = args.length; i < len; i++){
4623                                 args[i] = args[i].replace(re, "$1");
4624                             }
4625                             args = [values[name]].concat(args);
4626                         }else{
4627                             args = [values[name]];
4628                         }
4629                         return fm[format].apply(fm, args);
4630                     }
4631                 }else{
4632                     return values[name] !== undefined ? values[name] : "";
4633                 }
4634             };
4635             return this.html.replace(this.re, fn);
4636         } catch (e) {
4637             Roo.log(e);
4638             throw e;
4639         }
4640          
4641     },
4642     
4643     loading : false,
4644       
4645     load : function ()
4646     {
4647          
4648         if (this.loading) {
4649             return;
4650         }
4651         var _t = this;
4652         
4653         this.loading = true;
4654         this.compiled = false;
4655         
4656         var cx = new Roo.data.Connection();
4657         cx.request({
4658             url : this.url,
4659             method : 'GET',
4660             success : function (response) {
4661                 _t.loading = false;
4662                 _t.html = response.responseText;
4663                 _t.url = false;
4664                 _t.compile();
4665              },
4666             failure : function(response) {
4667                 Roo.log("Template failed to load from " + _t.url);
4668                 _t.loading = false;
4669             }
4670         });
4671     },
4672
4673     /**
4674      * Sets the HTML used as the template and optionally compiles it.
4675      * @param {String} html
4676      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677      * @return {Roo.Template} this
4678      */
4679     set : function(html, compile){
4680         this.html = html;
4681         this.compiled = null;
4682         if(compile){
4683             this.compile();
4684         }
4685         return this;
4686     },
4687     
4688     /**
4689      * True to disable format functions (defaults to false)
4690      * @type Boolean
4691      */
4692     disableFormats : false,
4693     
4694     /**
4695     * The regular expression used to match template variables 
4696     * @type RegExp
4697     * @property 
4698     */
4699     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4700     
4701     /**
4702      * Compiles the template into an internal function, eliminating the RegEx overhead.
4703      * @return {Roo.Template} this
4704      */
4705     compile : function(){
4706         var fm = Roo.util.Format;
4707         var useF = this.disableFormats !== true;
4708         var sep = Roo.isGecko ? "+" : ",";
4709         var fn = function(m, name, format, args){
4710             if(format && useF){
4711                 args = args ? ',' + args : "";
4712                 if(format.substr(0, 5) != "this."){
4713                     format = "fm." + format + '(';
4714                 }else{
4715                     format = 'this.call("'+ format.substr(5) + '", ';
4716                     args = ", values";
4717                 }
4718             }else{
4719                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4720             }
4721             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4722         };
4723         var body;
4724         // branched to use + in gecko and [].join() in others
4725         if(Roo.isGecko){
4726             body = "this.compiled = function(values){ return '" +
4727                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4728                     "';};";
4729         }else{
4730             body = ["this.compiled = function(values){ return ['"];
4731             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732             body.push("'].join('');};");
4733             body = body.join('');
4734         }
4735         /**
4736          * eval:var:values
4737          * eval:var:fm
4738          */
4739         eval(body);
4740         return this;
4741     },
4742     
4743     // private function used to call members
4744     call : function(fnName, value, allValues){
4745         return this[fnName](value, allValues);
4746     },
4747     
4748     /**
4749      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750      * @param {String/HTMLElement/Roo.Element} el The context element
4751      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753      * @return {HTMLElement/Roo.Element} The new node or Element
4754      */
4755     insertFirst: function(el, values, returnElement){
4756         return this.doInsert('afterBegin', el, values, returnElement);
4757     },
4758
4759     /**
4760      * Applies the supplied values to the template and inserts the new node(s) before el.
4761      * @param {String/HTMLElement/Roo.Element} el The context element
4762      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764      * @return {HTMLElement/Roo.Element} The new node or Element
4765      */
4766     insertBefore: function(el, values, returnElement){
4767         return this.doInsert('beforeBegin', el, values, returnElement);
4768     },
4769
4770     /**
4771      * Applies the supplied values to the template and inserts the new node(s) after el.
4772      * @param {String/HTMLElement/Roo.Element} el The context element
4773      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775      * @return {HTMLElement/Roo.Element} The new node or Element
4776      */
4777     insertAfter : function(el, values, returnElement){
4778         return this.doInsert('afterEnd', el, values, returnElement);
4779     },
4780     
4781     /**
4782      * Applies the supplied values to the template and appends the new node(s) to el.
4783      * @param {String/HTMLElement/Roo.Element} el The context element
4784      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786      * @return {HTMLElement/Roo.Element} The new node or Element
4787      */
4788     append : function(el, values, returnElement){
4789         return this.doInsert('beforeEnd', el, values, returnElement);
4790     },
4791
4792     doInsert : function(where, el, values, returnEl){
4793         el = Roo.getDom(el);
4794         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795         return returnEl ? Roo.get(newNode, true) : newNode;
4796     },
4797
4798     /**
4799      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800      * @param {String/HTMLElement/Roo.Element} el The context element
4801      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803      * @return {HTMLElement/Roo.Element} The new node or Element
4804      */
4805     overwrite : function(el, values, returnElement){
4806         el = Roo.getDom(el);
4807         el.innerHTML = this.applyTemplate(values);
4808         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4809     }
4810 };
4811 /**
4812  * Alias for {@link #applyTemplate}
4813  * @method
4814  */
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4816
4817 // backwards compat
4818 Roo.DomHelper.Template = Roo.Template;
4819
4820 /**
4821  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822  * @param {String/HTMLElement} el A DOM element or its id
4823  * @returns {Roo.Template} The created template
4824  * @static
4825  */
4826 Roo.Template.from = function(el){
4827     el = Roo.getDom(el);
4828     return new Roo.Template(el.value || el.innerHTML);
4829 };/*
4830  * Based on:
4831  * Ext JS Library 1.1.1
4832  * Copyright(c) 2006-2007, Ext JS, LLC.
4833  *
4834  * Originally Released Under LGPL - original licence link has changed is not relivant.
4835  *
4836  * Fork - LGPL
4837  * <script type="text/javascript">
4838  */
4839  
4840
4841 /*
4842  * This is code is also distributed under MIT license for use
4843  * with jQuery and prototype JavaScript libraries.
4844  */
4845 /**
4846  * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4848 <p>
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4850
4851 <p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4853 </p>
4854 <h4>Element Selectors:</h4>
4855 <ul class="list">
4856     <li> <b>*</b> any element</li>
4857     <li> <b>E</b> an element with the tag E</li>
4858     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4862 </ul>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4865 <ul class="list">
4866     <li> <b>E[foo]</b> has an attribute "foo"</li>
4867     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4873 </ul>
4874 <h4>Pseudo Classes:</h4>
4875 <ul class="list">
4876     <li> <b>E:first-child</b> E is the first child of its parent</li>
4877     <li> <b>E:last-child</b> E is the last child of its parent</li>
4878     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881     <li> <b>E:only-child</b> E is the only child of its parent</li>
4882     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883     <li> <b>E:first</b> the first E in the resultset</li>
4884     <li> <b>E:last</b> the last E in the resultset</li>
4885     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4894 </ul>
4895 <h4>CSS Value Selectors:</h4>
4896 <ul class="list">
4897     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4903 </ul>
4904  * @singleton
4905  */
4906 Roo.DomQuery = function(){
4907     var cache = {}, simpleCache = {}, valueCache = {};
4908     var nonSpace = /\S/;
4909     var trimRe = /^\s+|\s+$/g;
4910     var tplRe = /\{(\d+)\}/g;
4911     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912     var tagTokenRe = /^(#)?([\w-\*]+)/;
4913     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4914
4915     function child(p, index){
4916         var i = 0;
4917         var n = p.firstChild;
4918         while(n){
4919             if(n.nodeType == 1){
4920                if(++i == index){
4921                    return n;
4922                }
4923             }
4924             n = n.nextSibling;
4925         }
4926         return null;
4927     };
4928
4929     function next(n){
4930         while((n = n.nextSibling) && n.nodeType != 1);
4931         return n;
4932     };
4933
4934     function prev(n){
4935         while((n = n.previousSibling) && n.nodeType != 1);
4936         return n;
4937     };
4938
4939     function children(d){
4940         var n = d.firstChild, ni = -1;
4941             while(n){
4942                 var nx = n.nextSibling;
4943                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4944                     d.removeChild(n);
4945                 }else{
4946                     n.nodeIndex = ++ni;
4947                 }
4948                 n = nx;
4949             }
4950             return this;
4951         };
4952
4953     function byClassName(c, a, v){
4954         if(!v){
4955             return c;
4956         }
4957         var r = [], ri = -1, cn;
4958         for(var i = 0, ci; ci = c[i]; i++){
4959             if((' '+ci.className+' ').indexOf(v) != -1){
4960                 r[++ri] = ci;
4961             }
4962         }
4963         return r;
4964     };
4965
4966     function attrValue(n, attr){
4967         if(!n.tagName && typeof n.length != "undefined"){
4968             n = n[0];
4969         }
4970         if(!n){
4971             return null;
4972         }
4973         if(attr == "for"){
4974             return n.htmlFor;
4975         }
4976         if(attr == "class" || attr == "className"){
4977             return n.className;
4978         }
4979         return n.getAttribute(attr) || n[attr];
4980
4981     };
4982
4983     function getNodes(ns, mode, tagName){
4984         var result = [], ri = -1, cs;
4985         if(!ns){
4986             return result;
4987         }
4988         tagName = tagName || "*";
4989         if(typeof ns.getElementsByTagName != "undefined"){
4990             ns = [ns];
4991         }
4992         if(!mode){
4993             for(var i = 0, ni; ni = ns[i]; i++){
4994                 cs = ni.getElementsByTagName(tagName);
4995                 for(var j = 0, ci; ci = cs[j]; j++){
4996                     result[++ri] = ci;
4997                 }
4998             }
4999         }else if(mode == "/" || mode == ">"){
5000             var utag = tagName.toUpperCase();
5001             for(var i = 0, ni, cn; ni = ns[i]; i++){
5002                 cn = ni.children || ni.childNodes;
5003                 for(var j = 0, cj; cj = cn[j]; j++){
5004                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5005                         result[++ri] = cj;
5006                     }
5007                 }
5008             }
5009         }else if(mode == "+"){
5010             var utag = tagName.toUpperCase();
5011             for(var i = 0, n; n = ns[i]; i++){
5012                 while((n = n.nextSibling) && n.nodeType != 1);
5013                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5014                     result[++ri] = n;
5015                 }
5016             }
5017         }else if(mode == "~"){
5018             for(var i = 0, n; n = ns[i]; i++){
5019                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5020                 if(n){
5021                     result[++ri] = n;
5022                 }
5023             }
5024         }
5025         return result;
5026     };
5027
5028     function concat(a, b){
5029         if(b.slice){
5030             return a.concat(b);
5031         }
5032         for(var i = 0, l = b.length; i < l; i++){
5033             a[a.length] = b[i];
5034         }
5035         return a;
5036     }
5037
5038     function byTag(cs, tagName){
5039         if(cs.tagName || cs == document){
5040             cs = [cs];
5041         }
5042         if(!tagName){
5043             return cs;
5044         }
5045         var r = [], ri = -1;
5046         tagName = tagName.toLowerCase();
5047         for(var i = 0, ci; ci = cs[i]; i++){
5048             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5049                 r[++ri] = ci;
5050             }
5051         }
5052         return r;
5053     };
5054
5055     function byId(cs, attr, id){
5056         if(cs.tagName || cs == document){
5057             cs = [cs];
5058         }
5059         if(!id){
5060             return cs;
5061         }
5062         var r = [], ri = -1;
5063         for(var i = 0,ci; ci = cs[i]; i++){
5064             if(ci && ci.id == id){
5065                 r[++ri] = ci;
5066                 return r;
5067             }
5068         }
5069         return r;
5070     };
5071
5072     function byAttribute(cs, attr, value, op, custom){
5073         var r = [], ri = -1, st = custom=="{";
5074         var f = Roo.DomQuery.operators[op];
5075         for(var i = 0, ci; ci = cs[i]; i++){
5076             var a;
5077             if(st){
5078                 a = Roo.DomQuery.getStyle(ci, attr);
5079             }
5080             else if(attr == "class" || attr == "className"){
5081                 a = ci.className;
5082             }else if(attr == "for"){
5083                 a = ci.htmlFor;
5084             }else if(attr == "href"){
5085                 a = ci.getAttribute("href", 2);
5086             }else{
5087                 a = ci.getAttribute(attr);
5088             }
5089             if((f && f(a, value)) || (!f && a)){
5090                 r[++ri] = ci;
5091             }
5092         }
5093         return r;
5094     };
5095
5096     function byPseudo(cs, name, value){
5097         return Roo.DomQuery.pseudos[name](cs, value);
5098     };
5099
5100     // This is for IE MSXML which does not support expandos.
5101     // IE runs the same speed using setAttribute, however FF slows way down
5102     // and Safari completely fails so they need to continue to use expandos.
5103     var isIE = window.ActiveXObject ? true : false;
5104
5105     // this eval is stop the compressor from
5106     // renaming the variable to something shorter
5107     
5108     /** eval:var:batch */
5109     var batch = 30803; 
5110
5111     var key = 30803;
5112
5113     function nodupIEXml(cs){
5114         var d = ++key;
5115         cs[0].setAttribute("_nodup", d);
5116         var r = [cs[0]];
5117         for(var i = 1, len = cs.length; i < len; i++){
5118             var c = cs[i];
5119             if(!c.getAttribute("_nodup") != d){
5120                 c.setAttribute("_nodup", d);
5121                 r[r.length] = c;
5122             }
5123         }
5124         for(var i = 0, len = cs.length; i < len; i++){
5125             cs[i].removeAttribute("_nodup");
5126         }
5127         return r;
5128     }
5129
5130     function nodup(cs){
5131         if(!cs){
5132             return [];
5133         }
5134         var len = cs.length, c, i, r = cs, cj, ri = -1;
5135         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5136             return cs;
5137         }
5138         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139             return nodupIEXml(cs);
5140         }
5141         var d = ++key;
5142         cs[0]._nodup = d;
5143         for(i = 1; c = cs[i]; i++){
5144             if(c._nodup != d){
5145                 c._nodup = d;
5146             }else{
5147                 r = [];
5148                 for(var j = 0; j < i; j++){
5149                     r[++ri] = cs[j];
5150                 }
5151                 for(j = i+1; cj = cs[j]; j++){
5152                     if(cj._nodup != d){
5153                         cj._nodup = d;
5154                         r[++ri] = cj;
5155                     }
5156                 }
5157                 return r;
5158             }
5159         }
5160         return r;
5161     }
5162
5163     function quickDiffIEXml(c1, c2){
5164         var d = ++key;
5165         for(var i = 0, len = c1.length; i < len; i++){
5166             c1[i].setAttribute("_qdiff", d);
5167         }
5168         var r = [];
5169         for(var i = 0, len = c2.length; i < len; i++){
5170             if(c2[i].getAttribute("_qdiff") != d){
5171                 r[r.length] = c2[i];
5172             }
5173         }
5174         for(var i = 0, len = c1.length; i < len; i++){
5175            c1[i].removeAttribute("_qdiff");
5176         }
5177         return r;
5178     }
5179
5180     function quickDiff(c1, c2){
5181         var len1 = c1.length;
5182         if(!len1){
5183             return c2;
5184         }
5185         if(isIE && c1[0].selectSingleNode){
5186             return quickDiffIEXml(c1, c2);
5187         }
5188         var d = ++key;
5189         for(var i = 0; i < len1; i++){
5190             c1[i]._qdiff = d;
5191         }
5192         var r = [];
5193         for(var i = 0, len = c2.length; i < len; i++){
5194             if(c2[i]._qdiff != d){
5195                 r[r.length] = c2[i];
5196             }
5197         }
5198         return r;
5199     }
5200
5201     function quickId(ns, mode, root, id){
5202         if(ns == root){
5203            var d = root.ownerDocument || root;
5204            return d.getElementById(id);
5205         }
5206         ns = getNodes(ns, mode, "*");
5207         return byId(ns, null, id);
5208     }
5209
5210     return {
5211         getStyle : function(el, name){
5212             return Roo.fly(el).getStyle(name);
5213         },
5214         /**
5215          * Compiles a selector/xpath query into a reusable function. The returned function
5216          * takes one parameter "root" (optional), which is the context node from where the query should start.
5217          * @param {String} selector The selector/xpath query
5218          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219          * @return {Function}
5220          */
5221         compile : function(path, type){
5222             type = type || "select";
5223             
5224             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225             var q = path, mode, lq;
5226             var tk = Roo.DomQuery.matchers;
5227             var tklen = tk.length;
5228             var mm;
5229
5230             // accept leading mode switch
5231             var lmode = q.match(modeRe);
5232             if(lmode && lmode[1]){
5233                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234                 q = q.replace(lmode[1], "");
5235             }
5236             // strip leading slashes
5237             while(path.substr(0, 1)=="/"){
5238                 path = path.substr(1);
5239             }
5240
5241             while(q && lq != q){
5242                 lq = q;
5243                 var tm = q.match(tagTokenRe);
5244                 if(type == "select"){
5245                     Roo.log('tm');
5246                     Roo.log(tm);
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                         
5255                     }else if(q.substr(0, 1) != '@'){
5256                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5257                     }
5258                     Roo.log('fn');
5259                         Roo.log(fn);
5260                         Roo.log(q);
5261                 }else{
5262                     if(tm){
5263                         if(tm[1] == "#"){
5264                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5265                         }else{
5266                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5267                         }
5268                         q = q.replace(tm[0], "");
5269                     }
5270                 }
5271                 Roo.log(modeRe);
5272                 while(!(mm = q.match(modeRe))){
5273                     var matched = false;
5274                     Roo.log('mm');
5275                     Roo.log(mm);
5276                     for(var j = 0; j < tklen; j++){
5277                         var t = tk[j];
5278                         var m = q.match(t.re);
5279                         Roo.log('t');
5280                         Roo.log(t);
5281                         
5282                         Roo.log('m');
5283                         Roo.log(m);
5284                         if(m){
5285                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5286                                                     return m[i];
5287                                                 });
5288                             q = q.replace(m[0], "");
5289                             matched = true;
5290                             break;
5291                         }
5292                     }
5293                     // prevent infinite loop on bad selector
5294                     if(!matched){
5295                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5296                     }
5297                 }
5298                 if(mm[1]){
5299                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5300                     q = q.replace(mm[1], "");
5301                 }
5302             }
5303             fn[fn.length] = "return nodup(n);\n}";
5304             
5305              /** 
5306               * list of variables that need from compression as they are used by eval.
5307              *  eval:var:batch 
5308              *  eval:var:nodup
5309              *  eval:var:byTag
5310              *  eval:var:ById
5311              *  eval:var:getNodes
5312              *  eval:var:quickId
5313              *  eval:var:mode
5314              *  eval:var:root
5315              *  eval:var:n
5316              *  eval:var:byClassName
5317              *  eval:var:byPseudo
5318              *  eval:var:byAttribute
5319              *  eval:var:attrValue
5320              * 
5321              **/ 
5322             eval(fn.join(""));
5323             return f;
5324         },
5325
5326         /**
5327          * Selects a group of elements.
5328          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5329          * @param {Node} root (optional) The start of the query (defaults to document).
5330          * @return {Array}
5331          */
5332         select : function(path, root, type){
5333             if(!root || root == document){
5334                 root = document;
5335             }
5336             if(typeof root == "string"){
5337                 root = document.getElementById(root);
5338             }
5339             var paths = path.split(",");
5340             var results = [];
5341             for(var i = 0, len = paths.length; i < len; i++){
5342                 var p = paths[i].replace(trimRe, "");
5343                 if(!cache[p]){
5344                     cache[p] = Roo.DomQuery.compile(p);
5345                     if(!cache[p]){
5346                         throw p + " is not a valid selector";
5347                     }
5348                 }
5349                 var result = cache[p](root);
5350                 if(result && result != document){
5351                     results = results.concat(result);
5352                 }
5353             }
5354             if(paths.length > 1){
5355                 return nodup(results);
5356             }
5357             return results;
5358         },
5359
5360         /**
5361          * Selects a single element.
5362          * @param {String} selector The selector/xpath query
5363          * @param {Node} root (optional) The start of the query (defaults to document).
5364          * @return {Element}
5365          */
5366         selectNode : function(path, root){
5367             return Roo.DomQuery.select(path, root)[0];
5368         },
5369
5370         /**
5371          * Selects the value of a node, optionally replacing null with the defaultValue.
5372          * @param {String} selector The selector/xpath query
5373          * @param {Node} root (optional) The start of the query (defaults to document).
5374          * @param {String} defaultValue
5375          */
5376         selectValue : function(path, root, defaultValue){
5377             path = path.replace(trimRe, "");
5378             if(!valueCache[path]){
5379                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5380             }
5381             var n = valueCache[path](root);
5382             n = n[0] ? n[0] : n;
5383             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5384             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5385         },
5386
5387         /**
5388          * Selects the value of a node, parsing integers and floats.
5389          * @param {String} selector The selector/xpath query
5390          * @param {Node} root (optional) The start of the query (defaults to document).
5391          * @param {Number} defaultValue
5392          * @return {Number}
5393          */
5394         selectNumber : function(path, root, defaultValue){
5395             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5396             return parseFloat(v);
5397         },
5398
5399         /**
5400          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5401          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5402          * @param {String} selector The simple selector to test
5403          * @return {Boolean}
5404          */
5405         is : function(el, ss){
5406             if(typeof el == "string"){
5407                 el = document.getElementById(el);
5408             }
5409             var isArray = (el instanceof Array);
5410             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5411             return isArray ? (result.length == el.length) : (result.length > 0);
5412         },
5413
5414         /**
5415          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5416          * @param {Array} el An array of elements to filter
5417          * @param {String} selector The simple selector to test
5418          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5419          * the selector instead of the ones that match
5420          * @return {Array}
5421          */
5422         filter : function(els, ss, nonMatches){
5423             ss = ss.replace(trimRe, "");
5424             if(!simpleCache[ss]){
5425                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5426             }
5427             var result = simpleCache[ss](els);
5428             return nonMatches ? quickDiff(result, els) : result;
5429         },
5430
5431         /**
5432          * Collection of matching regular expressions and code snippets.
5433          */
5434         matchers : [{
5435                 re: /^\.([\w-]+)/,
5436                 select: 'n = byClassName(n, null, " {1} ");'
5437             }, {
5438                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5439                 select: 'n = byPseudo(n, "{1}", "{2}");'
5440             },{
5441                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5442                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5443             }, {
5444                 re: /^#([\w-]+)/,
5445                 select: 'n = byId(n, null, "{1}");'
5446             },{
5447                 re: /^@([\w-]+)/,
5448                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5449             }
5450         ],
5451
5452         /**
5453          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5454          * 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;.
5455          */
5456         operators : {
5457             "=" : function(a, v){
5458                 return a == v;
5459             },
5460             "!=" : function(a, v){
5461                 return a != v;
5462             },
5463             "^=" : function(a, v){
5464                 return a && a.substr(0, v.length) == v;
5465             },
5466             "$=" : function(a, v){
5467                 return a && a.substr(a.length-v.length) == v;
5468             },
5469             "*=" : function(a, v){
5470                 return a && a.indexOf(v) !== -1;
5471             },
5472             "%=" : function(a, v){
5473                 return (a % v) == 0;
5474             },
5475             "|=" : function(a, v){
5476                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5477             },
5478             "~=" : function(a, v){
5479                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5480             }
5481         },
5482
5483         /**
5484          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5485          * and the argument (if any) supplied in the selector.
5486          */
5487         pseudos : {
5488             "first-child" : function(c){
5489                 var r = [], ri = -1, n;
5490                 for(var i = 0, ci; ci = n = c[i]; i++){
5491                     while((n = n.previousSibling) && n.nodeType != 1);
5492                     if(!n){
5493                         r[++ri] = ci;
5494                     }
5495                 }
5496                 return r;
5497             },
5498
5499             "last-child" : function(c){
5500                 var r = [], ri = -1, n;
5501                 for(var i = 0, ci; ci = n = c[i]; i++){
5502                     while((n = n.nextSibling) && n.nodeType != 1);
5503                     if(!n){
5504                         r[++ri] = ci;
5505                     }
5506                 }
5507                 return r;
5508             },
5509
5510             "nth-child" : function(c, a) {
5511                 var r = [], ri = -1;
5512                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5513                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5514                 for(var i = 0, n; n = c[i]; i++){
5515                     var pn = n.parentNode;
5516                     if (batch != pn._batch) {
5517                         var j = 0;
5518                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5519                             if(cn.nodeType == 1){
5520                                cn.nodeIndex = ++j;
5521                             }
5522                         }
5523                         pn._batch = batch;
5524                     }
5525                     if (f == 1) {
5526                         if (l == 0 || n.nodeIndex == l){
5527                             r[++ri] = n;
5528                         }
5529                     } else if ((n.nodeIndex + l) % f == 0){
5530                         r[++ri] = n;
5531                     }
5532                 }
5533
5534                 return r;
5535             },
5536
5537             "only-child" : function(c){
5538                 var r = [], ri = -1;;
5539                 for(var i = 0, ci; ci = c[i]; i++){
5540                     if(!prev(ci) && !next(ci)){
5541                         r[++ri] = ci;
5542                     }
5543                 }
5544                 return r;
5545             },
5546
5547             "empty" : function(c){
5548                 var r = [], ri = -1;
5549                 for(var i = 0, ci; ci = c[i]; i++){
5550                     var cns = ci.childNodes, j = 0, cn, empty = true;
5551                     while(cn = cns[j]){
5552                         ++j;
5553                         if(cn.nodeType == 1 || cn.nodeType == 3){
5554                             empty = false;
5555                             break;
5556                         }
5557                     }
5558                     if(empty){
5559                         r[++ri] = ci;
5560                     }
5561                 }
5562                 return r;
5563             },
5564
5565             "contains" : function(c, v){
5566                 var r = [], ri = -1;
5567                 for(var i = 0, ci; ci = c[i]; i++){
5568                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5569                         r[++ri] = ci;
5570                     }
5571                 }
5572                 return r;
5573             },
5574
5575             "nodeValue" : function(c, v){
5576                 var r = [], ri = -1;
5577                 for(var i = 0, ci; ci = c[i]; i++){
5578                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5579                         r[++ri] = ci;
5580                     }
5581                 }
5582                 return r;
5583             },
5584
5585             "checked" : function(c){
5586                 var r = [], ri = -1;
5587                 for(var i = 0, ci; ci = c[i]; i++){
5588                     if(ci.checked == true){
5589                         r[++ri] = ci;
5590                     }
5591                 }
5592                 return r;
5593             },
5594
5595             "not" : function(c, ss){
5596                 return Roo.DomQuery.filter(c, ss, true);
5597             },
5598
5599             "odd" : function(c){
5600                 return this["nth-child"](c, "odd");
5601             },
5602
5603             "even" : function(c){
5604                 return this["nth-child"](c, "even");
5605             },
5606
5607             "nth" : function(c, a){
5608                 return c[a-1] || [];
5609             },
5610
5611             "first" : function(c){
5612                 return c[0] || [];
5613             },
5614
5615             "last" : function(c){
5616                 return c[c.length-1] || [];
5617             },
5618
5619             "has" : function(c, ss){
5620                 var s = Roo.DomQuery.select;
5621                 var r = [], ri = -1;
5622                 for(var i = 0, ci; ci = c[i]; i++){
5623                     if(s(ss, ci).length > 0){
5624                         r[++ri] = ci;
5625                     }
5626                 }
5627                 return r;
5628             },
5629
5630             "next" : 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 = next(ci);
5635                     if(n && is(n, ss)){
5636                         r[++ri] = ci;
5637                     }
5638                 }
5639                 return r;
5640             },
5641
5642             "prev" : function(c, ss){
5643                 var is = Roo.DomQuery.is;
5644                 var r = [], ri = -1;
5645                 for(var i = 0, ci; ci = c[i]; i++){
5646                     var n = prev(ci);
5647                     if(n && is(n, ss)){
5648                         r[++ri] = ci;
5649                     }
5650                 }
5651                 return r;
5652             }
5653         }
5654     };
5655 }();
5656
5657 /**
5658  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5659  * @param {String} path The selector/xpath query
5660  * @param {Node} root (optional) The start of the query (defaults to document).
5661  * @return {Array}
5662  * @member Roo
5663  * @method query
5664  */
5665 Roo.query = Roo.DomQuery.select;
5666 /*
5667  * Based on:
5668  * Ext JS Library 1.1.1
5669  * Copyright(c) 2006-2007, Ext JS, LLC.
5670  *
5671  * Originally Released Under LGPL - original licence link has changed is not relivant.
5672  *
5673  * Fork - LGPL
5674  * <script type="text/javascript">
5675  */
5676
5677 /**
5678  * @class Roo.util.Observable
5679  * Base class that provides a common interface for publishing events. Subclasses are expected to
5680  * to have a property "events" with all the events defined.<br>
5681  * For example:
5682  * <pre><code>
5683  Employee = function(name){
5684     this.name = name;
5685     this.addEvents({
5686         "fired" : true,
5687         "quit" : true
5688     });
5689  }
5690  Roo.extend(Employee, Roo.util.Observable);
5691 </code></pre>
5692  * @param {Object} config properties to use (incuding events / listeners)
5693  */
5694
5695 Roo.util.Observable = function(cfg){
5696     
5697     cfg = cfg|| {};
5698     this.addEvents(cfg.events || {});
5699     if (cfg.events) {
5700         delete cfg.events; // make sure
5701     }
5702      
5703     Roo.apply(this, cfg);
5704     
5705     if(this.listeners){
5706         this.on(this.listeners);
5707         delete this.listeners;
5708     }
5709 };
5710 Roo.util.Observable.prototype = {
5711     /** 
5712  * @cfg {Object} listeners  list of events and functions to call for this object, 
5713  * For example :
5714  * <pre><code>
5715     listeners :  { 
5716        'click' : function(e) {
5717            ..... 
5718         } ,
5719         .... 
5720     } 
5721   </code></pre>
5722  */
5723     
5724     
5725     /**
5726      * Fires the specified event with the passed parameters (minus the event name).
5727      * @param {String} eventName
5728      * @param {Object...} args Variable number of parameters are passed to handlers
5729      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5730      */
5731     fireEvent : function(){
5732         var ce = this.events[arguments[0].toLowerCase()];
5733         if(typeof ce == "object"){
5734             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5735         }else{
5736             return true;
5737         }
5738     },
5739
5740     // private
5741     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5742
5743     /**
5744      * Appends an event handler to this component
5745      * @param {String}   eventName The type of event to listen for
5746      * @param {Function} handler The method the event invokes
5747      * @param {Object}   scope (optional) The scope in which to execute the handler
5748      * function. The handler function's "this" context.
5749      * @param {Object}   options (optional) An object containing handler configuration
5750      * properties. This may contain any of the following properties:<ul>
5751      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5752      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5753      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5754      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5755      * by the specified number of milliseconds. If the event fires again within that time, the original
5756      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5757      * </ul><br>
5758      * <p>
5759      * <b>Combining Options</b><br>
5760      * Using the options argument, it is possible to combine different types of listeners:<br>
5761      * <br>
5762      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5763                 <pre><code>
5764                 el.on('click', this.onClick, this, {
5765                         single: true,
5766                 delay: 100,
5767                 forumId: 4
5768                 });
5769                 </code></pre>
5770      * <p>
5771      * <b>Attaching multiple handlers in 1 call</b><br>
5772      * The method also allows for a single argument to be passed which is a config object containing properties
5773      * which specify multiple handlers.
5774      * <pre><code>
5775                 el.on({
5776                         'click': {
5777                         fn: this.onClick,
5778                         scope: this,
5779                         delay: 100
5780                 }, 
5781                 'mouseover': {
5782                         fn: this.onMouseOver,
5783                         scope: this
5784                 },
5785                 'mouseout': {
5786                         fn: this.onMouseOut,
5787                         scope: this
5788                 }
5789                 });
5790                 </code></pre>
5791      * <p>
5792      * Or a shorthand syntax which passes the same scope object to all handlers:
5793         <pre><code>
5794                 el.on({
5795                         'click': this.onClick,
5796                 'mouseover': this.onMouseOver,
5797                 'mouseout': this.onMouseOut,
5798                 scope: this
5799                 });
5800                 </code></pre>
5801      */
5802     addListener : function(eventName, fn, scope, o){
5803         if(typeof eventName == "object"){
5804             o = eventName;
5805             for(var e in o){
5806                 if(this.filterOptRe.test(e)){
5807                     continue;
5808                 }
5809                 if(typeof o[e] == "function"){
5810                     // shared options
5811                     this.addListener(e, o[e], o.scope,  o);
5812                 }else{
5813                     // individual options
5814                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5815                 }
5816             }
5817             return;
5818         }
5819         o = (!o || typeof o == "boolean") ? {} : o;
5820         eventName = eventName.toLowerCase();
5821         var ce = this.events[eventName] || true;
5822         if(typeof ce == "boolean"){
5823             ce = new Roo.util.Event(this, eventName);
5824             this.events[eventName] = ce;
5825         }
5826         ce.addListener(fn, scope, o);
5827     },
5828
5829     /**
5830      * Removes a listener
5831      * @param {String}   eventName     The type of event to listen for
5832      * @param {Function} handler        The handler to remove
5833      * @param {Object}   scope  (optional) The scope (this object) for the handler
5834      */
5835     removeListener : function(eventName, fn, scope){
5836         var ce = this.events[eventName.toLowerCase()];
5837         if(typeof ce == "object"){
5838             ce.removeListener(fn, scope);
5839         }
5840     },
5841
5842     /**
5843      * Removes all listeners for this object
5844      */
5845     purgeListeners : function(){
5846         for(var evt in this.events){
5847             if(typeof this.events[evt] == "object"){
5848                  this.events[evt].clearListeners();
5849             }
5850         }
5851     },
5852
5853     relayEvents : function(o, events){
5854         var createHandler = function(ename){
5855             return function(){
5856                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5857             };
5858         };
5859         for(var i = 0, len = events.length; i < len; i++){
5860             var ename = events[i];
5861             if(!this.events[ename]){ this.events[ename] = true; };
5862             o.on(ename, createHandler(ename), this);
5863         }
5864     },
5865
5866     /**
5867      * Used to define events on this Observable
5868      * @param {Object} object The object with the events defined
5869      */
5870     addEvents : function(o){
5871         if(!this.events){
5872             this.events = {};
5873         }
5874         Roo.applyIf(this.events, o);
5875     },
5876
5877     /**
5878      * Checks to see if this object has any listeners for a specified event
5879      * @param {String} eventName The name of the event to check for
5880      * @return {Boolean} True if the event is being listened for, else false
5881      */
5882     hasListener : function(eventName){
5883         var e = this.events[eventName];
5884         return typeof e == "object" && e.listeners.length > 0;
5885     }
5886 };
5887 /**
5888  * Appends an event handler to this element (shorthand for addListener)
5889  * @param {String}   eventName     The type of event to listen for
5890  * @param {Function} handler        The method the event invokes
5891  * @param {Object}   scope (optional) The scope in which to execute the handler
5892  * function. The handler function's "this" context.
5893  * @param {Object}   options  (optional)
5894  * @method
5895  */
5896 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5897 /**
5898  * Removes a listener (shorthand for removeListener)
5899  * @param {String}   eventName     The type of event to listen for
5900  * @param {Function} handler        The handler to remove
5901  * @param {Object}   scope  (optional) The scope (this object) for the handler
5902  * @method
5903  */
5904 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5905
5906 /**
5907  * Starts capture on the specified Observable. All events will be passed
5908  * to the supplied function with the event name + standard signature of the event
5909  * <b>before</b> the event is fired. If the supplied function returns false,
5910  * the event will not fire.
5911  * @param {Observable} o The Observable to capture
5912  * @param {Function} fn The function to call
5913  * @param {Object} scope (optional) The scope (this object) for the fn
5914  * @static
5915  */
5916 Roo.util.Observable.capture = function(o, fn, scope){
5917     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5918 };
5919
5920 /**
5921  * Removes <b>all</b> added captures from the Observable.
5922  * @param {Observable} o The Observable to release
5923  * @static
5924  */
5925 Roo.util.Observable.releaseCapture = function(o){
5926     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5927 };
5928
5929 (function(){
5930
5931     var createBuffered = function(h, o, scope){
5932         var task = new Roo.util.DelayedTask();
5933         return function(){
5934             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5935         };
5936     };
5937
5938     var createSingle = function(h, e, fn, scope){
5939         return function(){
5940             e.removeListener(fn, scope);
5941             return h.apply(scope, arguments);
5942         };
5943     };
5944
5945     var createDelayed = function(h, o, scope){
5946         return function(){
5947             var args = Array.prototype.slice.call(arguments, 0);
5948             setTimeout(function(){
5949                 h.apply(scope, args);
5950             }, o.delay || 10);
5951         };
5952     };
5953
5954     Roo.util.Event = function(obj, name){
5955         this.name = name;
5956         this.obj = obj;
5957         this.listeners = [];
5958     };
5959
5960     Roo.util.Event.prototype = {
5961         addListener : function(fn, scope, options){
5962             var o = options || {};
5963             scope = scope || this.obj;
5964             if(!this.isListening(fn, scope)){
5965                 var l = {fn: fn, scope: scope, options: o};
5966                 var h = fn;
5967                 if(o.delay){
5968                     h = createDelayed(h, o, scope);
5969                 }
5970                 if(o.single){
5971                     h = createSingle(h, this, fn, scope);
5972                 }
5973                 if(o.buffer){
5974                     h = createBuffered(h, o, scope);
5975                 }
5976                 l.fireFn = h;
5977                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5978                     this.listeners.push(l);
5979                 }else{
5980                     this.listeners = this.listeners.slice(0);
5981                     this.listeners.push(l);
5982                 }
5983             }
5984         },
5985
5986         findListener : function(fn, scope){
5987             scope = scope || this.obj;
5988             var ls = this.listeners;
5989             for(var i = 0, len = ls.length; i < len; i++){
5990                 var l = ls[i];
5991                 if(l.fn == fn && l.scope == scope){
5992                     return i;
5993                 }
5994             }
5995             return -1;
5996         },
5997
5998         isListening : function(fn, scope){
5999             return this.findListener(fn, scope) != -1;
6000         },
6001
6002         removeListener : function(fn, scope){
6003             var index;
6004             if((index = this.findListener(fn, scope)) != -1){
6005                 if(!this.firing){
6006                     this.listeners.splice(index, 1);
6007                 }else{
6008                     this.listeners = this.listeners.slice(0);
6009                     this.listeners.splice(index, 1);
6010                 }
6011                 return true;
6012             }
6013             return false;
6014         },
6015
6016         clearListeners : function(){
6017             this.listeners = [];
6018         },
6019
6020         fire : function(){
6021             var ls = this.listeners, scope, len = ls.length;
6022             if(len > 0){
6023                 this.firing = true;
6024                 var args = Array.prototype.slice.call(arguments, 0);
6025                 for(var i = 0; i < len; i++){
6026                     var l = ls[i];
6027                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6028                         this.firing = false;
6029                         return false;
6030                     }
6031                 }
6032                 this.firing = false;
6033             }
6034             return true;
6035         }
6036     };
6037 })();/*
6038  * Based on:
6039  * Ext JS Library 1.1.1
6040  * Copyright(c) 2006-2007, Ext JS, LLC.
6041  *
6042  * Originally Released Under LGPL - original licence link has changed is not relivant.
6043  *
6044  * Fork - LGPL
6045  * <script type="text/javascript">
6046  */
6047
6048 /**
6049  * @class Roo.EventManager
6050  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6051  * several useful events directly.
6052  * See {@link Roo.EventObject} for more details on normalized event objects.
6053  * @singleton
6054  */
6055 Roo.EventManager = function(){
6056     var docReadyEvent, docReadyProcId, docReadyState = false;
6057     var resizeEvent, resizeTask, textEvent, textSize;
6058     var E = Roo.lib.Event;
6059     var D = Roo.lib.Dom;
6060
6061
6062     var fireDocReady = function(){
6063         if(!docReadyState){
6064             docReadyState = true;
6065             Roo.isReady = true;
6066             if(docReadyProcId){
6067                 clearInterval(docReadyProcId);
6068             }
6069             if(Roo.isGecko || Roo.isOpera) {
6070                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6071             }
6072             if(Roo.isIE){
6073                 var defer = document.getElementById("ie-deferred-loader");
6074                 if(defer){
6075                     defer.onreadystatechange = null;
6076                     defer.parentNode.removeChild(defer);
6077                 }
6078             }
6079             if(docReadyEvent){
6080                 docReadyEvent.fire();
6081                 docReadyEvent.clearListeners();
6082             }
6083         }
6084     };
6085     
6086     var initDocReady = function(){
6087         docReadyEvent = new Roo.util.Event();
6088         if(Roo.isGecko || Roo.isOpera) {
6089             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6090         }else if(Roo.isIE){
6091             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6092             var defer = document.getElementById("ie-deferred-loader");
6093             defer.onreadystatechange = function(){
6094                 if(this.readyState == "complete"){
6095                     fireDocReady();
6096                 }
6097             };
6098         }else if(Roo.isSafari){ 
6099             docReadyProcId = setInterval(function(){
6100                 var rs = document.readyState;
6101                 if(rs == "complete") {
6102                     fireDocReady();     
6103                  }
6104             }, 10);
6105         }
6106         // no matter what, make sure it fires on load
6107         E.on(window, "load", fireDocReady);
6108     };
6109
6110     var createBuffered = function(h, o){
6111         var task = new Roo.util.DelayedTask(h);
6112         return function(e){
6113             // create new event object impl so new events don't wipe out properties
6114             e = new Roo.EventObjectImpl(e);
6115             task.delay(o.buffer, h, null, [e]);
6116         };
6117     };
6118
6119     var createSingle = function(h, el, ename, fn){
6120         return function(e){
6121             Roo.EventManager.removeListener(el, ename, fn);
6122             h(e);
6123         };
6124     };
6125
6126     var createDelayed = function(h, o){
6127         return function(e){
6128             // create new event object impl so new events don't wipe out properties
6129             e = new Roo.EventObjectImpl(e);
6130             setTimeout(function(){
6131                 h(e);
6132             }, o.delay || 10);
6133         };
6134     };
6135
6136     var listen = function(element, ename, opt, fn, scope){
6137         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6138         fn = fn || o.fn; scope = scope || o.scope;
6139         var el = Roo.getDom(element);
6140         if(!el){
6141             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6142         }
6143         var h = function(e){
6144             e = Roo.EventObject.setEvent(e);
6145             var t;
6146             if(o.delegate){
6147                 t = e.getTarget(o.delegate, el);
6148                 if(!t){
6149                     return;
6150                 }
6151             }else{
6152                 t = e.target;
6153             }
6154             if(o.stopEvent === true){
6155                 e.stopEvent();
6156             }
6157             if(o.preventDefault === true){
6158                e.preventDefault();
6159             }
6160             if(o.stopPropagation === true){
6161                 e.stopPropagation();
6162             }
6163
6164             if(o.normalized === false){
6165                 e = e.browserEvent;
6166             }
6167
6168             fn.call(scope || el, e, t, o);
6169         };
6170         if(o.delay){
6171             h = createDelayed(h, o);
6172         }
6173         if(o.single){
6174             h = createSingle(h, el, ename, fn);
6175         }
6176         if(o.buffer){
6177             h = createBuffered(h, o);
6178         }
6179         fn._handlers = fn._handlers || [];
6180         fn._handlers.push([Roo.id(el), ename, h]);
6181
6182         E.on(el, ename, h);
6183         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6184             el.addEventListener("DOMMouseScroll", h, false);
6185             E.on(window, 'unload', function(){
6186                 el.removeEventListener("DOMMouseScroll", h, false);
6187             });
6188         }
6189         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6190             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6191         }
6192         return h;
6193     };
6194
6195     var stopListening = function(el, ename, fn){
6196         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6197         if(hds){
6198             for(var i = 0, len = hds.length; i < len; i++){
6199                 var h = hds[i];
6200                 if(h[0] == id && h[1] == ename){
6201                     hd = h[2];
6202                     hds.splice(i, 1);
6203                     break;
6204                 }
6205             }
6206         }
6207         E.un(el, ename, hd);
6208         el = Roo.getDom(el);
6209         if(ename == "mousewheel" && el.addEventListener){
6210             el.removeEventListener("DOMMouseScroll", hd, false);
6211         }
6212         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6213             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6214         }
6215     };
6216
6217     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6218     
6219     var pub = {
6220         
6221         
6222         /** 
6223          * Fix for doc tools
6224          * @scope Roo.EventManager
6225          */
6226         
6227         
6228         /** 
6229          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6230          * object with a Roo.EventObject
6231          * @param {Function} fn        The method the event invokes
6232          * @param {Object}   scope    An object that becomes the scope of the handler
6233          * @param {boolean}  override If true, the obj passed in becomes
6234          *                             the execution scope of the listener
6235          * @return {Function} The wrapped function
6236          * @deprecated
6237          */
6238         wrap : function(fn, scope, override){
6239             return function(e){
6240                 Roo.EventObject.setEvent(e);
6241                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6242             };
6243         },
6244         
6245         /**
6246      * Appends an event handler to an element (shorthand for addListener)
6247      * @param {String/HTMLElement}   element        The html element or id to assign the
6248      * @param {String}   eventName The type of event to listen for
6249      * @param {Function} handler The method the event invokes
6250      * @param {Object}   scope (optional) The scope in which to execute the handler
6251      * function. The handler function's "this" context.
6252      * @param {Object}   options (optional) An object containing handler configuration
6253      * properties. This may contain any of the following properties:<ul>
6254      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6255      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6256      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6257      * <li>preventDefault {Boolean} True to prevent the default action</li>
6258      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6259      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6260      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6261      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6262      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6263      * by the specified number of milliseconds. If the event fires again within that time, the original
6264      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6265      * </ul><br>
6266      * <p>
6267      * <b>Combining Options</b><br>
6268      * Using the options argument, it is possible to combine different types of listeners:<br>
6269      * <br>
6270      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6271      * Code:<pre><code>
6272 el.on('click', this.onClick, this, {
6273     single: true,
6274     delay: 100,
6275     stopEvent : true,
6276     forumId: 4
6277 });</code></pre>
6278      * <p>
6279      * <b>Attaching multiple handlers in 1 call</b><br>
6280       * The method also allows for a single argument to be passed which is a config object containing properties
6281      * which specify multiple handlers.
6282      * <p>
6283      * Code:<pre><code>
6284 el.on({
6285     'click' : {
6286         fn: this.onClick
6287         scope: this,
6288         delay: 100
6289     },
6290     'mouseover' : {
6291         fn: this.onMouseOver
6292         scope: this
6293     },
6294     'mouseout' : {
6295         fn: this.onMouseOut
6296         scope: this
6297     }
6298 });</code></pre>
6299      * <p>
6300      * Or a shorthand syntax:<br>
6301      * Code:<pre><code>
6302 el.on({
6303     'click' : this.onClick,
6304     'mouseover' : this.onMouseOver,
6305     'mouseout' : this.onMouseOut
6306     scope: this
6307 });</code></pre>
6308      */
6309         addListener : function(element, eventName, fn, scope, options){
6310             if(typeof eventName == "object"){
6311                 var o = eventName;
6312                 for(var e in o){
6313                     if(propRe.test(e)){
6314                         continue;
6315                     }
6316                     if(typeof o[e] == "function"){
6317                         // shared options
6318                         listen(element, e, o, o[e], o.scope);
6319                     }else{
6320                         // individual options
6321                         listen(element, e, o[e]);
6322                     }
6323                 }
6324                 return;
6325             }
6326             return listen(element, eventName, options, fn, scope);
6327         },
6328         
6329         /**
6330          * Removes an event handler
6331          *
6332          * @param {String/HTMLElement}   element        The id or html element to remove the 
6333          *                             event from
6334          * @param {String}   eventName     The type of event
6335          * @param {Function} fn
6336          * @return {Boolean} True if a listener was actually removed
6337          */
6338         removeListener : function(element, eventName, fn){
6339             return stopListening(element, eventName, fn);
6340         },
6341         
6342         /**
6343          * Fires when the document is ready (before onload and before images are loaded). Can be 
6344          * accessed shorthanded Roo.onReady().
6345          * @param {Function} fn        The method the event invokes
6346          * @param {Object}   scope    An  object that becomes the scope of the handler
6347          * @param {boolean}  options
6348          */
6349         onDocumentReady : function(fn, scope, options){
6350             if(docReadyState){ // if it already fired
6351                 docReadyEvent.addListener(fn, scope, options);
6352                 docReadyEvent.fire();
6353                 docReadyEvent.clearListeners();
6354                 return;
6355             }
6356             if(!docReadyEvent){
6357                 initDocReady();
6358             }
6359             docReadyEvent.addListener(fn, scope, options);
6360         },
6361         
6362         /**
6363          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6364          * @param {Function} fn        The method the event invokes
6365          * @param {Object}   scope    An object that becomes the scope of the handler
6366          * @param {boolean}  options
6367          */
6368         onWindowResize : function(fn, scope, options){
6369             if(!resizeEvent){
6370                 resizeEvent = new Roo.util.Event();
6371                 resizeTask = new Roo.util.DelayedTask(function(){
6372                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6373                 });
6374                 E.on(window, "resize", function(){
6375                     if(Roo.isIE){
6376                         resizeTask.delay(50);
6377                     }else{
6378                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6379                     }
6380                 });
6381             }
6382             resizeEvent.addListener(fn, scope, options);
6383         },
6384
6385         /**
6386          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6387          * @param {Function} fn        The method the event invokes
6388          * @param {Object}   scope    An object that becomes the scope of the handler
6389          * @param {boolean}  options
6390          */
6391         onTextResize : function(fn, scope, options){
6392             if(!textEvent){
6393                 textEvent = new Roo.util.Event();
6394                 var textEl = new Roo.Element(document.createElement('div'));
6395                 textEl.dom.className = 'x-text-resize';
6396                 textEl.dom.innerHTML = 'X';
6397                 textEl.appendTo(document.body);
6398                 textSize = textEl.dom.offsetHeight;
6399                 setInterval(function(){
6400                     if(textEl.dom.offsetHeight != textSize){
6401                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6402                     }
6403                 }, this.textResizeInterval);
6404             }
6405             textEvent.addListener(fn, scope, options);
6406         },
6407
6408         /**
6409          * Removes the passed window resize listener.
6410          * @param {Function} fn        The method the event invokes
6411          * @param {Object}   scope    The scope of handler
6412          */
6413         removeResizeListener : function(fn, scope){
6414             if(resizeEvent){
6415                 resizeEvent.removeListener(fn, scope);
6416             }
6417         },
6418
6419         // private
6420         fireResize : function(){
6421             if(resizeEvent){
6422                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6423             }   
6424         },
6425         /**
6426          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6427          */
6428         ieDeferSrc : false,
6429         /**
6430          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6431          */
6432         textResizeInterval : 50
6433     };
6434     
6435     /**
6436      * Fix for doc tools
6437      * @scopeAlias pub=Roo.EventManager
6438      */
6439     
6440      /**
6441      * Appends an event handler to an element (shorthand for addListener)
6442      * @param {String/HTMLElement}   element        The html element or id to assign the
6443      * @param {String}   eventName The type of event to listen for
6444      * @param {Function} handler The method the event invokes
6445      * @param {Object}   scope (optional) The scope in which to execute the handler
6446      * function. The handler function's "this" context.
6447      * @param {Object}   options (optional) An object containing handler configuration
6448      * properties. This may contain any of the following properties:<ul>
6449      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6450      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6451      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6452      * <li>preventDefault {Boolean} True to prevent the default action</li>
6453      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6454      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6455      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6456      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6457      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6458      * by the specified number of milliseconds. If the event fires again within that time, the original
6459      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6460      * </ul><br>
6461      * <p>
6462      * <b>Combining Options</b><br>
6463      * Using the options argument, it is possible to combine different types of listeners:<br>
6464      * <br>
6465      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6466      * Code:<pre><code>
6467 el.on('click', this.onClick, this, {
6468     single: true,
6469     delay: 100,
6470     stopEvent : true,
6471     forumId: 4
6472 });</code></pre>
6473      * <p>
6474      * <b>Attaching multiple handlers in 1 call</b><br>
6475       * The method also allows for a single argument to be passed which is a config object containing properties
6476      * which specify multiple handlers.
6477      * <p>
6478      * Code:<pre><code>
6479 el.on({
6480     'click' : {
6481         fn: this.onClick
6482         scope: this,
6483         delay: 100
6484     },
6485     'mouseover' : {
6486         fn: this.onMouseOver
6487         scope: this
6488     },
6489     'mouseout' : {
6490         fn: this.onMouseOut
6491         scope: this
6492     }
6493 });</code></pre>
6494      * <p>
6495      * Or a shorthand syntax:<br>
6496      * Code:<pre><code>
6497 el.on({
6498     'click' : this.onClick,
6499     'mouseover' : this.onMouseOver,
6500     'mouseout' : this.onMouseOut
6501     scope: this
6502 });</code></pre>
6503      */
6504     pub.on = pub.addListener;
6505     pub.un = pub.removeListener;
6506
6507     pub.stoppedMouseDownEvent = new Roo.util.Event();
6508     return pub;
6509 }();
6510 /**
6511   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6512   * @param {Function} fn        The method the event invokes
6513   * @param {Object}   scope    An  object that becomes the scope of the handler
6514   * @param {boolean}  override If true, the obj passed in becomes
6515   *                             the execution scope of the listener
6516   * @member Roo
6517   * @method onReady
6518  */
6519 Roo.onReady = Roo.EventManager.onDocumentReady;
6520
6521 Roo.onReady(function(){
6522     var bd = Roo.get(document.body);
6523     if(!bd){ return; }
6524
6525     var cls = [
6526             Roo.isIE ? "roo-ie"
6527             : Roo.isGecko ? "roo-gecko"
6528             : Roo.isOpera ? "roo-opera"
6529             : Roo.isSafari ? "roo-safari" : ""];
6530
6531     if(Roo.isMac){
6532         cls.push("roo-mac");
6533     }
6534     if(Roo.isLinux){
6535         cls.push("roo-linux");
6536     }
6537     if(Roo.isBorderBox){
6538         cls.push('roo-border-box');
6539     }
6540     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6541         var p = bd.dom.parentNode;
6542         if(p){
6543             p.className += ' roo-strict';
6544         }
6545     }
6546     bd.addClass(cls.join(' '));
6547 });
6548
6549 /**
6550  * @class Roo.EventObject
6551  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6552  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6553  * Example:
6554  * <pre><code>
6555  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6556     e.preventDefault();
6557     var target = e.getTarget();
6558     ...
6559  }
6560  var myDiv = Roo.get("myDiv");
6561  myDiv.on("click", handleClick);
6562  //or
6563  Roo.EventManager.on("myDiv", 'click', handleClick);
6564  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6565  </code></pre>
6566  * @singleton
6567  */
6568 Roo.EventObject = function(){
6569     
6570     var E = Roo.lib.Event;
6571     
6572     // safari keypress events for special keys return bad keycodes
6573     var safariKeys = {
6574         63234 : 37, // left
6575         63235 : 39, // right
6576         63232 : 38, // up
6577         63233 : 40, // down
6578         63276 : 33, // page up
6579         63277 : 34, // page down
6580         63272 : 46, // delete
6581         63273 : 36, // home
6582         63275 : 35  // end
6583     };
6584
6585     // normalize button clicks
6586     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6587                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6588
6589     Roo.EventObjectImpl = function(e){
6590         if(e){
6591             this.setEvent(e.browserEvent || e);
6592         }
6593     };
6594     Roo.EventObjectImpl.prototype = {
6595         /**
6596          * Used to fix doc tools.
6597          * @scope Roo.EventObject.prototype
6598          */
6599             
6600
6601         
6602         
6603         /** The normal browser event */
6604         browserEvent : null,
6605         /** The button pressed in a mouse event */
6606         button : -1,
6607         /** True if the shift key was down during the event */
6608         shiftKey : false,
6609         /** True if the control key was down during the event */
6610         ctrlKey : false,
6611         /** True if the alt key was down during the event */
6612         altKey : false,
6613
6614         /** Key constant 
6615         * @type Number */
6616         BACKSPACE : 8,
6617         /** Key constant 
6618         * @type Number */
6619         TAB : 9,
6620         /** Key constant 
6621         * @type Number */
6622         RETURN : 13,
6623         /** Key constant 
6624         * @type Number */
6625         ENTER : 13,
6626         /** Key constant 
6627         * @type Number */
6628         SHIFT : 16,
6629         /** Key constant 
6630         * @type Number */
6631         CONTROL : 17,
6632         /** Key constant 
6633         * @type Number */
6634         ESC : 27,
6635         /** Key constant 
6636         * @type Number */
6637         SPACE : 32,
6638         /** Key constant 
6639         * @type Number */
6640         PAGEUP : 33,
6641         /** Key constant 
6642         * @type Number */
6643         PAGEDOWN : 34,
6644         /** Key constant 
6645         * @type Number */
6646         END : 35,
6647         /** Key constant 
6648         * @type Number */
6649         HOME : 36,
6650         /** Key constant 
6651         * @type Number */
6652         LEFT : 37,
6653         /** Key constant 
6654         * @type Number */
6655         UP : 38,
6656         /** Key constant 
6657         * @type Number */
6658         RIGHT : 39,
6659         /** Key constant 
6660         * @type Number */
6661         DOWN : 40,
6662         /** Key constant 
6663         * @type Number */
6664         DELETE : 46,
6665         /** Key constant 
6666         * @type Number */
6667         F5 : 116,
6668
6669            /** @private */
6670         setEvent : function(e){
6671             if(e == this || (e && e.browserEvent)){ // already wrapped
6672                 return e;
6673             }
6674             this.browserEvent = e;
6675             if(e){
6676                 // normalize buttons
6677                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6678                 if(e.type == 'click' && this.button == -1){
6679                     this.button = 0;
6680                 }
6681                 this.type = e.type;
6682                 this.shiftKey = e.shiftKey;
6683                 // mac metaKey behaves like ctrlKey
6684                 this.ctrlKey = e.ctrlKey || e.metaKey;
6685                 this.altKey = e.altKey;
6686                 // in getKey these will be normalized for the mac
6687                 this.keyCode = e.keyCode;
6688                 // keyup warnings on firefox.
6689                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6690                 // cache the target for the delayed and or buffered events
6691                 this.target = E.getTarget(e);
6692                 // same for XY
6693                 this.xy = E.getXY(e);
6694             }else{
6695                 this.button = -1;
6696                 this.shiftKey = false;
6697                 this.ctrlKey = false;
6698                 this.altKey = false;
6699                 this.keyCode = 0;
6700                 this.charCode =0;
6701                 this.target = null;
6702                 this.xy = [0, 0];
6703             }
6704             return this;
6705         },
6706
6707         /**
6708          * Stop the event (preventDefault and stopPropagation)
6709          */
6710         stopEvent : function(){
6711             if(this.browserEvent){
6712                 if(this.browserEvent.type == 'mousedown'){
6713                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6714                 }
6715                 E.stopEvent(this.browserEvent);
6716             }
6717         },
6718
6719         /**
6720          * Prevents the browsers default handling of the event.
6721          */
6722         preventDefault : function(){
6723             if(this.browserEvent){
6724                 E.preventDefault(this.browserEvent);
6725             }
6726         },
6727
6728         /** @private */
6729         isNavKeyPress : function(){
6730             var k = this.keyCode;
6731             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6732             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6733         },
6734
6735         isSpecialKey : function(){
6736             var k = this.keyCode;
6737             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6738             (k == 16) || (k == 17) ||
6739             (k >= 18 && k <= 20) ||
6740             (k >= 33 && k <= 35) ||
6741             (k >= 36 && k <= 39) ||
6742             (k >= 44 && k <= 45);
6743         },
6744         /**
6745          * Cancels bubbling of the event.
6746          */
6747         stopPropagation : function(){
6748             if(this.browserEvent){
6749                 if(this.type == 'mousedown'){
6750                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6751                 }
6752                 E.stopPropagation(this.browserEvent);
6753             }
6754         },
6755
6756         /**
6757          * Gets the key code for the event.
6758          * @return {Number}
6759          */
6760         getCharCode : function(){
6761             return this.charCode || this.keyCode;
6762         },
6763
6764         /**
6765          * Returns a normalized keyCode for the event.
6766          * @return {Number} The key code
6767          */
6768         getKey : function(){
6769             var k = this.keyCode || this.charCode;
6770             return Roo.isSafari ? (safariKeys[k] || k) : k;
6771         },
6772
6773         /**
6774          * Gets the x coordinate of the event.
6775          * @return {Number}
6776          */
6777         getPageX : function(){
6778             return this.xy[0];
6779         },
6780
6781         /**
6782          * Gets the y coordinate of the event.
6783          * @return {Number}
6784          */
6785         getPageY : function(){
6786             return this.xy[1];
6787         },
6788
6789         /**
6790          * Gets the time of the event.
6791          * @return {Number}
6792          */
6793         getTime : function(){
6794             if(this.browserEvent){
6795                 return E.getTime(this.browserEvent);
6796             }
6797             return null;
6798         },
6799
6800         /**
6801          * Gets the page coordinates of the event.
6802          * @return {Array} The xy values like [x, y]
6803          */
6804         getXY : function(){
6805             return this.xy;
6806         },
6807
6808         /**
6809          * Gets the target for the event.
6810          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6811          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6812                 search as a number or element (defaults to 10 || document.body)
6813          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6814          * @return {HTMLelement}
6815          */
6816         getTarget : function(selector, maxDepth, returnEl){
6817             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6818         },
6819         /**
6820          * Gets the related target.
6821          * @return {HTMLElement}
6822          */
6823         getRelatedTarget : function(){
6824             if(this.browserEvent){
6825                 return E.getRelatedTarget(this.browserEvent);
6826             }
6827             return null;
6828         },
6829
6830         /**
6831          * Normalizes mouse wheel delta across browsers
6832          * @return {Number} The delta
6833          */
6834         getWheelDelta : function(){
6835             var e = this.browserEvent;
6836             var delta = 0;
6837             if(e.wheelDelta){ /* IE/Opera. */
6838                 delta = e.wheelDelta/120;
6839             }else if(e.detail){ /* Mozilla case. */
6840                 delta = -e.detail/3;
6841             }
6842             return delta;
6843         },
6844
6845         /**
6846          * Returns true if the control, meta, shift or alt key was pressed during this event.
6847          * @return {Boolean}
6848          */
6849         hasModifier : function(){
6850             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6851         },
6852
6853         /**
6854          * Returns true if the target of this event equals el or is a child of el
6855          * @param {String/HTMLElement/Element} el
6856          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6857          * @return {Boolean}
6858          */
6859         within : function(el, related){
6860             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6861             return t && Roo.fly(el).contains(t);
6862         },
6863
6864         getPoint : function(){
6865             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6866         }
6867     };
6868
6869     return new Roo.EventObjectImpl();
6870 }();
6871             
6872     /*
6873  * Based on:
6874  * Ext JS Library 1.1.1
6875  * Copyright(c) 2006-2007, Ext JS, LLC.
6876  *
6877  * Originally Released Under LGPL - original licence link has changed is not relivant.
6878  *
6879  * Fork - LGPL
6880  * <script type="text/javascript">
6881  */
6882
6883  
6884 // was in Composite Element!??!?!
6885  
6886 (function(){
6887     var D = Roo.lib.Dom;
6888     var E = Roo.lib.Event;
6889     var A = Roo.lib.Anim;
6890
6891     // local style camelizing for speed
6892     var propCache = {};
6893     var camelRe = /(-[a-z])/gi;
6894     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6895     var view = document.defaultView;
6896
6897 /**
6898  * @class Roo.Element
6899  * Represents an Element in the DOM.<br><br>
6900  * Usage:<br>
6901 <pre><code>
6902 var el = Roo.get("my-div");
6903
6904 // or with getEl
6905 var el = getEl("my-div");
6906
6907 // or with a DOM element
6908 var el = Roo.get(myDivElement);
6909 </code></pre>
6910  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6911  * each call instead of constructing a new one.<br><br>
6912  * <b>Animations</b><br />
6913  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6914  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6915 <pre>
6916 Option    Default   Description
6917 --------- --------  ---------------------------------------------
6918 duration  .35       The duration of the animation in seconds
6919 easing    easeOut   The YUI easing method
6920 callback  none      A function to execute when the anim completes
6921 scope     this      The scope (this) of the callback function
6922 </pre>
6923 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6924 * manipulate the animation. Here's an example:
6925 <pre><code>
6926 var el = Roo.get("my-div");
6927
6928 // no animation
6929 el.setWidth(100);
6930
6931 // default animation
6932 el.setWidth(100, true);
6933
6934 // animation with some options set
6935 el.setWidth(100, {
6936     duration: 1,
6937     callback: this.foo,
6938     scope: this
6939 });
6940
6941 // using the "anim" property to get the Anim object
6942 var opt = {
6943     duration: 1,
6944     callback: this.foo,
6945     scope: this
6946 };
6947 el.setWidth(100, opt);
6948 ...
6949 if(opt.anim.isAnimated()){
6950     opt.anim.stop();
6951 }
6952 </code></pre>
6953 * <b> Composite (Collections of) Elements</b><br />
6954  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6955  * @constructor Create a new Element directly.
6956  * @param {String/HTMLElement} element
6957  * @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).
6958  */
6959     Roo.Element = function(element, forceNew){
6960         var dom = typeof element == "string" ?
6961                 document.getElementById(element) : element;
6962         if(!dom){ // invalid id/element
6963             return null;
6964         }
6965         var id = dom.id;
6966         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6967             return Roo.Element.cache[id];
6968         }
6969
6970         /**
6971          * The DOM element
6972          * @type HTMLElement
6973          */
6974         this.dom = dom;
6975
6976         /**
6977          * The DOM element ID
6978          * @type String
6979          */
6980         this.id = id || Roo.id(dom);
6981     };
6982
6983     var El = Roo.Element;
6984
6985     El.prototype = {
6986         /**
6987          * The element's default display mode  (defaults to "")
6988          * @type String
6989          */
6990         originalDisplay : "",
6991
6992         visibilityMode : 1,
6993         /**
6994          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6995          * @type String
6996          */
6997         defaultUnit : "px",
6998         /**
6999          * Sets the element's visibility mode. When setVisible() is called it
7000          * will use this to determine whether to set the visibility or the display property.
7001          * @param visMode Element.VISIBILITY or Element.DISPLAY
7002          * @return {Roo.Element} this
7003          */
7004         setVisibilityMode : function(visMode){
7005             this.visibilityMode = visMode;
7006             return this;
7007         },
7008         /**
7009          * Convenience method for setVisibilityMode(Element.DISPLAY)
7010          * @param {String} display (optional) What to set display to when visible
7011          * @return {Roo.Element} this
7012          */
7013         enableDisplayMode : function(display){
7014             this.setVisibilityMode(El.DISPLAY);
7015             if(typeof display != "undefined") this.originalDisplay = display;
7016             return this;
7017         },
7018
7019         /**
7020          * 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)
7021          * @param {String} selector The simple selector to test
7022          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7023                 search as a number or element (defaults to 10 || document.body)
7024          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7025          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7026          */
7027         findParent : function(simpleSelector, maxDepth, returnEl){
7028             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7029             maxDepth = maxDepth || 50;
7030             if(typeof maxDepth != "number"){
7031                 stopEl = Roo.getDom(maxDepth);
7032                 maxDepth = 10;
7033             }
7034             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7035                 if(dq.is(p, simpleSelector)){
7036                     return returnEl ? Roo.get(p) : p;
7037                 }
7038                 depth++;
7039                 p = p.parentNode;
7040             }
7041             return null;
7042         },
7043
7044
7045         /**
7046          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7047          * @param {String} selector The simple selector to test
7048          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049                 search as a number or element (defaults to 10 || document.body)
7050          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7051          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7052          */
7053         findParentNode : function(simpleSelector, maxDepth, returnEl){
7054             var p = Roo.fly(this.dom.parentNode, '_internal');
7055             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7056         },
7057
7058         /**
7059          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7060          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7061          * @param {String} selector The simple selector to test
7062          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7063                 search as a number or element (defaults to 10 || document.body)
7064          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7065          */
7066         up : function(simpleSelector, maxDepth){
7067             return this.findParentNode(simpleSelector, maxDepth, true);
7068         },
7069
7070
7071
7072         /**
7073          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7074          * @param {String} selector The simple selector to test
7075          * @return {Boolean} True if this element matches the selector, else false
7076          */
7077         is : function(simpleSelector){
7078             return Roo.DomQuery.is(this.dom, simpleSelector);
7079         },
7080
7081         /**
7082          * Perform animation on this element.
7083          * @param {Object} args The YUI animation control args
7084          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7085          * @param {Function} onComplete (optional) Function to call when animation completes
7086          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7087          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7088          * @return {Roo.Element} this
7089          */
7090         animate : function(args, duration, onComplete, easing, animType){
7091             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7092             return this;
7093         },
7094
7095         /*
7096          * @private Internal animation call
7097          */
7098         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7099             animType = animType || 'run';
7100             opt = opt || {};
7101             var anim = Roo.lib.Anim[animType](
7102                 this.dom, args,
7103                 (opt.duration || defaultDur) || .35,
7104                 (opt.easing || defaultEase) || 'easeOut',
7105                 function(){
7106                     Roo.callback(cb, this);
7107                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7108                 },
7109                 this
7110             );
7111             opt.anim = anim;
7112             return anim;
7113         },
7114
7115         // private legacy anim prep
7116         preanim : function(a, i){
7117             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7118         },
7119
7120         /**
7121          * Removes worthless text nodes
7122          * @param {Boolean} forceReclean (optional) By default the element
7123          * keeps track if it has been cleaned already so
7124          * you can call this over and over. However, if you update the element and
7125          * need to force a reclean, you can pass true.
7126          */
7127         clean : function(forceReclean){
7128             if(this.isCleaned && forceReclean !== true){
7129                 return this;
7130             }
7131             var ns = /\S/;
7132             var d = this.dom, n = d.firstChild, ni = -1;
7133             while(n){
7134                 var nx = n.nextSibling;
7135                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7136                     d.removeChild(n);
7137                 }else{
7138                     n.nodeIndex = ++ni;
7139                 }
7140                 n = nx;
7141             }
7142             this.isCleaned = true;
7143             return this;
7144         },
7145
7146         // private
7147         calcOffsetsTo : function(el){
7148             el = Roo.get(el);
7149             var d = el.dom;
7150             var restorePos = false;
7151             if(el.getStyle('position') == 'static'){
7152                 el.position('relative');
7153                 restorePos = true;
7154             }
7155             var x = 0, y =0;
7156             var op = this.dom;
7157             while(op && op != d && op.tagName != 'HTML'){
7158                 x+= op.offsetLeft;
7159                 y+= op.offsetTop;
7160                 op = op.offsetParent;
7161             }
7162             if(restorePos){
7163                 el.position('static');
7164             }
7165             return [x, y];
7166         },
7167
7168         /**
7169          * Scrolls this element into view within the passed container.
7170          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7171          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7172          * @return {Roo.Element} this
7173          */
7174         scrollIntoView : function(container, hscroll){
7175             var c = Roo.getDom(container) || document.body;
7176             var el = this.dom;
7177
7178             var o = this.calcOffsetsTo(c),
7179                 l = o[0],
7180                 t = o[1],
7181                 b = t+el.offsetHeight,
7182                 r = l+el.offsetWidth;
7183
7184             var ch = c.clientHeight;
7185             var ct = parseInt(c.scrollTop, 10);
7186             var cl = parseInt(c.scrollLeft, 10);
7187             var cb = ct + ch;
7188             var cr = cl + c.clientWidth;
7189
7190             if(t < ct){
7191                 c.scrollTop = t;
7192             }else if(b > cb){
7193                 c.scrollTop = b-ch;
7194             }
7195
7196             if(hscroll !== false){
7197                 if(l < cl){
7198                     c.scrollLeft = l;
7199                 }else if(r > cr){
7200                     c.scrollLeft = r-c.clientWidth;
7201                 }
7202             }
7203             return this;
7204         },
7205
7206         // private
7207         scrollChildIntoView : function(child, hscroll){
7208             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7209         },
7210
7211         /**
7212          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7213          * the new height may not be available immediately.
7214          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7215          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7216          * @param {Function} onComplete (optional) Function to call when animation completes
7217          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7218          * @return {Roo.Element} this
7219          */
7220         autoHeight : function(animate, duration, onComplete, easing){
7221             var oldHeight = this.getHeight();
7222             this.clip();
7223             this.setHeight(1); // force clipping
7224             setTimeout(function(){
7225                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7226                 if(!animate){
7227                     this.setHeight(height);
7228                     this.unclip();
7229                     if(typeof onComplete == "function"){
7230                         onComplete();
7231                     }
7232                 }else{
7233                     this.setHeight(oldHeight); // restore original height
7234                     this.setHeight(height, animate, duration, function(){
7235                         this.unclip();
7236                         if(typeof onComplete == "function") onComplete();
7237                     }.createDelegate(this), easing);
7238                 }
7239             }.createDelegate(this), 0);
7240             return this;
7241         },
7242
7243         /**
7244          * Returns true if this element is an ancestor of the passed element
7245          * @param {HTMLElement/String} el The element to check
7246          * @return {Boolean} True if this element is an ancestor of el, else false
7247          */
7248         contains : function(el){
7249             if(!el){return false;}
7250             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7251         },
7252
7253         /**
7254          * Checks whether the element is currently visible using both visibility and display properties.
7255          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7256          * @return {Boolean} True if the element is currently visible, else false
7257          */
7258         isVisible : function(deep) {
7259             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7260             if(deep !== true || !vis){
7261                 return vis;
7262             }
7263             var p = this.dom.parentNode;
7264             while(p && p.tagName.toLowerCase() != "body"){
7265                 if(!Roo.fly(p, '_isVisible').isVisible()){
7266                     return false;
7267                 }
7268                 p = p.parentNode;
7269             }
7270             return true;
7271         },
7272
7273         /**
7274          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7275          * @param {String} selector The CSS selector
7276          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7277          * @return {CompositeElement/CompositeElementLite} The composite element
7278          */
7279         select : function(selector, unique){
7280             return El.select(selector, unique, this.dom);
7281         },
7282
7283         /**
7284          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7285          * @param {String} selector The CSS selector
7286          * @return {Array} An array of the matched nodes
7287          */
7288         query : function(selector, unique){
7289             return Roo.DomQuery.select(selector, this.dom);
7290         },
7291
7292         /**
7293          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7294          * @param {String} selector The CSS selector
7295          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7296          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7297          */
7298         child : function(selector, returnDom){
7299             var n = Roo.DomQuery.selectNode(selector, this.dom);
7300             return returnDom ? n : Roo.get(n);
7301         },
7302
7303         /**
7304          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7305          * @param {String} selector The CSS selector
7306          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7307          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7308          */
7309         down : function(selector, returnDom){
7310             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7311             return returnDom ? n : Roo.get(n);
7312         },
7313
7314         /**
7315          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7316          * @param {String} group The group the DD object is member of
7317          * @param {Object} config The DD config object
7318          * @param {Object} overrides An object containing methods to override/implement on the DD object
7319          * @return {Roo.dd.DD} The DD object
7320          */
7321         initDD : function(group, config, overrides){
7322             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7323             return Roo.apply(dd, overrides);
7324         },
7325
7326         /**
7327          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7328          * @param {String} group The group the DDProxy object is member of
7329          * @param {Object} config The DDProxy config object
7330          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7331          * @return {Roo.dd.DDProxy} The DDProxy object
7332          */
7333         initDDProxy : function(group, config, overrides){
7334             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7335             return Roo.apply(dd, overrides);
7336         },
7337
7338         /**
7339          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7340          * @param {String} group The group the DDTarget object is member of
7341          * @param {Object} config The DDTarget config object
7342          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7343          * @return {Roo.dd.DDTarget} The DDTarget object
7344          */
7345         initDDTarget : function(group, config, overrides){
7346             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7347             return Roo.apply(dd, overrides);
7348         },
7349
7350         /**
7351          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7352          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7353          * @param {Boolean} visible Whether the element is visible
7354          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7355          * @return {Roo.Element} this
7356          */
7357          setVisible : function(visible, animate){
7358             if(!animate || !A){
7359                 if(this.visibilityMode == El.DISPLAY){
7360                     this.setDisplayed(visible);
7361                 }else{
7362                     this.fixDisplay();
7363                     this.dom.style.visibility = visible ? "visible" : "hidden";
7364                 }
7365             }else{
7366                 // closure for composites
7367                 var dom = this.dom;
7368                 var visMode = this.visibilityMode;
7369                 if(visible){
7370                     this.setOpacity(.01);
7371                     this.setVisible(true);
7372                 }
7373                 this.anim({opacity: { to: (visible?1:0) }},
7374                       this.preanim(arguments, 1),
7375                       null, .35, 'easeIn', function(){
7376                          if(!visible){
7377                              if(visMode == El.DISPLAY){
7378                                  dom.style.display = "none";
7379                              }else{
7380                                  dom.style.visibility = "hidden";
7381                              }
7382                              Roo.get(dom).setOpacity(1);
7383                          }
7384                      });
7385             }
7386             return this;
7387         },
7388
7389         /**
7390          * Returns true if display is not "none"
7391          * @return {Boolean}
7392          */
7393         isDisplayed : function() {
7394             return this.getStyle("display") != "none";
7395         },
7396
7397         /**
7398          * Toggles the element's visibility or display, depending on visibility mode.
7399          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7400          * @return {Roo.Element} this
7401          */
7402         toggle : function(animate){
7403             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7404             return this;
7405         },
7406
7407         /**
7408          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7409          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7410          * @return {Roo.Element} this
7411          */
7412         setDisplayed : function(value) {
7413             if(typeof value == "boolean"){
7414                value = value ? this.originalDisplay : "none";
7415             }
7416             this.setStyle("display", value);
7417             return this;
7418         },
7419
7420         /**
7421          * Tries to focus the element. Any exceptions are caught and ignored.
7422          * @return {Roo.Element} this
7423          */
7424         focus : function() {
7425             try{
7426                 this.dom.focus();
7427             }catch(e){}
7428             return this;
7429         },
7430
7431         /**
7432          * Tries to blur the element. Any exceptions are caught and ignored.
7433          * @return {Roo.Element} this
7434          */
7435         blur : function() {
7436             try{
7437                 this.dom.blur();
7438             }catch(e){}
7439             return this;
7440         },
7441
7442         /**
7443          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7444          * @param {String/Array} className The CSS class to add, or an array of classes
7445          * @return {Roo.Element} this
7446          */
7447         addClass : function(className){
7448             if(className instanceof Array){
7449                 for(var i = 0, len = className.length; i < len; i++) {
7450                     this.addClass(className[i]);
7451                 }
7452             }else{
7453                 if(className && !this.hasClass(className)){
7454                     this.dom.className = this.dom.className + " " + className;
7455                 }
7456             }
7457             return this;
7458         },
7459
7460         /**
7461          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7462          * @param {String/Array} className The CSS class to add, or an array of classes
7463          * @return {Roo.Element} this
7464          */
7465         radioClass : function(className){
7466             var siblings = this.dom.parentNode.childNodes;
7467             for(var i = 0; i < siblings.length; i++) {
7468                 var s = siblings[i];
7469                 if(s.nodeType == 1){
7470                     Roo.get(s).removeClass(className);
7471                 }
7472             }
7473             this.addClass(className);
7474             return this;
7475         },
7476
7477         /**
7478          * Removes one or more CSS classes from the element.
7479          * @param {String/Array} className The CSS class to remove, or an array of classes
7480          * @return {Roo.Element} this
7481          */
7482         removeClass : function(className){
7483             if(!className || !this.dom.className){
7484                 return this;
7485             }
7486             if(className instanceof Array){
7487                 for(var i = 0, len = className.length; i < len; i++) {
7488                     this.removeClass(className[i]);
7489                 }
7490             }else{
7491                 if(this.hasClass(className)){
7492                     var re = this.classReCache[className];
7493                     if (!re) {
7494                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7495                        this.classReCache[className] = re;
7496                     }
7497                     this.dom.className =
7498                         this.dom.className.replace(re, " ");
7499                 }
7500             }
7501             return this;
7502         },
7503
7504         // private
7505         classReCache: {},
7506
7507         /**
7508          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7509          * @param {String} className The CSS class to toggle
7510          * @return {Roo.Element} this
7511          */
7512         toggleClass : function(className){
7513             if(this.hasClass(className)){
7514                 this.removeClass(className);
7515             }else{
7516                 this.addClass(className);
7517             }
7518             return this;
7519         },
7520
7521         /**
7522          * Checks if the specified CSS class exists on this element's DOM node.
7523          * @param {String} className The CSS class to check for
7524          * @return {Boolean} True if the class exists, else false
7525          */
7526         hasClass : function(className){
7527             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7528         },
7529
7530         /**
7531          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7532          * @param {String} oldClassName The CSS class to replace
7533          * @param {String} newClassName The replacement CSS class
7534          * @return {Roo.Element} this
7535          */
7536         replaceClass : function(oldClassName, newClassName){
7537             this.removeClass(oldClassName);
7538             this.addClass(newClassName);
7539             return this;
7540         },
7541
7542         /**
7543          * Returns an object with properties matching the styles requested.
7544          * For example, el.getStyles('color', 'font-size', 'width') might return
7545          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7546          * @param {String} style1 A style name
7547          * @param {String} style2 A style name
7548          * @param {String} etc.
7549          * @return {Object} The style object
7550          */
7551         getStyles : function(){
7552             var a = arguments, len = a.length, r = {};
7553             for(var i = 0; i < len; i++){
7554                 r[a[i]] = this.getStyle(a[i]);
7555             }
7556             return r;
7557         },
7558
7559         /**
7560          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7561          * @param {String} property The style property whose value is returned.
7562          * @return {String} The current value of the style property for this element.
7563          */
7564         getStyle : function(){
7565             return view && view.getComputedStyle ?
7566                 function(prop){
7567                     var el = this.dom, v, cs, camel;
7568                     if(prop == 'float'){
7569                         prop = "cssFloat";
7570                     }
7571                     if(el.style && (v = el.style[prop])){
7572                         return v;
7573                     }
7574                     if(cs = view.getComputedStyle(el, "")){
7575                         if(!(camel = propCache[prop])){
7576                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7577                         }
7578                         return cs[camel];
7579                     }
7580                     return null;
7581                 } :
7582                 function(prop){
7583                     var el = this.dom, v, cs, camel;
7584                     if(prop == 'opacity'){
7585                         if(typeof el.style.filter == 'string'){
7586                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7587                             if(m){
7588                                 var fv = parseFloat(m[1]);
7589                                 if(!isNaN(fv)){
7590                                     return fv ? fv / 100 : 0;
7591                                 }
7592                             }
7593                         }
7594                         return 1;
7595                     }else if(prop == 'float'){
7596                         prop = "styleFloat";
7597                     }
7598                     if(!(camel = propCache[prop])){
7599                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7600                     }
7601                     if(v = el.style[camel]){
7602                         return v;
7603                     }
7604                     if(cs = el.currentStyle){
7605                         return cs[camel];
7606                     }
7607                     return null;
7608                 };
7609         }(),
7610
7611         /**
7612          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7613          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7614          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7615          * @return {Roo.Element} this
7616          */
7617         setStyle : function(prop, value){
7618             if(typeof prop == "string"){
7619                 
7620                 if (prop == 'float') {
7621                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7622                     return this;
7623                 }
7624                 
7625                 var camel;
7626                 if(!(camel = propCache[prop])){
7627                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7628                 }
7629                 
7630                 if(camel == 'opacity') {
7631                     this.setOpacity(value);
7632                 }else{
7633                     this.dom.style[camel] = value;
7634                 }
7635             }else{
7636                 for(var style in prop){
7637                     if(typeof prop[style] != "function"){
7638                        this.setStyle(style, prop[style]);
7639                     }
7640                 }
7641             }
7642             return this;
7643         },
7644
7645         /**
7646          * More flexible version of {@link #setStyle} for setting style properties.
7647          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7648          * a function which returns such a specification.
7649          * @return {Roo.Element} this
7650          */
7651         applyStyles : function(style){
7652             Roo.DomHelper.applyStyles(this.dom, style);
7653             return this;
7654         },
7655
7656         /**
7657           * 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).
7658           * @return {Number} The X position of the element
7659           */
7660         getX : function(){
7661             return D.getX(this.dom);
7662         },
7663
7664         /**
7665           * 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).
7666           * @return {Number} The Y position of the element
7667           */
7668         getY : function(){
7669             return D.getY(this.dom);
7670         },
7671
7672         /**
7673           * 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).
7674           * @return {Array} The XY position of the element
7675           */
7676         getXY : function(){
7677             return D.getXY(this.dom);
7678         },
7679
7680         /**
7681          * 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).
7682          * @param {Number} The X position of the element
7683          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7684          * @return {Roo.Element} this
7685          */
7686         setX : function(x, animate){
7687             if(!animate || !A){
7688                 D.setX(this.dom, x);
7689             }else{
7690                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7691             }
7692             return this;
7693         },
7694
7695         /**
7696          * 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).
7697          * @param {Number} The Y position of the element
7698          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7699          * @return {Roo.Element} this
7700          */
7701         setY : function(y, animate){
7702             if(!animate || !A){
7703                 D.setY(this.dom, y);
7704             }else{
7705                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7706             }
7707             return this;
7708         },
7709
7710         /**
7711          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7712          * @param {String} left The left CSS property value
7713          * @return {Roo.Element} this
7714          */
7715         setLeft : function(left){
7716             this.setStyle("left", this.addUnits(left));
7717             return this;
7718         },
7719
7720         /**
7721          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7722          * @param {String} top The top CSS property value
7723          * @return {Roo.Element} this
7724          */
7725         setTop : function(top){
7726             this.setStyle("top", this.addUnits(top));
7727             return this;
7728         },
7729
7730         /**
7731          * Sets the element's CSS right style.
7732          * @param {String} right The right CSS property value
7733          * @return {Roo.Element} this
7734          */
7735         setRight : function(right){
7736             this.setStyle("right", this.addUnits(right));
7737             return this;
7738         },
7739
7740         /**
7741          * Sets the element's CSS bottom style.
7742          * @param {String} bottom The bottom CSS property value
7743          * @return {Roo.Element} this
7744          */
7745         setBottom : function(bottom){
7746             this.setStyle("bottom", this.addUnits(bottom));
7747             return this;
7748         },
7749
7750         /**
7751          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7752          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7753          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7754          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7755          * @return {Roo.Element} this
7756          */
7757         setXY : function(pos, animate){
7758             if(!animate || !A){
7759                 D.setXY(this.dom, pos);
7760             }else{
7761                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7762             }
7763             return this;
7764         },
7765
7766         /**
7767          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7768          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7769          * @param {Number} x X value for new position (coordinates are page-based)
7770          * @param {Number} y Y value for new position (coordinates are page-based)
7771          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7772          * @return {Roo.Element} this
7773          */
7774         setLocation : function(x, y, animate){
7775             this.setXY([x, y], this.preanim(arguments, 2));
7776             return this;
7777         },
7778
7779         /**
7780          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7781          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7782          * @param {Number} x X value for new position (coordinates are page-based)
7783          * @param {Number} y Y value for new position (coordinates are page-based)
7784          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7785          * @return {Roo.Element} this
7786          */
7787         moveTo : function(x, y, animate){
7788             this.setXY([x, y], this.preanim(arguments, 2));
7789             return this;
7790         },
7791
7792         /**
7793          * Returns the region of the given element.
7794          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7795          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7796          */
7797         getRegion : function(){
7798             return D.getRegion(this.dom);
7799         },
7800
7801         /**
7802          * Returns the offset height of the element
7803          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7804          * @return {Number} The element's height
7805          */
7806         getHeight : function(contentHeight){
7807             var h = this.dom.offsetHeight || 0;
7808             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7809         },
7810
7811         /**
7812          * Returns the offset width of the element
7813          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7814          * @return {Number} The element's width
7815          */
7816         getWidth : function(contentWidth){
7817             var w = this.dom.offsetWidth || 0;
7818             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7819         },
7820
7821         /**
7822          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7823          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7824          * if a height has not been set using CSS.
7825          * @return {Number}
7826          */
7827         getComputedHeight : function(){
7828             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7829             if(!h){
7830                 h = parseInt(this.getStyle('height'), 10) || 0;
7831                 if(!this.isBorderBox()){
7832                     h += this.getFrameWidth('tb');
7833                 }
7834             }
7835             return h;
7836         },
7837
7838         /**
7839          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7840          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7841          * if a width has not been set using CSS.
7842          * @return {Number}
7843          */
7844         getComputedWidth : function(){
7845             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7846             if(!w){
7847                 w = parseInt(this.getStyle('width'), 10) || 0;
7848                 if(!this.isBorderBox()){
7849                     w += this.getFrameWidth('lr');
7850                 }
7851             }
7852             return w;
7853         },
7854
7855         /**
7856          * Returns the size of the element.
7857          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7858          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7859          */
7860         getSize : function(contentSize){
7861             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7862         },
7863
7864         /**
7865          * Returns the width and height of the viewport.
7866          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7867          */
7868         getViewSize : function(){
7869             var d = this.dom, doc = document, aw = 0, ah = 0;
7870             if(d == doc || d == doc.body){
7871                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7872             }else{
7873                 return {
7874                     width : d.clientWidth,
7875                     height: d.clientHeight
7876                 };
7877             }
7878         },
7879
7880         /**
7881          * Returns the value of the "value" attribute
7882          * @param {Boolean} asNumber true to parse the value as a number
7883          * @return {String/Number}
7884          */
7885         getValue : function(asNumber){
7886             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7887         },
7888
7889         // private
7890         adjustWidth : function(width){
7891             if(typeof width == "number"){
7892                 if(this.autoBoxAdjust && !this.isBorderBox()){
7893                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7894                 }
7895                 if(width < 0){
7896                     width = 0;
7897                 }
7898             }
7899             return width;
7900         },
7901
7902         // private
7903         adjustHeight : function(height){
7904             if(typeof height == "number"){
7905                if(this.autoBoxAdjust && !this.isBorderBox()){
7906                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7907                }
7908                if(height < 0){
7909                    height = 0;
7910                }
7911             }
7912             return height;
7913         },
7914
7915         /**
7916          * Set the width of the element
7917          * @param {Number} width The new width
7918          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7919          * @return {Roo.Element} this
7920          */
7921         setWidth : function(width, animate){
7922             width = this.adjustWidth(width);
7923             if(!animate || !A){
7924                 this.dom.style.width = this.addUnits(width);
7925             }else{
7926                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7927             }
7928             return this;
7929         },
7930
7931         /**
7932          * Set the height of the element
7933          * @param {Number} height The new height
7934          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7935          * @return {Roo.Element} this
7936          */
7937          setHeight : function(height, animate){
7938             height = this.adjustHeight(height);
7939             if(!animate || !A){
7940                 this.dom.style.height = this.addUnits(height);
7941             }else{
7942                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7943             }
7944             return this;
7945         },
7946
7947         /**
7948          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7949          * @param {Number} width The new width
7950          * @param {Number} height The new height
7951          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7952          * @return {Roo.Element} this
7953          */
7954          setSize : function(width, height, animate){
7955             if(typeof width == "object"){ // in case of object from getSize()
7956                 height = width.height; width = width.width;
7957             }
7958             width = this.adjustWidth(width); height = this.adjustHeight(height);
7959             if(!animate || !A){
7960                 this.dom.style.width = this.addUnits(width);
7961                 this.dom.style.height = this.addUnits(height);
7962             }else{
7963                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7964             }
7965             return this;
7966         },
7967
7968         /**
7969          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7970          * @param {Number} x X value for new position (coordinates are page-based)
7971          * @param {Number} y Y value for new position (coordinates are page-based)
7972          * @param {Number} width The new width
7973          * @param {Number} height The new height
7974          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7975          * @return {Roo.Element} this
7976          */
7977         setBounds : function(x, y, width, height, animate){
7978             if(!animate || !A){
7979                 this.setSize(width, height);
7980                 this.setLocation(x, y);
7981             }else{
7982                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7983                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7984                               this.preanim(arguments, 4), 'motion');
7985             }
7986             return this;
7987         },
7988
7989         /**
7990          * 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.
7991          * @param {Roo.lib.Region} region The region to fill
7992          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7993          * @return {Roo.Element} this
7994          */
7995         setRegion : function(region, animate){
7996             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7997             return this;
7998         },
7999
8000         /**
8001          * Appends an event handler
8002          *
8003          * @param {String}   eventName     The type of event to append
8004          * @param {Function} fn        The method the event invokes
8005          * @param {Object} scope       (optional) The scope (this object) of the fn
8006          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8007          */
8008         addListener : function(eventName, fn, scope, options){
8009             if (this.dom) {
8010                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8011             }
8012         },
8013
8014         /**
8015          * Removes an event handler from this element
8016          * @param {String} eventName the type of event to remove
8017          * @param {Function} fn the method the event invokes
8018          * @return {Roo.Element} this
8019          */
8020         removeListener : function(eventName, fn){
8021             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8022             return this;
8023         },
8024
8025         /**
8026          * Removes all previous added listeners from this element
8027          * @return {Roo.Element} this
8028          */
8029         removeAllListeners : function(){
8030             E.purgeElement(this.dom);
8031             return this;
8032         },
8033
8034         relayEvent : function(eventName, observable){
8035             this.on(eventName, function(e){
8036                 observable.fireEvent(eventName, e);
8037             });
8038         },
8039
8040         /**
8041          * Set the opacity of the element
8042          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8043          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8044          * @return {Roo.Element} this
8045          */
8046          setOpacity : function(opacity, animate){
8047             if(!animate || !A){
8048                 var s = this.dom.style;
8049                 if(Roo.isIE){
8050                     s.zoom = 1;
8051                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8052                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8053                 }else{
8054                     s.opacity = opacity;
8055                 }
8056             }else{
8057                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8058             }
8059             return this;
8060         },
8061
8062         /**
8063          * Gets the left X coordinate
8064          * @param {Boolean} local True to get the local css position instead of page coordinate
8065          * @return {Number}
8066          */
8067         getLeft : function(local){
8068             if(!local){
8069                 return this.getX();
8070             }else{
8071                 return parseInt(this.getStyle("left"), 10) || 0;
8072             }
8073         },
8074
8075         /**
8076          * Gets the right X coordinate of the element (element X position + element width)
8077          * @param {Boolean} local True to get the local css position instead of page coordinate
8078          * @return {Number}
8079          */
8080         getRight : function(local){
8081             if(!local){
8082                 return this.getX() + this.getWidth();
8083             }else{
8084                 return (this.getLeft(true) + this.getWidth()) || 0;
8085             }
8086         },
8087
8088         /**
8089          * Gets the top Y coordinate
8090          * @param {Boolean} local True to get the local css position instead of page coordinate
8091          * @return {Number}
8092          */
8093         getTop : function(local) {
8094             if(!local){
8095                 return this.getY();
8096             }else{
8097                 return parseInt(this.getStyle("top"), 10) || 0;
8098             }
8099         },
8100
8101         /**
8102          * Gets the bottom Y coordinate of the element (element Y position + element height)
8103          * @param {Boolean} local True to get the local css position instead of page coordinate
8104          * @return {Number}
8105          */
8106         getBottom : function(local){
8107             if(!local){
8108                 return this.getY() + this.getHeight();
8109             }else{
8110                 return (this.getTop(true) + this.getHeight()) || 0;
8111             }
8112         },
8113
8114         /**
8115         * Initializes positioning on this element. If a desired position is not passed, it will make the
8116         * the element positioned relative IF it is not already positioned.
8117         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8118         * @param {Number} zIndex (optional) The zIndex to apply
8119         * @param {Number} x (optional) Set the page X position
8120         * @param {Number} y (optional) Set the page Y position
8121         */
8122         position : function(pos, zIndex, x, y){
8123             if(!pos){
8124                if(this.getStyle('position') == 'static'){
8125                    this.setStyle('position', 'relative');
8126                }
8127             }else{
8128                 this.setStyle("position", pos);
8129             }
8130             if(zIndex){
8131                 this.setStyle("z-index", zIndex);
8132             }
8133             if(x !== undefined && y !== undefined){
8134                 this.setXY([x, y]);
8135             }else if(x !== undefined){
8136                 this.setX(x);
8137             }else if(y !== undefined){
8138                 this.setY(y);
8139             }
8140         },
8141
8142         /**
8143         * Clear positioning back to the default when the document was loaded
8144         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8145         * @return {Roo.Element} this
8146          */
8147         clearPositioning : function(value){
8148             value = value ||'';
8149             this.setStyle({
8150                 "left": value,
8151                 "right": value,
8152                 "top": value,
8153                 "bottom": value,
8154                 "z-index": "",
8155                 "position" : "static"
8156             });
8157             return this;
8158         },
8159
8160         /**
8161         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8162         * snapshot before performing an update and then restoring the element.
8163         * @return {Object}
8164         */
8165         getPositioning : function(){
8166             var l = this.getStyle("left");
8167             var t = this.getStyle("top");
8168             return {
8169                 "position" : this.getStyle("position"),
8170                 "left" : l,
8171                 "right" : l ? "" : this.getStyle("right"),
8172                 "top" : t,
8173                 "bottom" : t ? "" : this.getStyle("bottom"),
8174                 "z-index" : this.getStyle("z-index")
8175             };
8176         },
8177
8178         /**
8179          * Gets the width of the border(s) for the specified side(s)
8180          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8181          * passing lr would get the border (l)eft width + the border (r)ight width.
8182          * @return {Number} The width of the sides passed added together
8183          */
8184         getBorderWidth : function(side){
8185             return this.addStyles(side, El.borders);
8186         },
8187
8188         /**
8189          * Gets the width of the padding(s) for the specified side(s)
8190          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8191          * passing lr would get the padding (l)eft + the padding (r)ight.
8192          * @return {Number} The padding of the sides passed added together
8193          */
8194         getPadding : function(side){
8195             return this.addStyles(side, El.paddings);
8196         },
8197
8198         /**
8199         * Set positioning with an object returned by getPositioning().
8200         * @param {Object} posCfg
8201         * @return {Roo.Element} this
8202          */
8203         setPositioning : function(pc){
8204             this.applyStyles(pc);
8205             if(pc.right == "auto"){
8206                 this.dom.style.right = "";
8207             }
8208             if(pc.bottom == "auto"){
8209                 this.dom.style.bottom = "";
8210             }
8211             return this;
8212         },
8213
8214         // private
8215         fixDisplay : function(){
8216             if(this.getStyle("display") == "none"){
8217                 this.setStyle("visibility", "hidden");
8218                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8219                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8220                     this.setStyle("display", "block");
8221                 }
8222             }
8223         },
8224
8225         /**
8226          * Quick set left and top adding default units
8227          * @param {String} left The left CSS property value
8228          * @param {String} top The top CSS property value
8229          * @return {Roo.Element} this
8230          */
8231          setLeftTop : function(left, top){
8232             this.dom.style.left = this.addUnits(left);
8233             this.dom.style.top = this.addUnits(top);
8234             return this;
8235         },
8236
8237         /**
8238          * Move this element relative to its current position.
8239          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8240          * @param {Number} distance How far to move the element in pixels
8241          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8242          * @return {Roo.Element} this
8243          */
8244          move : function(direction, distance, animate){
8245             var xy = this.getXY();
8246             direction = direction.toLowerCase();
8247             switch(direction){
8248                 case "l":
8249                 case "left":
8250                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8251                     break;
8252                case "r":
8253                case "right":
8254                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8255                     break;
8256                case "t":
8257                case "top":
8258                case "up":
8259                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8260                     break;
8261                case "b":
8262                case "bottom":
8263                case "down":
8264                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8265                     break;
8266             }
8267             return this;
8268         },
8269
8270         /**
8271          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8272          * @return {Roo.Element} this
8273          */
8274         clip : function(){
8275             if(!this.isClipped){
8276                this.isClipped = true;
8277                this.originalClip = {
8278                    "o": this.getStyle("overflow"),
8279                    "x": this.getStyle("overflow-x"),
8280                    "y": this.getStyle("overflow-y")
8281                };
8282                this.setStyle("overflow", "hidden");
8283                this.setStyle("overflow-x", "hidden");
8284                this.setStyle("overflow-y", "hidden");
8285             }
8286             return this;
8287         },
8288
8289         /**
8290          *  Return clipping (overflow) to original clipping before clip() was called
8291          * @return {Roo.Element} this
8292          */
8293         unclip : function(){
8294             if(this.isClipped){
8295                 this.isClipped = false;
8296                 var o = this.originalClip;
8297                 if(o.o){this.setStyle("overflow", o.o);}
8298                 if(o.x){this.setStyle("overflow-x", o.x);}
8299                 if(o.y){this.setStyle("overflow-y", o.y);}
8300             }
8301             return this;
8302         },
8303
8304
8305         /**
8306          * Gets the x,y coordinates specified by the anchor position on the element.
8307          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8308          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8309          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8310          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8311          * @return {Array} [x, y] An array containing the element's x and y coordinates
8312          */
8313         getAnchorXY : function(anchor, local, s){
8314             //Passing a different size is useful for pre-calculating anchors,
8315             //especially for anchored animations that change the el size.
8316
8317             var w, h, vp = false;
8318             if(!s){
8319                 var d = this.dom;
8320                 if(d == document.body || d == document){
8321                     vp = true;
8322                     w = D.getViewWidth(); h = D.getViewHeight();
8323                 }else{
8324                     w = this.getWidth(); h = this.getHeight();
8325                 }
8326             }else{
8327                 w = s.width;  h = s.height;
8328             }
8329             var x = 0, y = 0, r = Math.round;
8330             switch((anchor || "tl").toLowerCase()){
8331                 case "c":
8332                     x = r(w*.5);
8333                     y = r(h*.5);
8334                 break;
8335                 case "t":
8336                     x = r(w*.5);
8337                     y = 0;
8338                 break;
8339                 case "l":
8340                     x = 0;
8341                     y = r(h*.5);
8342                 break;
8343                 case "r":
8344                     x = w;
8345                     y = r(h*.5);
8346                 break;
8347                 case "b":
8348                     x = r(w*.5);
8349                     y = h;
8350                 break;
8351                 case "tl":
8352                     x = 0;
8353                     y = 0;
8354                 break;
8355                 case "bl":
8356                     x = 0;
8357                     y = h;
8358                 break;
8359                 case "br":
8360                     x = w;
8361                     y = h;
8362                 break;
8363                 case "tr":
8364                     x = w;
8365                     y = 0;
8366                 break;
8367             }
8368             if(local === true){
8369                 return [x, y];
8370             }
8371             if(vp){
8372                 var sc = this.getScroll();
8373                 return [x + sc.left, y + sc.top];
8374             }
8375             //Add the element's offset xy
8376             var o = this.getXY();
8377             return [x+o[0], y+o[1]];
8378         },
8379
8380         /**
8381          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8382          * supported position values.
8383          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8384          * @param {String} position The position to align to.
8385          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8386          * @return {Array} [x, y]
8387          */
8388         getAlignToXY : function(el, p, o){
8389             el = Roo.get(el);
8390             var d = this.dom;
8391             if(!el.dom){
8392                 throw "Element.alignTo with an element that doesn't exist";
8393             }
8394             var c = false; //constrain to viewport
8395             var p1 = "", p2 = "";
8396             o = o || [0,0];
8397
8398             if(!p){
8399                 p = "tl-bl";
8400             }else if(p == "?"){
8401                 p = "tl-bl?";
8402             }else if(p.indexOf("-") == -1){
8403                 p = "tl-" + p;
8404             }
8405             p = p.toLowerCase();
8406             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8407             if(!m){
8408                throw "Element.alignTo with an invalid alignment " + p;
8409             }
8410             p1 = m[1]; p2 = m[2]; c = !!m[3];
8411
8412             //Subtract the aligned el's internal xy from the target's offset xy
8413             //plus custom offset to get the aligned el's new offset xy
8414             var a1 = this.getAnchorXY(p1, true);
8415             var a2 = el.getAnchorXY(p2, false);
8416             var x = a2[0] - a1[0] + o[0];
8417             var y = a2[1] - a1[1] + o[1];
8418             if(c){
8419                 //constrain the aligned el to viewport if necessary
8420                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8421                 // 5px of margin for ie
8422                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8423
8424                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8425                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8426                 //otherwise swap the aligned el to the opposite border of the target.
8427                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8428                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8429                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8430                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8431
8432                var doc = document;
8433                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8434                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8435
8436                if((x+w) > dw + scrollX){
8437                     x = swapX ? r.left-w : dw+scrollX-w;
8438                 }
8439                if(x < scrollX){
8440                    x = swapX ? r.right : scrollX;
8441                }
8442                if((y+h) > dh + scrollY){
8443                     y = swapY ? r.top-h : dh+scrollY-h;
8444                 }
8445                if (y < scrollY){
8446                    y = swapY ? r.bottom : scrollY;
8447                }
8448             }
8449             return [x,y];
8450         },
8451
8452         // private
8453         getConstrainToXY : function(){
8454             var os = {top:0, left:0, bottom:0, right: 0};
8455
8456             return function(el, local, offsets, proposedXY){
8457                 el = Roo.get(el);
8458                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8459
8460                 var vw, vh, vx = 0, vy = 0;
8461                 if(el.dom == document.body || el.dom == document){
8462                     vw = Roo.lib.Dom.getViewWidth();
8463                     vh = Roo.lib.Dom.getViewHeight();
8464                 }else{
8465                     vw = el.dom.clientWidth;
8466                     vh = el.dom.clientHeight;
8467                     if(!local){
8468                         var vxy = el.getXY();
8469                         vx = vxy[0];
8470                         vy = vxy[1];
8471                     }
8472                 }
8473
8474                 var s = el.getScroll();
8475
8476                 vx += offsets.left + s.left;
8477                 vy += offsets.top + s.top;
8478
8479                 vw -= offsets.right;
8480                 vh -= offsets.bottom;
8481
8482                 var vr = vx+vw;
8483                 var vb = vy+vh;
8484
8485                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8486                 var x = xy[0], y = xy[1];
8487                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8488
8489                 // only move it if it needs it
8490                 var moved = false;
8491
8492                 // first validate right/bottom
8493                 if((x + w) > vr){
8494                     x = vr - w;
8495                     moved = true;
8496                 }
8497                 if((y + h) > vb){
8498                     y = vb - h;
8499                     moved = true;
8500                 }
8501                 // then make sure top/left isn't negative
8502                 if(x < vx){
8503                     x = vx;
8504                     moved = true;
8505                 }
8506                 if(y < vy){
8507                     y = vy;
8508                     moved = true;
8509                 }
8510                 return moved ? [x, y] : false;
8511             };
8512         }(),
8513
8514         // private
8515         adjustForConstraints : function(xy, parent, offsets){
8516             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8517         },
8518
8519         /**
8520          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8521          * document it aligns it to the viewport.
8522          * The position parameter is optional, and can be specified in any one of the following formats:
8523          * <ul>
8524          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8525          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8526          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8527          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8528          *   <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
8529          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8530          * </ul>
8531          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8532          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8533          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8534          * that specified in order to enforce the viewport constraints.
8535          * Following are all of the supported anchor positions:
8536     <pre>
8537     Value  Description
8538     -----  -----------------------------
8539     tl     The top left corner (default)
8540     t      The center of the top edge
8541     tr     The top right corner
8542     l      The center of the left edge
8543     c      In the center of the element
8544     r      The center of the right edge
8545     bl     The bottom left corner
8546     b      The center of the bottom edge
8547     br     The bottom right corner
8548     </pre>
8549     Example Usage:
8550     <pre><code>
8551     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8552     el.alignTo("other-el");
8553
8554     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8555     el.alignTo("other-el", "tr?");
8556
8557     // align the bottom right corner of el with the center left edge of other-el
8558     el.alignTo("other-el", "br-l?");
8559
8560     // align the center of el with the bottom left corner of other-el and
8561     // adjust the x position by -6 pixels (and the y position by 0)
8562     el.alignTo("other-el", "c-bl", [-6, 0]);
8563     </code></pre>
8564          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8565          * @param {String} position The position to align to.
8566          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8567          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8568          * @return {Roo.Element} this
8569          */
8570         alignTo : function(element, position, offsets, animate){
8571             var xy = this.getAlignToXY(element, position, offsets);
8572             this.setXY(xy, this.preanim(arguments, 3));
8573             return this;
8574         },
8575
8576         /**
8577          * Anchors an element to another element and realigns it when the window is resized.
8578          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8579          * @param {String} position The position to align to.
8580          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8581          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8582          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8583          * is a number, it is used as the buffer delay (defaults to 50ms).
8584          * @param {Function} callback The function to call after the animation finishes
8585          * @return {Roo.Element} this
8586          */
8587         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8588             var action = function(){
8589                 this.alignTo(el, alignment, offsets, animate);
8590                 Roo.callback(callback, this);
8591             };
8592             Roo.EventManager.onWindowResize(action, this);
8593             var tm = typeof monitorScroll;
8594             if(tm != 'undefined'){
8595                 Roo.EventManager.on(window, 'scroll', action, this,
8596                     {buffer: tm == 'number' ? monitorScroll : 50});
8597             }
8598             action.call(this); // align immediately
8599             return this;
8600         },
8601         /**
8602          * Clears any opacity settings from this element. Required in some cases for IE.
8603          * @return {Roo.Element} this
8604          */
8605         clearOpacity : function(){
8606             if (window.ActiveXObject) {
8607                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8608                     this.dom.style.filter = "";
8609                 }
8610             } else {
8611                 this.dom.style.opacity = "";
8612                 this.dom.style["-moz-opacity"] = "";
8613                 this.dom.style["-khtml-opacity"] = "";
8614             }
8615             return this;
8616         },
8617
8618         /**
8619          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8620          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8621          * @return {Roo.Element} this
8622          */
8623         hide : function(animate){
8624             this.setVisible(false, this.preanim(arguments, 0));
8625             return this;
8626         },
8627
8628         /**
8629         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8630         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8631          * @return {Roo.Element} this
8632          */
8633         show : function(animate){
8634             this.setVisible(true, this.preanim(arguments, 0));
8635             return this;
8636         },
8637
8638         /**
8639          * @private Test if size has a unit, otherwise appends the default
8640          */
8641         addUnits : function(size){
8642             return Roo.Element.addUnits(size, this.defaultUnit);
8643         },
8644
8645         /**
8646          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8647          * @return {Roo.Element} this
8648          */
8649         beginMeasure : function(){
8650             var el = this.dom;
8651             if(el.offsetWidth || el.offsetHeight){
8652                 return this; // offsets work already
8653             }
8654             var changed = [];
8655             var p = this.dom, b = document.body; // start with this element
8656             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8657                 var pe = Roo.get(p);
8658                 if(pe.getStyle('display') == 'none'){
8659                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8660                     p.style.visibility = "hidden";
8661                     p.style.display = "block";
8662                 }
8663                 p = p.parentNode;
8664             }
8665             this._measureChanged = changed;
8666             return this;
8667
8668         },
8669
8670         /**
8671          * Restores displays to before beginMeasure was called
8672          * @return {Roo.Element} this
8673          */
8674         endMeasure : function(){
8675             var changed = this._measureChanged;
8676             if(changed){
8677                 for(var i = 0, len = changed.length; i < len; i++) {
8678                     var r = changed[i];
8679                     r.el.style.visibility = r.visibility;
8680                     r.el.style.display = "none";
8681                 }
8682                 this._measureChanged = null;
8683             }
8684             return this;
8685         },
8686
8687         /**
8688         * Update the innerHTML of this element, optionally searching for and processing scripts
8689         * @param {String} html The new HTML
8690         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8691         * @param {Function} callback For async script loading you can be noticed when the update completes
8692         * @return {Roo.Element} this
8693          */
8694         update : function(html, loadScripts, callback){
8695             if(typeof html == "undefined"){
8696                 html = "";
8697             }
8698             if(loadScripts !== true){
8699                 this.dom.innerHTML = html;
8700                 if(typeof callback == "function"){
8701                     callback();
8702                 }
8703                 return this;
8704             }
8705             var id = Roo.id();
8706             var dom = this.dom;
8707
8708             html += '<span id="' + id + '"></span>';
8709
8710             E.onAvailable(id, function(){
8711                 var hd = document.getElementsByTagName("head")[0];
8712                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8713                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8714                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8715
8716                 var match;
8717                 while(match = re.exec(html)){
8718                     var attrs = match[1];
8719                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8720                     if(srcMatch && srcMatch[2]){
8721                        var s = document.createElement("script");
8722                        s.src = srcMatch[2];
8723                        var typeMatch = attrs.match(typeRe);
8724                        if(typeMatch && typeMatch[2]){
8725                            s.type = typeMatch[2];
8726                        }
8727                        hd.appendChild(s);
8728                     }else if(match[2] && match[2].length > 0){
8729                         if(window.execScript) {
8730                            window.execScript(match[2]);
8731                         } else {
8732                             /**
8733                              * eval:var:id
8734                              * eval:var:dom
8735                              * eval:var:html
8736                              * 
8737                              */
8738                            window.eval(match[2]);
8739                         }
8740                     }
8741                 }
8742                 var el = document.getElementById(id);
8743                 if(el){el.parentNode.removeChild(el);}
8744                 if(typeof callback == "function"){
8745                     callback();
8746                 }
8747             });
8748             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8749             return this;
8750         },
8751
8752         /**
8753          * Direct access to the UpdateManager update() method (takes the same parameters).
8754          * @param {String/Function} url The url for this request or a function to call to get the url
8755          * @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}
8756          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8757          * @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.
8758          * @return {Roo.Element} this
8759          */
8760         load : function(){
8761             var um = this.getUpdateManager();
8762             um.update.apply(um, arguments);
8763             return this;
8764         },
8765
8766         /**
8767         * Gets this element's UpdateManager
8768         * @return {Roo.UpdateManager} The UpdateManager
8769         */
8770         getUpdateManager : function(){
8771             if(!this.updateManager){
8772                 this.updateManager = new Roo.UpdateManager(this);
8773             }
8774             return this.updateManager;
8775         },
8776
8777         /**
8778          * Disables text selection for this element (normalized across browsers)
8779          * @return {Roo.Element} this
8780          */
8781         unselectable : function(){
8782             this.dom.unselectable = "on";
8783             this.swallowEvent("selectstart", true);
8784             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8785             this.addClass("x-unselectable");
8786             return this;
8787         },
8788
8789         /**
8790         * Calculates the x, y to center this element on the screen
8791         * @return {Array} The x, y values [x, y]
8792         */
8793         getCenterXY : function(){
8794             return this.getAlignToXY(document, 'c-c');
8795         },
8796
8797         /**
8798         * Centers the Element in either the viewport, or another Element.
8799         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8800         */
8801         center : function(centerIn){
8802             this.alignTo(centerIn || document, 'c-c');
8803             return this;
8804         },
8805
8806         /**
8807          * Tests various css rules/browsers to determine if this element uses a border box
8808          * @return {Boolean}
8809          */
8810         isBorderBox : function(){
8811             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8812         },
8813
8814         /**
8815          * Return a box {x, y, width, height} that can be used to set another elements
8816          * size/location to match this element.
8817          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8818          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8819          * @return {Object} box An object in the format {x, y, width, height}
8820          */
8821         getBox : function(contentBox, local){
8822             var xy;
8823             if(!local){
8824                 xy = this.getXY();
8825             }else{
8826                 var left = parseInt(this.getStyle("left"), 10) || 0;
8827                 var top = parseInt(this.getStyle("top"), 10) || 0;
8828                 xy = [left, top];
8829             }
8830             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8831             if(!contentBox){
8832                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8833             }else{
8834                 var l = this.getBorderWidth("l")+this.getPadding("l");
8835                 var r = this.getBorderWidth("r")+this.getPadding("r");
8836                 var t = this.getBorderWidth("t")+this.getPadding("t");
8837                 var b = this.getBorderWidth("b")+this.getPadding("b");
8838                 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)};
8839             }
8840             bx.right = bx.x + bx.width;
8841             bx.bottom = bx.y + bx.height;
8842             return bx;
8843         },
8844
8845         /**
8846          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8847          for more information about the sides.
8848          * @param {String} sides
8849          * @return {Number}
8850          */
8851         getFrameWidth : function(sides, onlyContentBox){
8852             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8853         },
8854
8855         /**
8856          * 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.
8857          * @param {Object} box The box to fill {x, y, width, height}
8858          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8859          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8860          * @return {Roo.Element} this
8861          */
8862         setBox : function(box, adjust, animate){
8863             var w = box.width, h = box.height;
8864             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8865                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8866                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8867             }
8868             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8869             return this;
8870         },
8871
8872         /**
8873          * Forces the browser to repaint this element
8874          * @return {Roo.Element} this
8875          */
8876          repaint : function(){
8877             var dom = this.dom;
8878             this.addClass("x-repaint");
8879             setTimeout(function(){
8880                 Roo.get(dom).removeClass("x-repaint");
8881             }, 1);
8882             return this;
8883         },
8884
8885         /**
8886          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8887          * then it returns the calculated width of the sides (see getPadding)
8888          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8889          * @return {Object/Number}
8890          */
8891         getMargins : function(side){
8892             if(!side){
8893                 return {
8894                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8895                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8896                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8897                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8898                 };
8899             }else{
8900                 return this.addStyles(side, El.margins);
8901              }
8902         },
8903
8904         // private
8905         addStyles : function(sides, styles){
8906             var val = 0, v, w;
8907             for(var i = 0, len = sides.length; i < len; i++){
8908                 v = this.getStyle(styles[sides.charAt(i)]);
8909                 if(v){
8910                      w = parseInt(v, 10);
8911                      if(w){ val += w; }
8912                 }
8913             }
8914             return val;
8915         },
8916
8917         /**
8918          * Creates a proxy element of this element
8919          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8920          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8921          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8922          * @return {Roo.Element} The new proxy element
8923          */
8924         createProxy : function(config, renderTo, matchBox){
8925             if(renderTo){
8926                 renderTo = Roo.getDom(renderTo);
8927             }else{
8928                 renderTo = document.body;
8929             }
8930             config = typeof config == "object" ?
8931                 config : {tag : "div", cls: config};
8932             var proxy = Roo.DomHelper.append(renderTo, config, true);
8933             if(matchBox){
8934                proxy.setBox(this.getBox());
8935             }
8936             return proxy;
8937         },
8938
8939         /**
8940          * Puts a mask over this element to disable user interaction. Requires core.css.
8941          * This method can only be applied to elements which accept child nodes.
8942          * @param {String} msg (optional) A message to display in the mask
8943          * @param {String} msgCls (optional) A css class to apply to the msg element
8944          * @return {Element} The mask  element
8945          */
8946         mask : function(msg, msgCls)
8947         {
8948             if(this.getStyle("position") == "static"){
8949                 this.setStyle("position", "relative");
8950             }
8951             if(!this._mask){
8952                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8953             }
8954             this.addClass("x-masked");
8955             this._mask.setDisplayed(true);
8956             
8957             // we wander
8958             var z = 0;
8959             var dom = this.dom
8960             while (dom && dom.style) {
8961                 if (!isNaN(parseInt(dom.style.zIndex))) {
8962                     z = Math.max(z, parseInt(dom.style.zIndex));
8963                 }
8964                 dom = dom.parentNode;
8965             }
8966             // if we are masking the body - then it hides everything..
8967             if (this.dom == document.body) {
8968                 z = 1000000;
8969                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8970                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8971             }
8972            
8973             if(typeof msg == 'string'){
8974                 if(!this._maskMsg){
8975                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8976                 }
8977                 var mm = this._maskMsg;
8978                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8979                 mm.dom.firstChild.innerHTML = msg;
8980                 mm.setDisplayed(true);
8981                 mm.center(this);
8982                 mm.setStyle('z-index', z + 102);
8983             }
8984             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8985                 this._mask.setHeight(this.getHeight());
8986             }
8987             this._mask.setStyle('z-index', z + 100);
8988             
8989             return this._mask;
8990         },
8991
8992         /**
8993          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8994          * it is cached for reuse.
8995          */
8996         unmask : function(removeEl){
8997             if(this._mask){
8998                 if(removeEl === true){
8999                     this._mask.remove();
9000                     delete this._mask;
9001                     if(this._maskMsg){
9002                         this._maskMsg.remove();
9003                         delete this._maskMsg;
9004                     }
9005                 }else{
9006                     this._mask.setDisplayed(false);
9007                     if(this._maskMsg){
9008                         this._maskMsg.setDisplayed(false);
9009                     }
9010                 }
9011             }
9012             this.removeClass("x-masked");
9013         },
9014
9015         /**
9016          * Returns true if this element is masked
9017          * @return {Boolean}
9018          */
9019         isMasked : function(){
9020             return this._mask && this._mask.isVisible();
9021         },
9022
9023         /**
9024          * Creates an iframe shim for this element to keep selects and other windowed objects from
9025          * showing through.
9026          * @return {Roo.Element} The new shim element
9027          */
9028         createShim : function(){
9029             var el = document.createElement('iframe');
9030             el.frameBorder = 'no';
9031             el.className = 'roo-shim';
9032             if(Roo.isIE && Roo.isSecure){
9033                 el.src = Roo.SSL_SECURE_URL;
9034             }
9035             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9036             shim.autoBoxAdjust = false;
9037             return shim;
9038         },
9039
9040         /**
9041          * Removes this element from the DOM and deletes it from the cache
9042          */
9043         remove : function(){
9044             if(this.dom.parentNode){
9045                 this.dom.parentNode.removeChild(this.dom);
9046             }
9047             delete El.cache[this.dom.id];
9048         },
9049
9050         /**
9051          * Sets up event handlers to add and remove a css class when the mouse is over this element
9052          * @param {String} className
9053          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9054          * mouseout events for children elements
9055          * @return {Roo.Element} this
9056          */
9057         addClassOnOver : function(className, preventFlicker){
9058             this.on("mouseover", function(){
9059                 Roo.fly(this, '_internal').addClass(className);
9060             }, this.dom);
9061             var removeFn = function(e){
9062                 if(preventFlicker !== true || !e.within(this, true)){
9063                     Roo.fly(this, '_internal').removeClass(className);
9064                 }
9065             };
9066             this.on("mouseout", removeFn, this.dom);
9067             return this;
9068         },
9069
9070         /**
9071          * Sets up event handlers to add and remove a css class when this element has the focus
9072          * @param {String} className
9073          * @return {Roo.Element} this
9074          */
9075         addClassOnFocus : function(className){
9076             this.on("focus", function(){
9077                 Roo.fly(this, '_internal').addClass(className);
9078             }, this.dom);
9079             this.on("blur", function(){
9080                 Roo.fly(this, '_internal').removeClass(className);
9081             }, this.dom);
9082             return this;
9083         },
9084         /**
9085          * 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)
9086          * @param {String} className
9087          * @return {Roo.Element} this
9088          */
9089         addClassOnClick : function(className){
9090             var dom = this.dom;
9091             this.on("mousedown", function(){
9092                 Roo.fly(dom, '_internal').addClass(className);
9093                 var d = Roo.get(document);
9094                 var fn = function(){
9095                     Roo.fly(dom, '_internal').removeClass(className);
9096                     d.removeListener("mouseup", fn);
9097                 };
9098                 d.on("mouseup", fn);
9099             });
9100             return this;
9101         },
9102
9103         /**
9104          * Stops the specified event from bubbling and optionally prevents the default action
9105          * @param {String} eventName
9106          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9107          * @return {Roo.Element} this
9108          */
9109         swallowEvent : function(eventName, preventDefault){
9110             var fn = function(e){
9111                 e.stopPropagation();
9112                 if(preventDefault){
9113                     e.preventDefault();
9114                 }
9115             };
9116             if(eventName instanceof Array){
9117                 for(var i = 0, len = eventName.length; i < len; i++){
9118                      this.on(eventName[i], fn);
9119                 }
9120                 return this;
9121             }
9122             this.on(eventName, fn);
9123             return this;
9124         },
9125
9126         /**
9127          * @private
9128          */
9129       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9130
9131         /**
9132          * Sizes this element to its parent element's dimensions performing
9133          * neccessary box adjustments.
9134          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9135          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9136          * @return {Roo.Element} this
9137          */
9138         fitToParent : function(monitorResize, targetParent) {
9139           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9140           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9141           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9142             return;
9143           }
9144           var p = Roo.get(targetParent || this.dom.parentNode);
9145           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9146           if (monitorResize === true) {
9147             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9148             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9149           }
9150           return this;
9151         },
9152
9153         /**
9154          * Gets the next sibling, skipping text nodes
9155          * @return {HTMLElement} The next sibling or null
9156          */
9157         getNextSibling : function(){
9158             var n = this.dom.nextSibling;
9159             while(n && n.nodeType != 1){
9160                 n = n.nextSibling;
9161             }
9162             return n;
9163         },
9164
9165         /**
9166          * Gets the previous sibling, skipping text nodes
9167          * @return {HTMLElement} The previous sibling or null
9168          */
9169         getPrevSibling : function(){
9170             var n = this.dom.previousSibling;
9171             while(n && n.nodeType != 1){
9172                 n = n.previousSibling;
9173             }
9174             return n;
9175         },
9176
9177
9178         /**
9179          * Appends the passed element(s) to this element
9180          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9181          * @return {Roo.Element} this
9182          */
9183         appendChild: function(el){
9184             el = Roo.get(el);
9185             el.appendTo(this);
9186             return this;
9187         },
9188
9189         /**
9190          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9191          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9192          * automatically generated with the specified attributes.
9193          * @param {HTMLElement} insertBefore (optional) a child element of this element
9194          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9195          * @return {Roo.Element} The new child element
9196          */
9197         createChild: function(config, insertBefore, returnDom){
9198             config = config || {tag:'div'};
9199             if(insertBefore){
9200                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9201             }
9202             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9203         },
9204
9205         /**
9206          * Appends this element to the passed element
9207          * @param {String/HTMLElement/Element} el The new parent element
9208          * @return {Roo.Element} this
9209          */
9210         appendTo: function(el){
9211             el = Roo.getDom(el);
9212             el.appendChild(this.dom);
9213             return this;
9214         },
9215
9216         /**
9217          * Inserts this element before the passed element in the DOM
9218          * @param {String/HTMLElement/Element} el The element to insert before
9219          * @return {Roo.Element} this
9220          */
9221         insertBefore: function(el){
9222             el = Roo.getDom(el);
9223             el.parentNode.insertBefore(this.dom, el);
9224             return this;
9225         },
9226
9227         /**
9228          * Inserts this element after the passed element in the DOM
9229          * @param {String/HTMLElement/Element} el The element to insert after
9230          * @return {Roo.Element} this
9231          */
9232         insertAfter: function(el){
9233             el = Roo.getDom(el);
9234             el.parentNode.insertBefore(this.dom, el.nextSibling);
9235             return this;
9236         },
9237
9238         /**
9239          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9240          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9241          * @return {Roo.Element} The new child
9242          */
9243         insertFirst: function(el, returnDom){
9244             el = el || {};
9245             if(typeof el == 'object' && !el.nodeType){ // dh config
9246                 return this.createChild(el, this.dom.firstChild, returnDom);
9247             }else{
9248                 el = Roo.getDom(el);
9249                 this.dom.insertBefore(el, this.dom.firstChild);
9250                 return !returnDom ? Roo.get(el) : el;
9251             }
9252         },
9253
9254         /**
9255          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9256          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9257          * @param {String} where (optional) 'before' or 'after' defaults to before
9258          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9259          * @return {Roo.Element} the inserted Element
9260          */
9261         insertSibling: function(el, where, returnDom){
9262             where = where ? where.toLowerCase() : 'before';
9263             el = el || {};
9264             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9265
9266             if(typeof el == 'object' && !el.nodeType){ // dh config
9267                 if(where == 'after' && !this.dom.nextSibling){
9268                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9269                 }else{
9270                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9271                 }
9272
9273             }else{
9274                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9275                             where == 'before' ? this.dom : this.dom.nextSibling);
9276                 if(!returnDom){
9277                     rt = Roo.get(rt);
9278                 }
9279             }
9280             return rt;
9281         },
9282
9283         /**
9284          * Creates and wraps this element with another element
9285          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9286          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9287          * @return {HTMLElement/Element} The newly created wrapper element
9288          */
9289         wrap: function(config, returnDom){
9290             if(!config){
9291                 config = {tag: "div"};
9292             }
9293             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9294             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9295             return newEl;
9296         },
9297
9298         /**
9299          * Replaces the passed element with this element
9300          * @param {String/HTMLElement/Element} el The element to replace
9301          * @return {Roo.Element} this
9302          */
9303         replace: function(el){
9304             el = Roo.get(el);
9305             this.insertBefore(el);
9306             el.remove();
9307             return this;
9308         },
9309
9310         /**
9311          * Inserts an html fragment into this element
9312          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9313          * @param {String} html The HTML fragment
9314          * @param {Boolean} returnEl True to return an Roo.Element
9315          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9316          */
9317         insertHtml : function(where, html, returnEl){
9318             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9319             return returnEl ? Roo.get(el) : el;
9320         },
9321
9322         /**
9323          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9324          * @param {Object} o The object with the attributes
9325          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9326          * @return {Roo.Element} this
9327          */
9328         set : function(o, useSet){
9329             var el = this.dom;
9330             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9331             for(var attr in o){
9332                 if(attr == "style" || typeof o[attr] == "function") continue;
9333                 if(attr=="cls"){
9334                     el.className = o["cls"];
9335                 }else{
9336                     if(useSet) el.setAttribute(attr, o[attr]);
9337                     else el[attr] = o[attr];
9338                 }
9339             }
9340             if(o.style){
9341                 Roo.DomHelper.applyStyles(el, o.style);
9342             }
9343             return this;
9344         },
9345
9346         /**
9347          * Convenience method for constructing a KeyMap
9348          * @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:
9349          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9350          * @param {Function} fn The function to call
9351          * @param {Object} scope (optional) The scope of the function
9352          * @return {Roo.KeyMap} The KeyMap created
9353          */
9354         addKeyListener : function(key, fn, scope){
9355             var config;
9356             if(typeof key != "object" || key instanceof Array){
9357                 config = {
9358                     key: key,
9359                     fn: fn,
9360                     scope: scope
9361                 };
9362             }else{
9363                 config = {
9364                     key : key.key,
9365                     shift : key.shift,
9366                     ctrl : key.ctrl,
9367                     alt : key.alt,
9368                     fn: fn,
9369                     scope: scope
9370                 };
9371             }
9372             return new Roo.KeyMap(this, config);
9373         },
9374
9375         /**
9376          * Creates a KeyMap for this element
9377          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9378          * @return {Roo.KeyMap} The KeyMap created
9379          */
9380         addKeyMap : function(config){
9381             return new Roo.KeyMap(this, config);
9382         },
9383
9384         /**
9385          * Returns true if this element is scrollable.
9386          * @return {Boolean}
9387          */
9388          isScrollable : function(){
9389             var dom = this.dom;
9390             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9391         },
9392
9393         /**
9394          * 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().
9395          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9396          * @param {Number} value The new scroll value
9397          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9398          * @return {Element} this
9399          */
9400
9401         scrollTo : function(side, value, animate){
9402             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9403             if(!animate || !A){
9404                 this.dom[prop] = value;
9405             }else{
9406                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9407                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9408             }
9409             return this;
9410         },
9411
9412         /**
9413          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9414          * within this element's scrollable range.
9415          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9416          * @param {Number} distance How far to scroll the element in pixels
9417          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9418          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9419          * was scrolled as far as it could go.
9420          */
9421          scroll : function(direction, distance, animate){
9422              if(!this.isScrollable()){
9423                  return;
9424              }
9425              var el = this.dom;
9426              var l = el.scrollLeft, t = el.scrollTop;
9427              var w = el.scrollWidth, h = el.scrollHeight;
9428              var cw = el.clientWidth, ch = el.clientHeight;
9429              direction = direction.toLowerCase();
9430              var scrolled = false;
9431              var a = this.preanim(arguments, 2);
9432              switch(direction){
9433                  case "l":
9434                  case "left":
9435                      if(w - l > cw){
9436                          var v = Math.min(l + distance, w-cw);
9437                          this.scrollTo("left", v, a);
9438                          scrolled = true;
9439                      }
9440                      break;
9441                 case "r":
9442                 case "right":
9443                      if(l > 0){
9444                          var v = Math.max(l - distance, 0);
9445                          this.scrollTo("left", v, a);
9446                          scrolled = true;
9447                      }
9448                      break;
9449                 case "t":
9450                 case "top":
9451                 case "up":
9452                      if(t > 0){
9453                          var v = Math.max(t - distance, 0);
9454                          this.scrollTo("top", v, a);
9455                          scrolled = true;
9456                      }
9457                      break;
9458                 case "b":
9459                 case "bottom":
9460                 case "down":
9461                      if(h - t > ch){
9462                          var v = Math.min(t + distance, h-ch);
9463                          this.scrollTo("top", v, a);
9464                          scrolled = true;
9465                      }
9466                      break;
9467              }
9468              return scrolled;
9469         },
9470
9471         /**
9472          * Translates the passed page coordinates into left/top css values for this element
9473          * @param {Number/Array} x The page x or an array containing [x, y]
9474          * @param {Number} y The page y
9475          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9476          */
9477         translatePoints : function(x, y){
9478             if(typeof x == 'object' || x instanceof Array){
9479                 y = x[1]; x = x[0];
9480             }
9481             var p = this.getStyle('position');
9482             var o = this.getXY();
9483
9484             var l = parseInt(this.getStyle('left'), 10);
9485             var t = parseInt(this.getStyle('top'), 10);
9486
9487             if(isNaN(l)){
9488                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9489             }
9490             if(isNaN(t)){
9491                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9492             }
9493
9494             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9495         },
9496
9497         /**
9498          * Returns the current scroll position of the element.
9499          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9500          */
9501         getScroll : function(){
9502             var d = this.dom, doc = document;
9503             if(d == doc || d == doc.body){
9504                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9505                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9506                 return {left: l, top: t};
9507             }else{
9508                 return {left: d.scrollLeft, top: d.scrollTop};
9509             }
9510         },
9511
9512         /**
9513          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9514          * are convert to standard 6 digit hex color.
9515          * @param {String} attr The css attribute
9516          * @param {String} defaultValue The default value to use when a valid color isn't found
9517          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9518          * YUI color anims.
9519          */
9520         getColor : function(attr, defaultValue, prefix){
9521             var v = this.getStyle(attr);
9522             if(!v || v == "transparent" || v == "inherit") {
9523                 return defaultValue;
9524             }
9525             var color = typeof prefix == "undefined" ? "#" : prefix;
9526             if(v.substr(0, 4) == "rgb("){
9527                 var rvs = v.slice(4, v.length -1).split(",");
9528                 for(var i = 0; i < 3; i++){
9529                     var h = parseInt(rvs[i]).toString(16);
9530                     if(h < 16){
9531                         h = "0" + h;
9532                     }
9533                     color += h;
9534                 }
9535             } else {
9536                 if(v.substr(0, 1) == "#"){
9537                     if(v.length == 4) {
9538                         for(var i = 1; i < 4; i++){
9539                             var c = v.charAt(i);
9540                             color +=  c + c;
9541                         }
9542                     }else if(v.length == 7){
9543                         color += v.substr(1);
9544                     }
9545                 }
9546             }
9547             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9548         },
9549
9550         /**
9551          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9552          * gradient background, rounded corners and a 4-way shadow.
9553          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9554          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9555          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9556          * @return {Roo.Element} this
9557          */
9558         boxWrap : function(cls){
9559             cls = cls || 'x-box';
9560             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9561             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9562             return el;
9563         },
9564
9565         /**
9566          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9567          * @param {String} namespace The namespace in which to look for the attribute
9568          * @param {String} name The attribute name
9569          * @return {String} The attribute value
9570          */
9571         getAttributeNS : Roo.isIE ? function(ns, name){
9572             var d = this.dom;
9573             var type = typeof d[ns+":"+name];
9574             if(type != 'undefined' && type != 'unknown'){
9575                 return d[ns+":"+name];
9576             }
9577             return d[name];
9578         } : function(ns, name){
9579             var d = this.dom;
9580             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9581         },
9582         
9583         
9584         /**
9585          * Sets or Returns the value the dom attribute value
9586          * @param {String} name The attribute name
9587          * @param {String} value (optional) The value to set the attribute to
9588          * @return {String} The attribute value
9589          */
9590         attr : function(name){
9591             if (arguments.length > 1) {
9592                 this.dom.setAttribute(name, arguments[1]);
9593                 return arguments[1];
9594             }
9595             if (!this.dom.hasAttribute(name)) {
9596                 return undefined;
9597             }
9598             return this.dom.getAttribute(name);
9599         }
9600         
9601         
9602         
9603     };
9604
9605     var ep = El.prototype;
9606
9607     /**
9608      * Appends an event handler (Shorthand for addListener)
9609      * @param {String}   eventName     The type of event to append
9610      * @param {Function} fn        The method the event invokes
9611      * @param {Object} scope       (optional) The scope (this object) of the fn
9612      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9613      * @method
9614      */
9615     ep.on = ep.addListener;
9616         // backwards compat
9617     ep.mon = ep.addListener;
9618
9619     /**
9620      * Removes an event handler from this element (shorthand for removeListener)
9621      * @param {String} eventName the type of event to remove
9622      * @param {Function} fn the method the event invokes
9623      * @return {Roo.Element} this
9624      * @method
9625      */
9626     ep.un = ep.removeListener;
9627
9628     /**
9629      * true to automatically adjust width and height settings for box-model issues (default to true)
9630      */
9631     ep.autoBoxAdjust = true;
9632
9633     // private
9634     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9635
9636     // private
9637     El.addUnits = function(v, defaultUnit){
9638         if(v === "" || v == "auto"){
9639             return v;
9640         }
9641         if(v === undefined){
9642             return '';
9643         }
9644         if(typeof v == "number" || !El.unitPattern.test(v)){
9645             return v + (defaultUnit || 'px');
9646         }
9647         return v;
9648     };
9649
9650     // special markup used throughout Roo when box wrapping elements
9651     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>';
9652     /**
9653      * Visibility mode constant - Use visibility to hide element
9654      * @static
9655      * @type Number
9656      */
9657     El.VISIBILITY = 1;
9658     /**
9659      * Visibility mode constant - Use display to hide element
9660      * @static
9661      * @type Number
9662      */
9663     El.DISPLAY = 2;
9664
9665     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9666     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9667     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9668
9669
9670
9671     /**
9672      * @private
9673      */
9674     El.cache = {};
9675
9676     var docEl;
9677
9678     /**
9679      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9680      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9681      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9682      * @return {Element} The Element object
9683      * @static
9684      */
9685     El.get = function(el){
9686         var ex, elm, id;
9687         if(!el){ return null; }
9688         if(typeof el == "string"){ // element id
9689             if(!(elm = document.getElementById(el))){
9690                 return null;
9691             }
9692             if(ex = El.cache[el]){
9693                 ex.dom = elm;
9694             }else{
9695                 ex = El.cache[el] = new El(elm);
9696             }
9697             return ex;
9698         }else if(el.tagName){ // dom element
9699             if(!(id = el.id)){
9700                 id = Roo.id(el);
9701             }
9702             if(ex = El.cache[id]){
9703                 ex.dom = el;
9704             }else{
9705                 ex = El.cache[id] = new El(el);
9706             }
9707             return ex;
9708         }else if(el instanceof El){
9709             if(el != docEl){
9710                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9711                                                               // catch case where it hasn't been appended
9712                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9713             }
9714             return el;
9715         }else if(el.isComposite){
9716             return el;
9717         }else if(el instanceof Array){
9718             return El.select(el);
9719         }else if(el == document){
9720             // create a bogus element object representing the document object
9721             if(!docEl){
9722                 var f = function(){};
9723                 f.prototype = El.prototype;
9724                 docEl = new f();
9725                 docEl.dom = document;
9726             }
9727             return docEl;
9728         }
9729         return null;
9730     };
9731
9732     // private
9733     El.uncache = function(el){
9734         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9735             if(a[i]){
9736                 delete El.cache[a[i].id || a[i]];
9737             }
9738         }
9739     };
9740
9741     // private
9742     // Garbage collection - uncache elements/purge listeners on orphaned elements
9743     // so we don't hold a reference and cause the browser to retain them
9744     El.garbageCollect = function(){
9745         if(!Roo.enableGarbageCollector){
9746             clearInterval(El.collectorThread);
9747             return;
9748         }
9749         for(var eid in El.cache){
9750             var el = El.cache[eid], d = el.dom;
9751             // -------------------------------------------------------
9752             // Determining what is garbage:
9753             // -------------------------------------------------------
9754             // !d
9755             // dom node is null, definitely garbage
9756             // -------------------------------------------------------
9757             // !d.parentNode
9758             // no parentNode == direct orphan, definitely garbage
9759             // -------------------------------------------------------
9760             // !d.offsetParent && !document.getElementById(eid)
9761             // display none elements have no offsetParent so we will
9762             // also try to look it up by it's id. However, check
9763             // offsetParent first so we don't do unneeded lookups.
9764             // This enables collection of elements that are not orphans
9765             // directly, but somewhere up the line they have an orphan
9766             // parent.
9767             // -------------------------------------------------------
9768             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9769                 delete El.cache[eid];
9770                 if(d && Roo.enableListenerCollection){
9771                     E.purgeElement(d);
9772                 }
9773             }
9774         }
9775     }
9776     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9777
9778
9779     // dom is optional
9780     El.Flyweight = function(dom){
9781         this.dom = dom;
9782     };
9783     El.Flyweight.prototype = El.prototype;
9784
9785     El._flyweights = {};
9786     /**
9787      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9788      * the dom node can be overwritten by other code.
9789      * @param {String/HTMLElement} el The dom node or id
9790      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9791      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9792      * @static
9793      * @return {Element} The shared Element object
9794      */
9795     El.fly = function(el, named){
9796         named = named || '_global';
9797         el = Roo.getDom(el);
9798         if(!el){
9799             return null;
9800         }
9801         if(!El._flyweights[named]){
9802             El._flyweights[named] = new El.Flyweight();
9803         }
9804         El._flyweights[named].dom = el;
9805         return El._flyweights[named];
9806     };
9807
9808     /**
9809      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9810      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9811      * Shorthand of {@link Roo.Element#get}
9812      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9813      * @return {Element} The Element object
9814      * @member Roo
9815      * @method get
9816      */
9817     Roo.get = El.get;
9818     /**
9819      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9820      * the dom node can be overwritten by other code.
9821      * Shorthand of {@link Roo.Element#fly}
9822      * @param {String/HTMLElement} el The dom node or id
9823      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9824      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9825      * @static
9826      * @return {Element} The shared Element object
9827      * @member Roo
9828      * @method fly
9829      */
9830     Roo.fly = El.fly;
9831
9832     // speedy lookup for elements never to box adjust
9833     var noBoxAdjust = Roo.isStrict ? {
9834         select:1
9835     } : {
9836         input:1, select:1, textarea:1
9837     };
9838     if(Roo.isIE || Roo.isGecko){
9839         noBoxAdjust['button'] = 1;
9840     }
9841
9842
9843     Roo.EventManager.on(window, 'unload', function(){
9844         delete El.cache;
9845         delete El._flyweights;
9846     });
9847 })();
9848
9849
9850
9851
9852 if(Roo.DomQuery){
9853     Roo.Element.selectorFunction = Roo.DomQuery.select;
9854 }
9855
9856 Roo.Element.select = function(selector, unique, root){
9857     var els;
9858     if(typeof selector == "string"){
9859         els = Roo.Element.selectorFunction(selector, root);
9860     }else if(selector.length !== undefined){
9861         els = selector;
9862     }else{
9863         throw "Invalid selector";
9864     }
9865     if(unique === true){
9866         return new Roo.CompositeElement(els);
9867     }else{
9868         return new Roo.CompositeElementLite(els);
9869     }
9870 };
9871 /**
9872  * Selects elements based on the passed CSS selector to enable working on them as 1.
9873  * @param {String/Array} selector The CSS selector or an array of elements
9874  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9875  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9876  * @return {CompositeElementLite/CompositeElement}
9877  * @member Roo
9878  * @method select
9879  */
9880 Roo.select = Roo.Element.select;
9881
9882
9883
9884
9885
9886
9887
9888
9889
9890
9891
9892
9893
9894
9895 /*
9896  * Based on:
9897  * Ext JS Library 1.1.1
9898  * Copyright(c) 2006-2007, Ext JS, LLC.
9899  *
9900  * Originally Released Under LGPL - original licence link has changed is not relivant.
9901  *
9902  * Fork - LGPL
9903  * <script type="text/javascript">
9904  */
9905
9906
9907
9908 //Notifies Element that fx methods are available
9909 Roo.enableFx = true;
9910
9911 /**
9912  * @class Roo.Fx
9913  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9914  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9915  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9916  * Element effects to work.</p><br/>
9917  *
9918  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9919  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9920  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9921  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9922  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9923  * expected results and should be done with care.</p><br/>
9924  *
9925  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9926  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9927 <pre>
9928 Value  Description
9929 -----  -----------------------------
9930 tl     The top left corner
9931 t      The center of the top edge
9932 tr     The top right corner
9933 l      The center of the left edge
9934 r      The center of the right edge
9935 bl     The bottom left corner
9936 b      The center of the bottom edge
9937 br     The bottom right corner
9938 </pre>
9939  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9940  * below are common options that can be passed to any Fx method.</b>
9941  * @cfg {Function} callback A function called when the effect is finished
9942  * @cfg {Object} scope The scope of the effect function
9943  * @cfg {String} easing A valid Easing value for the effect
9944  * @cfg {String} afterCls A css class to apply after the effect
9945  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9946  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9947  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9948  * effects that end with the element being visually hidden, ignored otherwise)
9949  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9950  * a function which returns such a specification that will be applied to the Element after the effect finishes
9951  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9952  * @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
9953  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9954  */
9955 Roo.Fx = {
9956         /**
9957          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9958          * origin for the slide effect.  This function automatically handles wrapping the element with
9959          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9960          * Usage:
9961          *<pre><code>
9962 // default: slide the element in from the top
9963 el.slideIn();
9964
9965 // custom: slide the element in from the right with a 2-second duration
9966 el.slideIn('r', { duration: 2 });
9967
9968 // common config options shown with default values
9969 el.slideIn('t', {
9970     easing: 'easeOut',
9971     duration: .5
9972 });
9973 </code></pre>
9974          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9975          * @param {Object} options (optional) Object literal with any of the Fx config options
9976          * @return {Roo.Element} The Element
9977          */
9978     slideIn : function(anchor, o){
9979         var el = this.getFxEl();
9980         o = o || {};
9981
9982         el.queueFx(o, function(){
9983
9984             anchor = anchor || "t";
9985
9986             // fix display to visibility
9987             this.fixDisplay();
9988
9989             // restore values after effect
9990             var r = this.getFxRestore();
9991             var b = this.getBox();
9992             // fixed size for slide
9993             this.setSize(b);
9994
9995             // wrap if needed
9996             var wrap = this.fxWrap(r.pos, o, "hidden");
9997
9998             var st = this.dom.style;
9999             st.visibility = "visible";
10000             st.position = "absolute";
10001
10002             // clear out temp styles after slide and unwrap
10003             var after = function(){
10004                 el.fxUnwrap(wrap, r.pos, o);
10005                 st.width = r.width;
10006                 st.height = r.height;
10007                 el.afterFx(o);
10008             };
10009             // time to calc the positions
10010             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10011
10012             switch(anchor.toLowerCase()){
10013                 case "t":
10014                     wrap.setSize(b.width, 0);
10015                     st.left = st.bottom = "0";
10016                     a = {height: bh};
10017                 break;
10018                 case "l":
10019                     wrap.setSize(0, b.height);
10020                     st.right = st.top = "0";
10021                     a = {width: bw};
10022                 break;
10023                 case "r":
10024                     wrap.setSize(0, b.height);
10025                     wrap.setX(b.right);
10026                     st.left = st.top = "0";
10027                     a = {width: bw, points: pt};
10028                 break;
10029                 case "b":
10030                     wrap.setSize(b.width, 0);
10031                     wrap.setY(b.bottom);
10032                     st.left = st.top = "0";
10033                     a = {height: bh, points: pt};
10034                 break;
10035                 case "tl":
10036                     wrap.setSize(0, 0);
10037                     st.right = st.bottom = "0";
10038                     a = {width: bw, height: bh};
10039                 break;
10040                 case "bl":
10041                     wrap.setSize(0, 0);
10042                     wrap.setY(b.y+b.height);
10043                     st.right = st.top = "0";
10044                     a = {width: bw, height: bh, points: pt};
10045                 break;
10046                 case "br":
10047                     wrap.setSize(0, 0);
10048                     wrap.setXY([b.right, b.bottom]);
10049                     st.left = st.top = "0";
10050                     a = {width: bw, height: bh, points: pt};
10051                 break;
10052                 case "tr":
10053                     wrap.setSize(0, 0);
10054                     wrap.setX(b.x+b.width);
10055                     st.left = st.bottom = "0";
10056                     a = {width: bw, height: bh, points: pt};
10057                 break;
10058             }
10059             this.dom.style.visibility = "visible";
10060             wrap.show();
10061
10062             arguments.callee.anim = wrap.fxanim(a,
10063                 o,
10064                 'motion',
10065                 .5,
10066                 'easeOut', after);
10067         });
10068         return this;
10069     },
10070     
10071         /**
10072          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10073          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10074          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10075          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10076          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10077          * Usage:
10078          *<pre><code>
10079 // default: slide the element out to the top
10080 el.slideOut();
10081
10082 // custom: slide the element out to the right with a 2-second duration
10083 el.slideOut('r', { duration: 2 });
10084
10085 // common config options shown with default values
10086 el.slideOut('t', {
10087     easing: 'easeOut',
10088     duration: .5,
10089     remove: false,
10090     useDisplay: false
10091 });
10092 </code></pre>
10093          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10094          * @param {Object} options (optional) Object literal with any of the Fx config options
10095          * @return {Roo.Element} The Element
10096          */
10097     slideOut : function(anchor, o){
10098         var el = this.getFxEl();
10099         o = o || {};
10100
10101         el.queueFx(o, function(){
10102
10103             anchor = anchor || "t";
10104
10105             // restore values after effect
10106             var r = this.getFxRestore();
10107             
10108             var b = this.getBox();
10109             // fixed size for slide
10110             this.setSize(b);
10111
10112             // wrap if needed
10113             var wrap = this.fxWrap(r.pos, o, "visible");
10114
10115             var st = this.dom.style;
10116             st.visibility = "visible";
10117             st.position = "absolute";
10118
10119             wrap.setSize(b);
10120
10121             var after = function(){
10122                 if(o.useDisplay){
10123                     el.setDisplayed(false);
10124                 }else{
10125                     el.hide();
10126                 }
10127
10128                 el.fxUnwrap(wrap, r.pos, o);
10129
10130                 st.width = r.width;
10131                 st.height = r.height;
10132
10133                 el.afterFx(o);
10134             };
10135
10136             var a, zero = {to: 0};
10137             switch(anchor.toLowerCase()){
10138                 case "t":
10139                     st.left = st.bottom = "0";
10140                     a = {height: zero};
10141                 break;
10142                 case "l":
10143                     st.right = st.top = "0";
10144                     a = {width: zero};
10145                 break;
10146                 case "r":
10147                     st.left = st.top = "0";
10148                     a = {width: zero, points: {to:[b.right, b.y]}};
10149                 break;
10150                 case "b":
10151                     st.left = st.top = "0";
10152                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10153                 break;
10154                 case "tl":
10155                     st.right = st.bottom = "0";
10156                     a = {width: zero, height: zero};
10157                 break;
10158                 case "bl":
10159                     st.right = st.top = "0";
10160                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10161                 break;
10162                 case "br":
10163                     st.left = st.top = "0";
10164                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10165                 break;
10166                 case "tr":
10167                     st.left = st.bottom = "0";
10168                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10169                 break;
10170             }
10171
10172             arguments.callee.anim = wrap.fxanim(a,
10173                 o,
10174                 'motion',
10175                 .5,
10176                 "easeOut", after);
10177         });
10178         return this;
10179     },
10180
10181         /**
10182          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10183          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10184          * The element must be removed from the DOM using the 'remove' config option if desired.
10185          * Usage:
10186          *<pre><code>
10187 // default
10188 el.puff();
10189
10190 // common config options shown with default values
10191 el.puff({
10192     easing: 'easeOut',
10193     duration: .5,
10194     remove: false,
10195     useDisplay: false
10196 });
10197 </code></pre>
10198          * @param {Object} options (optional) Object literal with any of the Fx config options
10199          * @return {Roo.Element} The Element
10200          */
10201     puff : function(o){
10202         var el = this.getFxEl();
10203         o = o || {};
10204
10205         el.queueFx(o, function(){
10206             this.clearOpacity();
10207             this.show();
10208
10209             // restore values after effect
10210             var r = this.getFxRestore();
10211             var st = this.dom.style;
10212
10213             var after = function(){
10214                 if(o.useDisplay){
10215                     el.setDisplayed(false);
10216                 }else{
10217                     el.hide();
10218                 }
10219
10220                 el.clearOpacity();
10221
10222                 el.setPositioning(r.pos);
10223                 st.width = r.width;
10224                 st.height = r.height;
10225                 st.fontSize = '';
10226                 el.afterFx(o);
10227             };
10228
10229             var width = this.getWidth();
10230             var height = this.getHeight();
10231
10232             arguments.callee.anim = this.fxanim({
10233                     width : {to: this.adjustWidth(width * 2)},
10234                     height : {to: this.adjustHeight(height * 2)},
10235                     points : {by: [-(width * .5), -(height * .5)]},
10236                     opacity : {to: 0},
10237                     fontSize: {to:200, unit: "%"}
10238                 },
10239                 o,
10240                 'motion',
10241                 .5,
10242                 "easeOut", after);
10243         });
10244         return this;
10245     },
10246
10247         /**
10248          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10249          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10250          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10251          * Usage:
10252          *<pre><code>
10253 // default
10254 el.switchOff();
10255
10256 // all config options shown with default values
10257 el.switchOff({
10258     easing: 'easeIn',
10259     duration: .3,
10260     remove: false,
10261     useDisplay: false
10262 });
10263 </code></pre>
10264          * @param {Object} options (optional) Object literal with any of the Fx config options
10265          * @return {Roo.Element} The Element
10266          */
10267     switchOff : function(o){
10268         var el = this.getFxEl();
10269         o = o || {};
10270
10271         el.queueFx(o, function(){
10272             this.clearOpacity();
10273             this.clip();
10274
10275             // restore values after effect
10276             var r = this.getFxRestore();
10277             var st = this.dom.style;
10278
10279             var after = function(){
10280                 if(o.useDisplay){
10281                     el.setDisplayed(false);
10282                 }else{
10283                     el.hide();
10284                 }
10285
10286                 el.clearOpacity();
10287                 el.setPositioning(r.pos);
10288                 st.width = r.width;
10289                 st.height = r.height;
10290
10291                 el.afterFx(o);
10292             };
10293
10294             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10295                 this.clearOpacity();
10296                 (function(){
10297                     this.fxanim({
10298                         height:{to:1},
10299                         points:{by:[0, this.getHeight() * .5]}
10300                     }, o, 'motion', 0.3, 'easeIn', after);
10301                 }).defer(100, this);
10302             });
10303         });
10304         return this;
10305     },
10306
10307     /**
10308      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10309      * changed using the "attr" config option) and then fading back to the original color. If no original
10310      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10311      * Usage:
10312 <pre><code>
10313 // default: highlight background to yellow
10314 el.highlight();
10315
10316 // custom: highlight foreground text to blue for 2 seconds
10317 el.highlight("0000ff", { attr: 'color', duration: 2 });
10318
10319 // common config options shown with default values
10320 el.highlight("ffff9c", {
10321     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10322     endColor: (current color) or "ffffff",
10323     easing: 'easeIn',
10324     duration: 1
10325 });
10326 </code></pre>
10327      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10328      * @param {Object} options (optional) Object literal with any of the Fx config options
10329      * @return {Roo.Element} The Element
10330      */ 
10331     highlight : function(color, o){
10332         var el = this.getFxEl();
10333         o = o || {};
10334
10335         el.queueFx(o, function(){
10336             color = color || "ffff9c";
10337             attr = o.attr || "backgroundColor";
10338
10339             this.clearOpacity();
10340             this.show();
10341
10342             var origColor = this.getColor(attr);
10343             var restoreColor = this.dom.style[attr];
10344             endColor = (o.endColor || origColor) || "ffffff";
10345
10346             var after = function(){
10347                 el.dom.style[attr] = restoreColor;
10348                 el.afterFx(o);
10349             };
10350
10351             var a = {};
10352             a[attr] = {from: color, to: endColor};
10353             arguments.callee.anim = this.fxanim(a,
10354                 o,
10355                 'color',
10356                 1,
10357                 'easeIn', after);
10358         });
10359         return this;
10360     },
10361
10362    /**
10363     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10364     * Usage:
10365 <pre><code>
10366 // default: a single light blue ripple
10367 el.frame();
10368
10369 // custom: 3 red ripples lasting 3 seconds total
10370 el.frame("ff0000", 3, { duration: 3 });
10371
10372 // common config options shown with default values
10373 el.frame("C3DAF9", 1, {
10374     duration: 1 //duration of entire animation (not each individual ripple)
10375     // Note: Easing is not configurable and will be ignored if included
10376 });
10377 </code></pre>
10378     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10379     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10380     * @param {Object} options (optional) Object literal with any of the Fx config options
10381     * @return {Roo.Element} The Element
10382     */
10383     frame : function(color, count, o){
10384         var el = this.getFxEl();
10385         o = o || {};
10386
10387         el.queueFx(o, function(){
10388             color = color || "#C3DAF9";
10389             if(color.length == 6){
10390                 color = "#" + color;
10391             }
10392             count = count || 1;
10393             duration = o.duration || 1;
10394             this.show();
10395
10396             var b = this.getBox();
10397             var animFn = function(){
10398                 var proxy = this.createProxy({
10399
10400                      style:{
10401                         visbility:"hidden",
10402                         position:"absolute",
10403                         "z-index":"35000", // yee haw
10404                         border:"0px solid " + color
10405                      }
10406                   });
10407                 var scale = Roo.isBorderBox ? 2 : 1;
10408                 proxy.animate({
10409                     top:{from:b.y, to:b.y - 20},
10410                     left:{from:b.x, to:b.x - 20},
10411                     borderWidth:{from:0, to:10},
10412                     opacity:{from:1, to:0},
10413                     height:{from:b.height, to:(b.height + (20*scale))},
10414                     width:{from:b.width, to:(b.width + (20*scale))}
10415                 }, duration, function(){
10416                     proxy.remove();
10417                 });
10418                 if(--count > 0){
10419                      animFn.defer((duration/2)*1000, this);
10420                 }else{
10421                     el.afterFx(o);
10422                 }
10423             };
10424             animFn.call(this);
10425         });
10426         return this;
10427     },
10428
10429    /**
10430     * Creates a pause before any subsequent queued effects begin.  If there are
10431     * no effects queued after the pause it will have no effect.
10432     * Usage:
10433 <pre><code>
10434 el.pause(1);
10435 </code></pre>
10436     * @param {Number} seconds The length of time to pause (in seconds)
10437     * @return {Roo.Element} The Element
10438     */
10439     pause : function(seconds){
10440         var el = this.getFxEl();
10441         var o = {};
10442
10443         el.queueFx(o, function(){
10444             setTimeout(function(){
10445                 el.afterFx(o);
10446             }, seconds * 1000);
10447         });
10448         return this;
10449     },
10450
10451    /**
10452     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10453     * using the "endOpacity" config option.
10454     * Usage:
10455 <pre><code>
10456 // default: fade in from opacity 0 to 100%
10457 el.fadeIn();
10458
10459 // custom: fade in from opacity 0 to 75% over 2 seconds
10460 el.fadeIn({ endOpacity: .75, duration: 2});
10461
10462 // common config options shown with default values
10463 el.fadeIn({
10464     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10465     easing: 'easeOut',
10466     duration: .5
10467 });
10468 </code></pre>
10469     * @param {Object} options (optional) Object literal with any of the Fx config options
10470     * @return {Roo.Element} The Element
10471     */
10472     fadeIn : function(o){
10473         var el = this.getFxEl();
10474         o = o || {};
10475         el.queueFx(o, function(){
10476             this.setOpacity(0);
10477             this.fixDisplay();
10478             this.dom.style.visibility = 'visible';
10479             var to = o.endOpacity || 1;
10480             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10481                 o, null, .5, "easeOut", function(){
10482                 if(to == 1){
10483                     this.clearOpacity();
10484                 }
10485                 el.afterFx(o);
10486             });
10487         });
10488         return this;
10489     },
10490
10491    /**
10492     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10493     * using the "endOpacity" config option.
10494     * Usage:
10495 <pre><code>
10496 // default: fade out from the element's current opacity to 0
10497 el.fadeOut();
10498
10499 // custom: fade out from the element's current opacity to 25% over 2 seconds
10500 el.fadeOut({ endOpacity: .25, duration: 2});
10501
10502 // common config options shown with default values
10503 el.fadeOut({
10504     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10505     easing: 'easeOut',
10506     duration: .5
10507     remove: false,
10508     useDisplay: false
10509 });
10510 </code></pre>
10511     * @param {Object} options (optional) Object literal with any of the Fx config options
10512     * @return {Roo.Element} The Element
10513     */
10514     fadeOut : function(o){
10515         var el = this.getFxEl();
10516         o = o || {};
10517         el.queueFx(o, function(){
10518             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10519                 o, null, .5, "easeOut", function(){
10520                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10521                      this.dom.style.display = "none";
10522                 }else{
10523                      this.dom.style.visibility = "hidden";
10524                 }
10525                 this.clearOpacity();
10526                 el.afterFx(o);
10527             });
10528         });
10529         return this;
10530     },
10531
10532    /**
10533     * Animates the transition of an element's dimensions from a starting height/width
10534     * to an ending height/width.
10535     * Usage:
10536 <pre><code>
10537 // change height and width to 100x100 pixels
10538 el.scale(100, 100);
10539
10540 // common config options shown with default values.  The height and width will default to
10541 // the element's existing values if passed as null.
10542 el.scale(
10543     [element's width],
10544     [element's height], {
10545     easing: 'easeOut',
10546     duration: .35
10547 });
10548 </code></pre>
10549     * @param {Number} width  The new width (pass undefined to keep the original width)
10550     * @param {Number} height  The new height (pass undefined to keep the original height)
10551     * @param {Object} options (optional) Object literal with any of the Fx config options
10552     * @return {Roo.Element} The Element
10553     */
10554     scale : function(w, h, o){
10555         this.shift(Roo.apply({}, o, {
10556             width: w,
10557             height: h
10558         }));
10559         return this;
10560     },
10561
10562    /**
10563     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10564     * Any of these properties not specified in the config object will not be changed.  This effect 
10565     * requires that at least one new dimension, position or opacity setting must be passed in on
10566     * the config object in order for the function to have any effect.
10567     * Usage:
10568 <pre><code>
10569 // slide the element horizontally to x position 200 while changing the height and opacity
10570 el.shift({ x: 200, height: 50, opacity: .8 });
10571
10572 // common config options shown with default values.
10573 el.shift({
10574     width: [element's width],
10575     height: [element's height],
10576     x: [element's x position],
10577     y: [element's y position],
10578     opacity: [element's opacity],
10579     easing: 'easeOut',
10580     duration: .35
10581 });
10582 </code></pre>
10583     * @param {Object} options  Object literal with any of the Fx config options
10584     * @return {Roo.Element} The Element
10585     */
10586     shift : function(o){
10587         var el = this.getFxEl();
10588         o = o || {};
10589         el.queueFx(o, function(){
10590             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10591             if(w !== undefined){
10592                 a.width = {to: this.adjustWidth(w)};
10593             }
10594             if(h !== undefined){
10595                 a.height = {to: this.adjustHeight(h)};
10596             }
10597             if(x !== undefined || y !== undefined){
10598                 a.points = {to: [
10599                     x !== undefined ? x : this.getX(),
10600                     y !== undefined ? y : this.getY()
10601                 ]};
10602             }
10603             if(op !== undefined){
10604                 a.opacity = {to: op};
10605             }
10606             if(o.xy !== undefined){
10607                 a.points = {to: o.xy};
10608             }
10609             arguments.callee.anim = this.fxanim(a,
10610                 o, 'motion', .35, "easeOut", function(){
10611                 el.afterFx(o);
10612             });
10613         });
10614         return this;
10615     },
10616
10617         /**
10618          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10619          * ending point of the effect.
10620          * Usage:
10621          *<pre><code>
10622 // default: slide the element downward while fading out
10623 el.ghost();
10624
10625 // custom: slide the element out to the right with a 2-second duration
10626 el.ghost('r', { duration: 2 });
10627
10628 // common config options shown with default values
10629 el.ghost('b', {
10630     easing: 'easeOut',
10631     duration: .5
10632     remove: false,
10633     useDisplay: false
10634 });
10635 </code></pre>
10636          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10637          * @param {Object} options (optional) Object literal with any of the Fx config options
10638          * @return {Roo.Element} The Element
10639          */
10640     ghost : function(anchor, o){
10641         var el = this.getFxEl();
10642         o = o || {};
10643
10644         el.queueFx(o, function(){
10645             anchor = anchor || "b";
10646
10647             // restore values after effect
10648             var r = this.getFxRestore();
10649             var w = this.getWidth(),
10650                 h = this.getHeight();
10651
10652             var st = this.dom.style;
10653
10654             var after = function(){
10655                 if(o.useDisplay){
10656                     el.setDisplayed(false);
10657                 }else{
10658                     el.hide();
10659                 }
10660
10661                 el.clearOpacity();
10662                 el.setPositioning(r.pos);
10663                 st.width = r.width;
10664                 st.height = r.height;
10665
10666                 el.afterFx(o);
10667             };
10668
10669             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10670             switch(anchor.toLowerCase()){
10671                 case "t":
10672                     pt.by = [0, -h];
10673                 break;
10674                 case "l":
10675                     pt.by = [-w, 0];
10676                 break;
10677                 case "r":
10678                     pt.by = [w, 0];
10679                 break;
10680                 case "b":
10681                     pt.by = [0, h];
10682                 break;
10683                 case "tl":
10684                     pt.by = [-w, -h];
10685                 break;
10686                 case "bl":
10687                     pt.by = [-w, h];
10688                 break;
10689                 case "br":
10690                     pt.by = [w, h];
10691                 break;
10692                 case "tr":
10693                     pt.by = [w, -h];
10694                 break;
10695             }
10696
10697             arguments.callee.anim = this.fxanim(a,
10698                 o,
10699                 'motion',
10700                 .5,
10701                 "easeOut", after);
10702         });
10703         return this;
10704     },
10705
10706         /**
10707          * Ensures that all effects queued after syncFx is called on the element are
10708          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10709          * @return {Roo.Element} The Element
10710          */
10711     syncFx : function(){
10712         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10713             block : false,
10714             concurrent : true,
10715             stopFx : false
10716         });
10717         return this;
10718     },
10719
10720         /**
10721          * Ensures that all effects queued after sequenceFx is called on the element are
10722          * run in sequence.  This is the opposite of {@link #syncFx}.
10723          * @return {Roo.Element} The Element
10724          */
10725     sequenceFx : function(){
10726         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10727             block : false,
10728             concurrent : false,
10729             stopFx : false
10730         });
10731         return this;
10732     },
10733
10734         /* @private */
10735     nextFx : function(){
10736         var ef = this.fxQueue[0];
10737         if(ef){
10738             ef.call(this);
10739         }
10740     },
10741
10742         /**
10743          * Returns true if the element has any effects actively running or queued, else returns false.
10744          * @return {Boolean} True if element has active effects, else false
10745          */
10746     hasActiveFx : function(){
10747         return this.fxQueue && this.fxQueue[0];
10748     },
10749
10750         /**
10751          * Stops any running effects and clears the element's internal effects queue if it contains
10752          * any additional effects that haven't started yet.
10753          * @return {Roo.Element} The Element
10754          */
10755     stopFx : function(){
10756         if(this.hasActiveFx()){
10757             var cur = this.fxQueue[0];
10758             if(cur && cur.anim && cur.anim.isAnimated()){
10759                 this.fxQueue = [cur]; // clear out others
10760                 cur.anim.stop(true);
10761             }
10762         }
10763         return this;
10764     },
10765
10766         /* @private */
10767     beforeFx : function(o){
10768         if(this.hasActiveFx() && !o.concurrent){
10769            if(o.stopFx){
10770                this.stopFx();
10771                return true;
10772            }
10773            return false;
10774         }
10775         return true;
10776     },
10777
10778         /**
10779          * Returns true if the element is currently blocking so that no other effect can be queued
10780          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10781          * used to ensure that an effect initiated by a user action runs to completion prior to the
10782          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10783          * @return {Boolean} True if blocking, else false
10784          */
10785     hasFxBlock : function(){
10786         var q = this.fxQueue;
10787         return q && q[0] && q[0].block;
10788     },
10789
10790         /* @private */
10791     queueFx : function(o, fn){
10792         if(!this.fxQueue){
10793             this.fxQueue = [];
10794         }
10795         if(!this.hasFxBlock()){
10796             Roo.applyIf(o, this.fxDefaults);
10797             if(!o.concurrent){
10798                 var run = this.beforeFx(o);
10799                 fn.block = o.block;
10800                 this.fxQueue.push(fn);
10801                 if(run){
10802                     this.nextFx();
10803                 }
10804             }else{
10805                 fn.call(this);
10806             }
10807         }
10808         return this;
10809     },
10810
10811         /* @private */
10812     fxWrap : function(pos, o, vis){
10813         var wrap;
10814         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10815             var wrapXY;
10816             if(o.fixPosition){
10817                 wrapXY = this.getXY();
10818             }
10819             var div = document.createElement("div");
10820             div.style.visibility = vis;
10821             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10822             wrap.setPositioning(pos);
10823             if(wrap.getStyle("position") == "static"){
10824                 wrap.position("relative");
10825             }
10826             this.clearPositioning('auto');
10827             wrap.clip();
10828             wrap.dom.appendChild(this.dom);
10829             if(wrapXY){
10830                 wrap.setXY(wrapXY);
10831             }
10832         }
10833         return wrap;
10834     },
10835
10836         /* @private */
10837     fxUnwrap : function(wrap, pos, o){
10838         this.clearPositioning();
10839         this.setPositioning(pos);
10840         if(!o.wrap){
10841             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10842             wrap.remove();
10843         }
10844     },
10845
10846         /* @private */
10847     getFxRestore : function(){
10848         var st = this.dom.style;
10849         return {pos: this.getPositioning(), width: st.width, height : st.height};
10850     },
10851
10852         /* @private */
10853     afterFx : function(o){
10854         if(o.afterStyle){
10855             this.applyStyles(o.afterStyle);
10856         }
10857         if(o.afterCls){
10858             this.addClass(o.afterCls);
10859         }
10860         if(o.remove === true){
10861             this.remove();
10862         }
10863         Roo.callback(o.callback, o.scope, [this]);
10864         if(!o.concurrent){
10865             this.fxQueue.shift();
10866             this.nextFx();
10867         }
10868     },
10869
10870         /* @private */
10871     getFxEl : function(){ // support for composite element fx
10872         return Roo.get(this.dom);
10873     },
10874
10875         /* @private */
10876     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10877         animType = animType || 'run';
10878         opt = opt || {};
10879         var anim = Roo.lib.Anim[animType](
10880             this.dom, args,
10881             (opt.duration || defaultDur) || .35,
10882             (opt.easing || defaultEase) || 'easeOut',
10883             function(){
10884                 Roo.callback(cb, this);
10885             },
10886             this
10887         );
10888         opt.anim = anim;
10889         return anim;
10890     }
10891 };
10892
10893 // backwords compat
10894 Roo.Fx.resize = Roo.Fx.scale;
10895
10896 //When included, Roo.Fx is automatically applied to Element so that all basic
10897 //effects are available directly via the Element API
10898 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10899  * Based on:
10900  * Ext JS Library 1.1.1
10901  * Copyright(c) 2006-2007, Ext JS, LLC.
10902  *
10903  * Originally Released Under LGPL - original licence link has changed is not relivant.
10904  *
10905  * Fork - LGPL
10906  * <script type="text/javascript">
10907  */
10908
10909
10910 /**
10911  * @class Roo.CompositeElement
10912  * Standard composite class. Creates a Roo.Element for every element in the collection.
10913  * <br><br>
10914  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10915  * actions will be performed on all the elements in this collection.</b>
10916  * <br><br>
10917  * All methods return <i>this</i> and can be chained.
10918  <pre><code>
10919  var els = Roo.select("#some-el div.some-class", true);
10920  // or select directly from an existing element
10921  var el = Roo.get('some-el');
10922  el.select('div.some-class', true);
10923
10924  els.setWidth(100); // all elements become 100 width
10925  els.hide(true); // all elements fade out and hide
10926  // or
10927  els.setWidth(100).hide(true);
10928  </code></pre>
10929  */
10930 Roo.CompositeElement = function(els){
10931     this.elements = [];
10932     this.addElements(els);
10933 };
10934 Roo.CompositeElement.prototype = {
10935     isComposite: true,
10936     addElements : function(els){
10937         if(!els) return this;
10938         if(typeof els == "string"){
10939             els = Roo.Element.selectorFunction(els);
10940         }
10941         var yels = this.elements;
10942         var index = yels.length-1;
10943         for(var i = 0, len = els.length; i < len; i++) {
10944                 yels[++index] = Roo.get(els[i]);
10945         }
10946         return this;
10947     },
10948
10949     /**
10950     * Clears this composite and adds the elements returned by the passed selector.
10951     * @param {String/Array} els A string CSS selector, an array of elements or an element
10952     * @return {CompositeElement} this
10953     */
10954     fill : function(els){
10955         this.elements = [];
10956         this.add(els);
10957         return this;
10958     },
10959
10960     /**
10961     * Filters this composite to only elements that match the passed selector.
10962     * @param {String} selector A string CSS selector
10963     * @return {CompositeElement} this
10964     */
10965     filter : function(selector){
10966         var els = [];
10967         this.each(function(el){
10968             if(el.is(selector)){
10969                 els[els.length] = el.dom;
10970             }
10971         });
10972         this.fill(els);
10973         return this;
10974     },
10975
10976     invoke : function(fn, args){
10977         var els = this.elements;
10978         for(var i = 0, len = els.length; i < len; i++) {
10979                 Roo.Element.prototype[fn].apply(els[i], args);
10980         }
10981         return this;
10982     },
10983     /**
10984     * Adds elements to this composite.
10985     * @param {String/Array} els A string CSS selector, an array of elements or an element
10986     * @return {CompositeElement} this
10987     */
10988     add : function(els){
10989         if(typeof els == "string"){
10990             this.addElements(Roo.Element.selectorFunction(els));
10991         }else if(els.length !== undefined){
10992             this.addElements(els);
10993         }else{
10994             this.addElements([els]);
10995         }
10996         return this;
10997     },
10998     /**
10999     * Calls the passed function passing (el, this, index) for each element in this composite.
11000     * @param {Function} fn The function to call
11001     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11002     * @return {CompositeElement} this
11003     */
11004     each : function(fn, scope){
11005         var els = this.elements;
11006         for(var i = 0, len = els.length; i < len; i++){
11007             if(fn.call(scope || els[i], els[i], this, i) === false) {
11008                 break;
11009             }
11010         }
11011         return this;
11012     },
11013
11014     /**
11015      * Returns the Element object at the specified index
11016      * @param {Number} index
11017      * @return {Roo.Element}
11018      */
11019     item : function(index){
11020         return this.elements[index] || null;
11021     },
11022
11023     /**
11024      * Returns the first Element
11025      * @return {Roo.Element}
11026      */
11027     first : function(){
11028         return this.item(0);
11029     },
11030
11031     /**
11032      * Returns the last Element
11033      * @return {Roo.Element}
11034      */
11035     last : function(){
11036         return this.item(this.elements.length-1);
11037     },
11038
11039     /**
11040      * Returns the number of elements in this composite
11041      * @return Number
11042      */
11043     getCount : function(){
11044         return this.elements.length;
11045     },
11046
11047     /**
11048      * Returns true if this composite contains the passed element
11049      * @return Boolean
11050      */
11051     contains : function(el){
11052         return this.indexOf(el) !== -1;
11053     },
11054
11055     /**
11056      * Returns true if this composite contains the passed element
11057      * @return Boolean
11058      */
11059     indexOf : function(el){
11060         return this.elements.indexOf(Roo.get(el));
11061     },
11062
11063
11064     /**
11065     * Removes the specified element(s).
11066     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11067     * or an array of any of those.
11068     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11069     * @return {CompositeElement} this
11070     */
11071     removeElement : function(el, removeDom){
11072         if(el instanceof Array){
11073             for(var i = 0, len = el.length; i < len; i++){
11074                 this.removeElement(el[i]);
11075             }
11076             return this;
11077         }
11078         var index = typeof el == 'number' ? el : this.indexOf(el);
11079         if(index !== -1){
11080             if(removeDom){
11081                 var d = this.elements[index];
11082                 if(d.dom){
11083                     d.remove();
11084                 }else{
11085                     d.parentNode.removeChild(d);
11086                 }
11087             }
11088             this.elements.splice(index, 1);
11089         }
11090         return this;
11091     },
11092
11093     /**
11094     * Replaces the specified element with the passed element.
11095     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11096     * to replace.
11097     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11098     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11099     * @return {CompositeElement} this
11100     */
11101     replaceElement : function(el, replacement, domReplace){
11102         var index = typeof el == 'number' ? el : this.indexOf(el);
11103         if(index !== -1){
11104             if(domReplace){
11105                 this.elements[index].replaceWith(replacement);
11106             }else{
11107                 this.elements.splice(index, 1, Roo.get(replacement))
11108             }
11109         }
11110         return this;
11111     },
11112
11113     /**
11114      * Removes all elements.
11115      */
11116     clear : function(){
11117         this.elements = [];
11118     }
11119 };
11120 (function(){
11121     Roo.CompositeElement.createCall = function(proto, fnName){
11122         if(!proto[fnName]){
11123             proto[fnName] = function(){
11124                 return this.invoke(fnName, arguments);
11125             };
11126         }
11127     };
11128     for(var fnName in Roo.Element.prototype){
11129         if(typeof Roo.Element.prototype[fnName] == "function"){
11130             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11131         }
11132     };
11133 })();
11134 /*
11135  * Based on:
11136  * Ext JS Library 1.1.1
11137  * Copyright(c) 2006-2007, Ext JS, LLC.
11138  *
11139  * Originally Released Under LGPL - original licence link has changed is not relivant.
11140  *
11141  * Fork - LGPL
11142  * <script type="text/javascript">
11143  */
11144
11145 /**
11146  * @class Roo.CompositeElementLite
11147  * @extends Roo.CompositeElement
11148  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11149  <pre><code>
11150  var els = Roo.select("#some-el div.some-class");
11151  // or select directly from an existing element
11152  var el = Roo.get('some-el');
11153  el.select('div.some-class');
11154
11155  els.setWidth(100); // all elements become 100 width
11156  els.hide(true); // all elements fade out and hide
11157  // or
11158  els.setWidth(100).hide(true);
11159  </code></pre><br><br>
11160  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11161  * actions will be performed on all the elements in this collection.</b>
11162  */
11163 Roo.CompositeElementLite = function(els){
11164     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11165     this.el = new Roo.Element.Flyweight();
11166 };
11167 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11168     addElements : function(els){
11169         if(els){
11170             if(els instanceof Array){
11171                 this.elements = this.elements.concat(els);
11172             }else{
11173                 var yels = this.elements;
11174                 var index = yels.length-1;
11175                 for(var i = 0, len = els.length; i < len; i++) {
11176                     yels[++index] = els[i];
11177                 }
11178             }
11179         }
11180         return this;
11181     },
11182     invoke : function(fn, args){
11183         var els = this.elements;
11184         var el = this.el;
11185         for(var i = 0, len = els.length; i < len; i++) {
11186             el.dom = els[i];
11187                 Roo.Element.prototype[fn].apply(el, args);
11188         }
11189         return this;
11190     },
11191     /**
11192      * Returns a flyweight Element of the dom element object at the specified index
11193      * @param {Number} index
11194      * @return {Roo.Element}
11195      */
11196     item : function(index){
11197         if(!this.elements[index]){
11198             return null;
11199         }
11200         this.el.dom = this.elements[index];
11201         return this.el;
11202     },
11203
11204     // fixes scope with flyweight
11205     addListener : function(eventName, handler, scope, opt){
11206         var els = this.elements;
11207         for(var i = 0, len = els.length; i < len; i++) {
11208             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11209         }
11210         return this;
11211     },
11212
11213     /**
11214     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11215     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11216     * a reference to the dom node, use el.dom.</b>
11217     * @param {Function} fn The function to call
11218     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11219     * @return {CompositeElement} this
11220     */
11221     each : function(fn, scope){
11222         var els = this.elements;
11223         var el = this.el;
11224         for(var i = 0, len = els.length; i < len; i++){
11225             el.dom = els[i];
11226                 if(fn.call(scope || el, el, this, i) === false){
11227                 break;
11228             }
11229         }
11230         return this;
11231     },
11232
11233     indexOf : function(el){
11234         return this.elements.indexOf(Roo.getDom(el));
11235     },
11236
11237     replaceElement : function(el, replacement, domReplace){
11238         var index = typeof el == 'number' ? el : this.indexOf(el);
11239         if(index !== -1){
11240             replacement = Roo.getDom(replacement);
11241             if(domReplace){
11242                 var d = this.elements[index];
11243                 d.parentNode.insertBefore(replacement, d);
11244                 d.parentNode.removeChild(d);
11245             }
11246             this.elements.splice(index, 1, replacement);
11247         }
11248         return this;
11249     }
11250 });
11251 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11252
11253 /*
11254  * Based on:
11255  * Ext JS Library 1.1.1
11256  * Copyright(c) 2006-2007, Ext JS, LLC.
11257  *
11258  * Originally Released Under LGPL - original licence link has changed is not relivant.
11259  *
11260  * Fork - LGPL
11261  * <script type="text/javascript">
11262  */
11263
11264  
11265
11266 /**
11267  * @class Roo.data.Connection
11268  * @extends Roo.util.Observable
11269  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11270  * either to a configured URL, or to a URL specified at request time.<br><br>
11271  * <p>
11272  * Requests made by this class are asynchronous, and will return immediately. No data from
11273  * the server will be available to the statement immediately following the {@link #request} call.
11274  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11275  * <p>
11276  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11277  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11278  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11279  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11280  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11281  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11282  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11283  * standard DOM methods.
11284  * @constructor
11285  * @param {Object} config a configuration object.
11286  */
11287 Roo.data.Connection = function(config){
11288     Roo.apply(this, config);
11289     this.addEvents({
11290         /**
11291          * @event beforerequest
11292          * Fires before a network request is made to retrieve a data object.
11293          * @param {Connection} conn This Connection object.
11294          * @param {Object} options The options config object passed to the {@link #request} method.
11295          */
11296         "beforerequest" : true,
11297         /**
11298          * @event requestcomplete
11299          * Fires if the request was successfully completed.
11300          * @param {Connection} conn This Connection object.
11301          * @param {Object} response The XHR object containing the response data.
11302          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11303          * @param {Object} options The options config object passed to the {@link #request} method.
11304          */
11305         "requestcomplete" : true,
11306         /**
11307          * @event requestexception
11308          * Fires if an error HTTP status was returned from the server.
11309          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11310          * @param {Connection} conn This Connection object.
11311          * @param {Object} response The XHR object containing the response data.
11312          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11313          * @param {Object} options The options config object passed to the {@link #request} method.
11314          */
11315         "requestexception" : true
11316     });
11317     Roo.data.Connection.superclass.constructor.call(this);
11318 };
11319
11320 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11321     /**
11322      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11323      */
11324     /**
11325      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11326      * extra parameters to each request made by this object. (defaults to undefined)
11327      */
11328     /**
11329      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11330      *  to each request made by this object. (defaults to undefined)
11331      */
11332     /**
11333      * @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)
11334      */
11335     /**
11336      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11337      */
11338     timeout : 30000,
11339     /**
11340      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11341      * @type Boolean
11342      */
11343     autoAbort:false,
11344
11345     /**
11346      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11347      * @type Boolean
11348      */
11349     disableCaching: true,
11350
11351     /**
11352      * Sends an HTTP request to a remote server.
11353      * @param {Object} options An object which may contain the following properties:<ul>
11354      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11355      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11356      * request, a url encoded string or a function to call to get either.</li>
11357      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11358      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11359      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11360      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11361      * <li>options {Object} The parameter to the request call.</li>
11362      * <li>success {Boolean} True if the request succeeded.</li>
11363      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11364      * </ul></li>
11365      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11366      * The callback is passed the following parameters:<ul>
11367      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11368      * <li>options {Object} The parameter to the request call.</li>
11369      * </ul></li>
11370      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11371      * The callback is passed the following parameters:<ul>
11372      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11373      * <li>options {Object} The parameter to the request call.</li>
11374      * </ul></li>
11375      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11376      * for the callback function. Defaults to the browser window.</li>
11377      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11378      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11379      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11380      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11381      * params for the post data. Any params will be appended to the URL.</li>
11382      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11383      * </ul>
11384      * @return {Number} transactionId
11385      */
11386     request : function(o){
11387         if(this.fireEvent("beforerequest", this, o) !== false){
11388             var p = o.params;
11389
11390             if(typeof p == "function"){
11391                 p = p.call(o.scope||window, o);
11392             }
11393             if(typeof p == "object"){
11394                 p = Roo.urlEncode(o.params);
11395             }
11396             if(this.extraParams){
11397                 var extras = Roo.urlEncode(this.extraParams);
11398                 p = p ? (p + '&' + extras) : extras;
11399             }
11400
11401             var url = o.url || this.url;
11402             if(typeof url == 'function'){
11403                 url = url.call(o.scope||window, o);
11404             }
11405
11406             if(o.form){
11407                 var form = Roo.getDom(o.form);
11408                 url = url || form.action;
11409
11410                 var enctype = form.getAttribute("enctype");
11411                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11412                     return this.doFormUpload(o, p, url);
11413                 }
11414                 var f = Roo.lib.Ajax.serializeForm(form);
11415                 p = p ? (p + '&' + f) : f;
11416             }
11417
11418             var hs = o.headers;
11419             if(this.defaultHeaders){
11420                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11421                 if(!o.headers){
11422                     o.headers = hs;
11423                 }
11424             }
11425
11426             var cb = {
11427                 success: this.handleResponse,
11428                 failure: this.handleFailure,
11429                 scope: this,
11430                 argument: {options: o},
11431                 timeout : o.timeout || this.timeout
11432             };
11433
11434             var method = o.method||this.method||(p ? "POST" : "GET");
11435
11436             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11437                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11438             }
11439
11440             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11441                 if(o.autoAbort){
11442                     this.abort();
11443                 }
11444             }else if(this.autoAbort !== false){
11445                 this.abort();
11446             }
11447
11448             if((method == 'GET' && p) || o.xmlData){
11449                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11450                 p = '';
11451             }
11452             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11453             return this.transId;
11454         }else{
11455             Roo.callback(o.callback, o.scope, [o, null, null]);
11456             return null;
11457         }
11458     },
11459
11460     /**
11461      * Determine whether this object has a request outstanding.
11462      * @param {Number} transactionId (Optional) defaults to the last transaction
11463      * @return {Boolean} True if there is an outstanding request.
11464      */
11465     isLoading : function(transId){
11466         if(transId){
11467             return Roo.lib.Ajax.isCallInProgress(transId);
11468         }else{
11469             return this.transId ? true : false;
11470         }
11471     },
11472
11473     /**
11474      * Aborts any outstanding request.
11475      * @param {Number} transactionId (Optional) defaults to the last transaction
11476      */
11477     abort : function(transId){
11478         if(transId || this.isLoading()){
11479             Roo.lib.Ajax.abort(transId || this.transId);
11480         }
11481     },
11482
11483     // private
11484     handleResponse : function(response){
11485         this.transId = false;
11486         var options = response.argument.options;
11487         response.argument = options ? options.argument : null;
11488         this.fireEvent("requestcomplete", this, response, options);
11489         Roo.callback(options.success, options.scope, [response, options]);
11490         Roo.callback(options.callback, options.scope, [options, true, response]);
11491     },
11492
11493     // private
11494     handleFailure : function(response, e){
11495         this.transId = false;
11496         var options = response.argument.options;
11497         response.argument = options ? options.argument : null;
11498         this.fireEvent("requestexception", this, response, options, e);
11499         Roo.callback(options.failure, options.scope, [response, options]);
11500         Roo.callback(options.callback, options.scope, [options, false, response]);
11501     },
11502
11503     // private
11504     doFormUpload : function(o, ps, url){
11505         var id = Roo.id();
11506         var frame = document.createElement('iframe');
11507         frame.id = id;
11508         frame.name = id;
11509         frame.className = 'x-hidden';
11510         if(Roo.isIE){
11511             frame.src = Roo.SSL_SECURE_URL;
11512         }
11513         document.body.appendChild(frame);
11514
11515         if(Roo.isIE){
11516            document.frames[id].name = id;
11517         }
11518
11519         var form = Roo.getDom(o.form);
11520         form.target = id;
11521         form.method = 'POST';
11522         form.enctype = form.encoding = 'multipart/form-data';
11523         if(url){
11524             form.action = url;
11525         }
11526
11527         var hiddens, hd;
11528         if(ps){ // add dynamic params
11529             hiddens = [];
11530             ps = Roo.urlDecode(ps, false);
11531             for(var k in ps){
11532                 if(ps.hasOwnProperty(k)){
11533                     hd = document.createElement('input');
11534                     hd.type = 'hidden';
11535                     hd.name = k;
11536                     hd.value = ps[k];
11537                     form.appendChild(hd);
11538                     hiddens.push(hd);
11539                 }
11540             }
11541         }
11542
11543         function cb(){
11544             var r = {  // bogus response object
11545                 responseText : '',
11546                 responseXML : null
11547             };
11548
11549             r.argument = o ? o.argument : null;
11550
11551             try { //
11552                 var doc;
11553                 if(Roo.isIE){
11554                     doc = frame.contentWindow.document;
11555                 }else {
11556                     doc = (frame.contentDocument || window.frames[id].document);
11557                 }
11558                 if(doc && doc.body){
11559                     r.responseText = doc.body.innerHTML;
11560                 }
11561                 if(doc && doc.XMLDocument){
11562                     r.responseXML = doc.XMLDocument;
11563                 }else {
11564                     r.responseXML = doc;
11565                 }
11566             }
11567             catch(e) {
11568                 // ignore
11569             }
11570
11571             Roo.EventManager.removeListener(frame, 'load', cb, this);
11572
11573             this.fireEvent("requestcomplete", this, r, o);
11574             Roo.callback(o.success, o.scope, [r, o]);
11575             Roo.callback(o.callback, o.scope, [o, true, r]);
11576
11577             setTimeout(function(){document.body.removeChild(frame);}, 100);
11578         }
11579
11580         Roo.EventManager.on(frame, 'load', cb, this);
11581         form.submit();
11582
11583         if(hiddens){ // remove dynamic params
11584             for(var i = 0, len = hiddens.length; i < len; i++){
11585                 form.removeChild(hiddens[i]);
11586             }
11587         }
11588     }
11589 });
11590 /*
11591  * Based on:
11592  * Ext JS Library 1.1.1
11593  * Copyright(c) 2006-2007, Ext JS, LLC.
11594  *
11595  * Originally Released Under LGPL - original licence link has changed is not relivant.
11596  *
11597  * Fork - LGPL
11598  * <script type="text/javascript">
11599  */
11600  
11601 /**
11602  * Global Ajax request class.
11603  * 
11604  * @class Roo.Ajax
11605  * @extends Roo.data.Connection
11606  * @static
11607  * 
11608  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11609  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11610  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11611  * @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)
11612  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11613  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11614  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11615  */
11616 Roo.Ajax = new Roo.data.Connection({
11617     // fix up the docs
11618     /**
11619      * @scope Roo.Ajax
11620      * @type {Boolear} 
11621      */
11622     autoAbort : false,
11623
11624     /**
11625      * Serialize the passed form into a url encoded string
11626      * @scope Roo.Ajax
11627      * @param {String/HTMLElement} form
11628      * @return {String}
11629      */
11630     serializeForm : function(form){
11631         return Roo.lib.Ajax.serializeForm(form);
11632     }
11633 });/*
11634  * Based on:
11635  * Ext JS Library 1.1.1
11636  * Copyright(c) 2006-2007, Ext JS, LLC.
11637  *
11638  * Originally Released Under LGPL - original licence link has changed is not relivant.
11639  *
11640  * Fork - LGPL
11641  * <script type="text/javascript">
11642  */
11643
11644  
11645 /**
11646  * @class Roo.UpdateManager
11647  * @extends Roo.util.Observable
11648  * Provides AJAX-style update for Element object.<br><br>
11649  * Usage:<br>
11650  * <pre><code>
11651  * // Get it from a Roo.Element object
11652  * var el = Roo.get("foo");
11653  * var mgr = el.getUpdateManager();
11654  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11655  * ...
11656  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11657  * <br>
11658  * // or directly (returns the same UpdateManager instance)
11659  * var mgr = new Roo.UpdateManager("myElementId");
11660  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11661  * mgr.on("update", myFcnNeedsToKnow);
11662  * <br>
11663    // short handed call directly from the element object
11664    Roo.get("foo").load({
11665         url: "bar.php",
11666         scripts:true,
11667         params: "for=bar",
11668         text: "Loading Foo..."
11669    });
11670  * </code></pre>
11671  * @constructor
11672  * Create new UpdateManager directly.
11673  * @param {String/HTMLElement/Roo.Element} el The element to update
11674  * @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).
11675  */
11676 Roo.UpdateManager = function(el, forceNew){
11677     el = Roo.get(el);
11678     if(!forceNew && el.updateManager){
11679         return el.updateManager;
11680     }
11681     /**
11682      * The Element object
11683      * @type Roo.Element
11684      */
11685     this.el = el;
11686     /**
11687      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11688      * @type String
11689      */
11690     this.defaultUrl = null;
11691
11692     this.addEvents({
11693         /**
11694          * @event beforeupdate
11695          * Fired before an update is made, return false from your handler and the update is cancelled.
11696          * @param {Roo.Element} el
11697          * @param {String/Object/Function} url
11698          * @param {String/Object} params
11699          */
11700         "beforeupdate": true,
11701         /**
11702          * @event update
11703          * Fired after successful update is made.
11704          * @param {Roo.Element} el
11705          * @param {Object} oResponseObject The response Object
11706          */
11707         "update": true,
11708         /**
11709          * @event failure
11710          * Fired on update failure.
11711          * @param {Roo.Element} el
11712          * @param {Object} oResponseObject The response Object
11713          */
11714         "failure": true
11715     });
11716     var d = Roo.UpdateManager.defaults;
11717     /**
11718      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11719      * @type String
11720      */
11721     this.sslBlankUrl = d.sslBlankUrl;
11722     /**
11723      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11724      * @type Boolean
11725      */
11726     this.disableCaching = d.disableCaching;
11727     /**
11728      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11729      * @type String
11730      */
11731     this.indicatorText = d.indicatorText;
11732     /**
11733      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11734      * @type String
11735      */
11736     this.showLoadIndicator = d.showLoadIndicator;
11737     /**
11738      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11739      * @type Number
11740      */
11741     this.timeout = d.timeout;
11742
11743     /**
11744      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11745      * @type Boolean
11746      */
11747     this.loadScripts = d.loadScripts;
11748
11749     /**
11750      * Transaction object of current executing transaction
11751      */
11752     this.transaction = null;
11753
11754     /**
11755      * @private
11756      */
11757     this.autoRefreshProcId = null;
11758     /**
11759      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11760      * @type Function
11761      */
11762     this.refreshDelegate = this.refresh.createDelegate(this);
11763     /**
11764      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11765      * @type Function
11766      */
11767     this.updateDelegate = this.update.createDelegate(this);
11768     /**
11769      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11770      * @type Function
11771      */
11772     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11773     /**
11774      * @private
11775      */
11776     this.successDelegate = this.processSuccess.createDelegate(this);
11777     /**
11778      * @private
11779      */
11780     this.failureDelegate = this.processFailure.createDelegate(this);
11781
11782     if(!this.renderer){
11783      /**
11784       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11785       */
11786     this.renderer = new Roo.UpdateManager.BasicRenderer();
11787     }
11788     
11789     Roo.UpdateManager.superclass.constructor.call(this);
11790 };
11791
11792 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11793     /**
11794      * Get the Element this UpdateManager is bound to
11795      * @return {Roo.Element} The element
11796      */
11797     getEl : function(){
11798         return this.el;
11799     },
11800     /**
11801      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11802      * @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:
11803 <pre><code>
11804 um.update({<br/>
11805     url: "your-url.php",<br/>
11806     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11807     callback: yourFunction,<br/>
11808     scope: yourObject, //(optional scope)  <br/>
11809     discardUrl: false, <br/>
11810     nocache: false,<br/>
11811     text: "Loading...",<br/>
11812     timeout: 30,<br/>
11813     scripts: false<br/>
11814 });
11815 </code></pre>
11816      * The only required property is url. The optional properties nocache, text and scripts
11817      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11818      * @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}
11819      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11820      * @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.
11821      */
11822     update : function(url, params, callback, discardUrl){
11823         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11824             var method = this.method,
11825                 cfg;
11826             if(typeof url == "object"){ // must be config object
11827                 cfg = url;
11828                 url = cfg.url;
11829                 params = params || cfg.params;
11830                 callback = callback || cfg.callback;
11831                 discardUrl = discardUrl || cfg.discardUrl;
11832                 if(callback && cfg.scope){
11833                     callback = callback.createDelegate(cfg.scope);
11834                 }
11835                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11836                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11837                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11838                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11839                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11840             }
11841             this.showLoading();
11842             if(!discardUrl){
11843                 this.defaultUrl = url;
11844             }
11845             if(typeof url == "function"){
11846                 url = url.call(this);
11847             }
11848
11849             method = method || (params ? "POST" : "GET");
11850             if(method == "GET"){
11851                 url = this.prepareUrl(url);
11852             }
11853
11854             var o = Roo.apply(cfg ||{}, {
11855                 url : url,
11856                 params: params,
11857                 success: this.successDelegate,
11858                 failure: this.failureDelegate,
11859                 callback: undefined,
11860                 timeout: (this.timeout*1000),
11861                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11862             });
11863             Roo.log("updated manager called with timeout of " + o.timeout);
11864             this.transaction = Roo.Ajax.request(o);
11865         }
11866     },
11867
11868     /**
11869      * 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.
11870      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11871      * @param {String/HTMLElement} form The form Id or form element
11872      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11873      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11874      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11875      */
11876     formUpdate : function(form, url, reset, callback){
11877         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11878             if(typeof url == "function"){
11879                 url = url.call(this);
11880             }
11881             form = Roo.getDom(form);
11882             this.transaction = Roo.Ajax.request({
11883                 form: form,
11884                 url:url,
11885                 success: this.successDelegate,
11886                 failure: this.failureDelegate,
11887                 timeout: (this.timeout*1000),
11888                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11889             });
11890             this.showLoading.defer(1, this);
11891         }
11892     },
11893
11894     /**
11895      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11896      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11897      */
11898     refresh : function(callback){
11899         if(this.defaultUrl == null){
11900             return;
11901         }
11902         this.update(this.defaultUrl, null, callback, true);
11903     },
11904
11905     /**
11906      * Set this element to auto refresh.
11907      * @param {Number} interval How often to update (in seconds).
11908      * @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)
11909      * @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}
11910      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11911      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11912      */
11913     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11914         if(refreshNow){
11915             this.update(url || this.defaultUrl, params, callback, true);
11916         }
11917         if(this.autoRefreshProcId){
11918             clearInterval(this.autoRefreshProcId);
11919         }
11920         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11921     },
11922
11923     /**
11924      * Stop auto refresh on this element.
11925      */
11926      stopAutoRefresh : function(){
11927         if(this.autoRefreshProcId){
11928             clearInterval(this.autoRefreshProcId);
11929             delete this.autoRefreshProcId;
11930         }
11931     },
11932
11933     isAutoRefreshing : function(){
11934        return this.autoRefreshProcId ? true : false;
11935     },
11936     /**
11937      * Called to update the element to "Loading" state. Override to perform custom action.
11938      */
11939     showLoading : function(){
11940         if(this.showLoadIndicator){
11941             this.el.update(this.indicatorText);
11942         }
11943     },
11944
11945     /**
11946      * Adds unique parameter to query string if disableCaching = true
11947      * @private
11948      */
11949     prepareUrl : function(url){
11950         if(this.disableCaching){
11951             var append = "_dc=" + (new Date().getTime());
11952             if(url.indexOf("?") !== -1){
11953                 url += "&" + append;
11954             }else{
11955                 url += "?" + append;
11956             }
11957         }
11958         return url;
11959     },
11960
11961     /**
11962      * @private
11963      */
11964     processSuccess : function(response){
11965         this.transaction = null;
11966         if(response.argument.form && response.argument.reset){
11967             try{ // put in try/catch since some older FF releases had problems with this
11968                 response.argument.form.reset();
11969             }catch(e){}
11970         }
11971         if(this.loadScripts){
11972             this.renderer.render(this.el, response, this,
11973                 this.updateComplete.createDelegate(this, [response]));
11974         }else{
11975             this.renderer.render(this.el, response, this);
11976             this.updateComplete(response);
11977         }
11978     },
11979
11980     updateComplete : function(response){
11981         this.fireEvent("update", this.el, response);
11982         if(typeof response.argument.callback == "function"){
11983             response.argument.callback(this.el, true, response);
11984         }
11985     },
11986
11987     /**
11988      * @private
11989      */
11990     processFailure : function(response){
11991         this.transaction = null;
11992         this.fireEvent("failure", this.el, response);
11993         if(typeof response.argument.callback == "function"){
11994             response.argument.callback(this.el, false, response);
11995         }
11996     },
11997
11998     /**
11999      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12000      * @param {Object} renderer The object implementing the render() method
12001      */
12002     setRenderer : function(renderer){
12003         this.renderer = renderer;
12004     },
12005
12006     getRenderer : function(){
12007        return this.renderer;
12008     },
12009
12010     /**
12011      * Set the defaultUrl used for updates
12012      * @param {String/Function} defaultUrl The url or a function to call to get the url
12013      */
12014     setDefaultUrl : function(defaultUrl){
12015         this.defaultUrl = defaultUrl;
12016     },
12017
12018     /**
12019      * Aborts the executing transaction
12020      */
12021     abort : function(){
12022         if(this.transaction){
12023             Roo.Ajax.abort(this.transaction);
12024         }
12025     },
12026
12027     /**
12028      * Returns true if an update is in progress
12029      * @return {Boolean}
12030      */
12031     isUpdating : function(){
12032         if(this.transaction){
12033             return Roo.Ajax.isLoading(this.transaction);
12034         }
12035         return false;
12036     }
12037 });
12038
12039 /**
12040  * @class Roo.UpdateManager.defaults
12041  * @static (not really - but it helps the doc tool)
12042  * The defaults collection enables customizing the default properties of UpdateManager
12043  */
12044    Roo.UpdateManager.defaults = {
12045        /**
12046          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12047          * @type Number
12048          */
12049          timeout : 30,
12050
12051          /**
12052          * True to process scripts by default (Defaults to false).
12053          * @type Boolean
12054          */
12055         loadScripts : false,
12056
12057         /**
12058         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12059         * @type String
12060         */
12061         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12062         /**
12063          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12064          * @type Boolean
12065          */
12066         disableCaching : false,
12067         /**
12068          * Whether to show indicatorText when loading (Defaults to true).
12069          * @type Boolean
12070          */
12071         showLoadIndicator : true,
12072         /**
12073          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12074          * @type String
12075          */
12076         indicatorText : '<div class="loading-indicator">Loading...</div>'
12077    };
12078
12079 /**
12080  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12081  *Usage:
12082  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12083  * @param {String/HTMLElement/Roo.Element} el The element to update
12084  * @param {String} url The url
12085  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12086  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12087  * @static
12088  * @deprecated
12089  * @member Roo.UpdateManager
12090  */
12091 Roo.UpdateManager.updateElement = function(el, url, params, options){
12092     var um = Roo.get(el, true).getUpdateManager();
12093     Roo.apply(um, options);
12094     um.update(url, params, options ? options.callback : null);
12095 };
12096 // alias for backwards compat
12097 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12098 /**
12099  * @class Roo.UpdateManager.BasicRenderer
12100  * Default Content renderer. Updates the elements innerHTML with the responseText.
12101  */
12102 Roo.UpdateManager.BasicRenderer = function(){};
12103
12104 Roo.UpdateManager.BasicRenderer.prototype = {
12105     /**
12106      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12107      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12108      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12109      * @param {Roo.Element} el The element being rendered
12110      * @param {Object} response The YUI Connect response object
12111      * @param {UpdateManager} updateManager The calling update manager
12112      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12113      */
12114      render : function(el, response, updateManager, callback){
12115         el.update(response.responseText, updateManager.loadScripts, callback);
12116     }
12117 };
12118 /*
12119  * Based on:
12120  * Roo JS
12121  * (c)) Alan Knowles
12122  * Licence : LGPL
12123  */
12124
12125
12126 /**
12127  * @class Roo.DomTemplate
12128  * @extends Roo.Template
12129  * An effort at a dom based template engine..
12130  *
12131  * Similar to XTemplate, except it uses dom parsing to create the template..
12132  *
12133  * Supported features:
12134  *
12135  *  Tags:
12136
12137 <pre><code>
12138       {a_variable} - output encoded.
12139       {a_variable.format:("Y-m-d")} - call a method on the variable
12140       {a_variable:raw} - unencoded output
12141       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12142       {a_variable:this.method_on_template(...)} - call a method on the template object.
12143  
12144 </code></pre>
12145  *  The tpl tag:
12146 <pre><code>
12147         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12148         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12149         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12150         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12151   
12152 </code></pre>
12153  *      
12154  */
12155 Roo.DomTemplate = function()
12156 {
12157      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12158      if (this.html) {
12159         this.compile();
12160      }
12161 };
12162
12163
12164 Roo.extend(Roo.DomTemplate, Roo.Template, {
12165     /**
12166      * id counter for sub templates.
12167      */
12168     id : 0,
12169     /**
12170      * flag to indicate if dom parser is inside a pre,
12171      * it will strip whitespace if not.
12172      */
12173     inPre : false,
12174     
12175     /**
12176      * The various sub templates
12177      */
12178     tpls : false,
12179     
12180     
12181     
12182     /**
12183      *
12184      * basic tag replacing syntax
12185      * WORD:WORD()
12186      *
12187      * // you can fake an object call by doing this
12188      *  x.t:(test,tesT) 
12189      * 
12190      */
12191     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12192     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12193     
12194     iterChild : function (node, method) {
12195         
12196         var oldPre = this.inPre;
12197         if (node.tagName == 'PRE') {
12198             this.inPre = true;
12199         }
12200         for( var i = 0; i < node.childNodes.length; i++) {
12201             method.call(this, node.childNodes[i]);
12202         }
12203         this.inPre = oldPre;
12204     },
12205     
12206     
12207     
12208     /**
12209      * compile the template
12210      *
12211      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12212      *
12213      */
12214     compile: function()
12215     {
12216         var s = this.html;
12217         
12218         // covert the html into DOM...
12219         var doc = false;
12220         var div =false;
12221         try {
12222             doc = document.implementation.createHTMLDocument("");
12223             doc.documentElement.innerHTML =   this.html  ;
12224             div = doc.documentElement;
12225         } catch (e) {
12226             // old IE... - nasty -- it causes all sorts of issues.. with
12227             // images getting pulled from server..
12228             div = document.createElement('div');
12229             div.innerHTML = this.html;
12230         }
12231         //doc.documentElement.innerHTML = htmlBody
12232          
12233         
12234         
12235         this.tpls = [];
12236         var _t = this;
12237         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12238         
12239         var tpls = this.tpls;
12240         
12241         // create a top level template from the snippet..
12242         
12243         //Roo.log(div.innerHTML);
12244         
12245         var tpl = {
12246             uid : 'master',
12247             id : this.id++,
12248             attr : false,
12249             value : false,
12250             body : div.innerHTML,
12251             
12252             forCall : false,
12253             execCall : false,
12254             dom : div,
12255             isTop : true
12256             
12257         };
12258         tpls.unshift(tpl);
12259         
12260         
12261         // compile them...
12262         this.tpls = [];
12263         Roo.each(tpls, function(tp){
12264             this.compileTpl(tp);
12265             this.tpls[tp.id] = tp;
12266         }, this);
12267         
12268         this.master = tpls[0];
12269         return this;
12270         
12271         
12272     },
12273     
12274     compileNode : function(node, istop) {
12275         // test for
12276         //Roo.log(node);
12277         
12278         
12279         // skip anything not a tag..
12280         if (node.nodeType != 1) {
12281             if (node.nodeType == 3 && !this.inPre) {
12282                 // reduce white space..
12283                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12284                 
12285             }
12286             return;
12287         }
12288         
12289         var tpl = {
12290             uid : false,
12291             id : false,
12292             attr : false,
12293             value : false,
12294             body : '',
12295             
12296             forCall : false,
12297             execCall : false,
12298             dom : false,
12299             isTop : istop
12300             
12301             
12302         };
12303         
12304         
12305         switch(true) {
12306             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12307             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12308             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12309             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12310             // no default..
12311         }
12312         
12313         
12314         if (!tpl.attr) {
12315             // just itterate children..
12316             this.iterChild(node,this.compileNode);
12317             return;
12318         }
12319         tpl.uid = this.id++;
12320         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12321         node.removeAttribute('roo-'+ tpl.attr);
12322         if (tpl.attr != 'name') {
12323             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12324             node.parentNode.replaceChild(placeholder,  node);
12325         } else {
12326             
12327             var placeholder =  document.createElement('span');
12328             placeholder.className = 'roo-tpl-' + tpl.value;
12329             node.parentNode.replaceChild(placeholder,  node);
12330         }
12331         
12332         // parent now sees '{domtplXXXX}
12333         this.iterChild(node,this.compileNode);
12334         
12335         // we should now have node body...
12336         var div = document.createElement('div');
12337         div.appendChild(node);
12338         tpl.dom = node;
12339         // this has the unfortunate side effect of converting tagged attributes
12340         // eg. href="{...}" into %7C...%7D
12341         // this has been fixed by searching for those combo's although it's a bit hacky..
12342         
12343         
12344         tpl.body = div.innerHTML;
12345         
12346         
12347          
12348         tpl.id = tpl.uid;
12349         switch(tpl.attr) {
12350             case 'for' :
12351                 switch (tpl.value) {
12352                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12353                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12354                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12355                 }
12356                 break;
12357             
12358             case 'exec':
12359                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12360                 break;
12361             
12362             case 'if':     
12363                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12364                 break;
12365             
12366             case 'name':
12367                 tpl.id  = tpl.value; // replace non characters???
12368                 break;
12369             
12370         }
12371         
12372         
12373         this.tpls.push(tpl);
12374         
12375         
12376         
12377     },
12378     
12379     
12380     
12381     
12382     /**
12383      * Compile a segment of the template into a 'sub-template'
12384      *
12385      * 
12386      * 
12387      *
12388      */
12389     compileTpl : function(tpl)
12390     {
12391         var fm = Roo.util.Format;
12392         var useF = this.disableFormats !== true;
12393         
12394         var sep = Roo.isGecko ? "+\n" : ",\n";
12395         
12396         var undef = function(str) {
12397             Roo.debug && Roo.log("Property not found :"  + str);
12398             return '';
12399         };
12400           
12401         //Roo.log(tpl.body);
12402         
12403         
12404         
12405         var fn = function(m, lbrace, name, format, args)
12406         {
12407             //Roo.log("ARGS");
12408             //Roo.log(arguments);
12409             args = args ? args.replace(/\\'/g,"'") : args;
12410             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12411             if (typeof(format) == 'undefined') {
12412                 format =  'htmlEncode'; 
12413             }
12414             if (format == 'raw' ) {
12415                 format = false;
12416             }
12417             
12418             if(name.substr(0, 6) == 'domtpl'){
12419                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12420             }
12421             
12422             // build an array of options to determine if value is undefined..
12423             
12424             // basically get 'xxxx.yyyy' then do
12425             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12426             //    (function () { Roo.log("Property not found"); return ''; })() :
12427             //    ......
12428             
12429             var udef_ar = [];
12430             var lookfor = '';
12431             Roo.each(name.split('.'), function(st) {
12432                 lookfor += (lookfor.length ? '.': '') + st;
12433                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12434             });
12435             
12436             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12437             
12438             
12439             if(format && useF){
12440                 
12441                 args = args ? ',' + args : "";
12442                  
12443                 if(format.substr(0, 5) != "this."){
12444                     format = "fm." + format + '(';
12445                 }else{
12446                     format = 'this.call("'+ format.substr(5) + '", ';
12447                     args = ", values";
12448                 }
12449                 
12450                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12451             }
12452              
12453             if (args && args.length) {
12454                 // called with xxyx.yuu:(test,test)
12455                 // change to ()
12456                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12457             }
12458             // raw.. - :raw modifier..
12459             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12460             
12461         };
12462         var body;
12463         // branched to use + in gecko and [].join() in others
12464         if(Roo.isGecko){
12465             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12466                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12467                     "';};};";
12468         }else{
12469             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12470             body.push(tpl.body.replace(/(\r\n|\n)/g,
12471                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12472             body.push("'].join('');};};");
12473             body = body.join('');
12474         }
12475         
12476         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12477        
12478         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12479         eval(body);
12480         
12481         return this;
12482     },
12483      
12484     /**
12485      * same as applyTemplate, except it's done to one of the subTemplates
12486      * when using named templates, you can do:
12487      *
12488      * var str = pl.applySubTemplate('your-name', values);
12489      *
12490      * 
12491      * @param {Number} id of the template
12492      * @param {Object} values to apply to template
12493      * @param {Object} parent (normaly the instance of this object)
12494      */
12495     applySubTemplate : function(id, values, parent)
12496     {
12497         
12498         
12499         var t = this.tpls[id];
12500         
12501         
12502         try { 
12503             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12504                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12505                 return '';
12506             }
12507         } catch(e) {
12508             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12509             Roo.log(values);
12510           
12511             return '';
12512         }
12513         try { 
12514             
12515             if(t.execCall && t.execCall.call(this, values, parent)){
12516                 return '';
12517             }
12518         } catch(e) {
12519             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12520             Roo.log(values);
12521             return '';
12522         }
12523         
12524         try {
12525             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12526             parent = t.target ? values : parent;
12527             if(t.forCall && vs instanceof Array){
12528                 var buf = [];
12529                 for(var i = 0, len = vs.length; i < len; i++){
12530                     try {
12531                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12532                     } catch (e) {
12533                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12534                         Roo.log(e.body);
12535                         //Roo.log(t.compiled);
12536                         Roo.log(vs[i]);
12537                     }   
12538                 }
12539                 return buf.join('');
12540             }
12541         } catch (e) {
12542             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12543             Roo.log(values);
12544             return '';
12545         }
12546         try {
12547             return t.compiled.call(this, vs, parent);
12548         } catch (e) {
12549             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12550             Roo.log(e.body);
12551             //Roo.log(t.compiled);
12552             Roo.log(values);
12553             return '';
12554         }
12555     },
12556
12557    
12558
12559     applyTemplate : function(values){
12560         return this.master.compiled.call(this, values, {});
12561         //var s = this.subs;
12562     },
12563
12564     apply : function(){
12565         return this.applyTemplate.apply(this, arguments);
12566     }
12567
12568  });
12569
12570 Roo.DomTemplate.from = function(el){
12571     el = Roo.getDom(el);
12572     return new Roo.Domtemplate(el.value || el.innerHTML);
12573 };/*
12574  * Based on:
12575  * Ext JS Library 1.1.1
12576  * Copyright(c) 2006-2007, Ext JS, LLC.
12577  *
12578  * Originally Released Under LGPL - original licence link has changed is not relivant.
12579  *
12580  * Fork - LGPL
12581  * <script type="text/javascript">
12582  */
12583
12584 /**
12585  * @class Roo.util.DelayedTask
12586  * Provides a convenient method of performing setTimeout where a new
12587  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12588  * You can use this class to buffer
12589  * the keypress events for a certain number of milliseconds, and perform only if they stop
12590  * for that amount of time.
12591  * @constructor The parameters to this constructor serve as defaults and are not required.
12592  * @param {Function} fn (optional) The default function to timeout
12593  * @param {Object} scope (optional) The default scope of that timeout
12594  * @param {Array} args (optional) The default Array of arguments
12595  */
12596 Roo.util.DelayedTask = function(fn, scope, args){
12597     var id = null, d, t;
12598
12599     var call = function(){
12600         var now = new Date().getTime();
12601         if(now - t >= d){
12602             clearInterval(id);
12603             id = null;
12604             fn.apply(scope, args || []);
12605         }
12606     };
12607     /**
12608      * Cancels any pending timeout and queues a new one
12609      * @param {Number} delay The milliseconds to delay
12610      * @param {Function} newFn (optional) Overrides function passed to constructor
12611      * @param {Object} newScope (optional) Overrides scope passed to constructor
12612      * @param {Array} newArgs (optional) Overrides args passed to constructor
12613      */
12614     this.delay = function(delay, newFn, newScope, newArgs){
12615         if(id && delay != d){
12616             this.cancel();
12617         }
12618         d = delay;
12619         t = new Date().getTime();
12620         fn = newFn || fn;
12621         scope = newScope || scope;
12622         args = newArgs || args;
12623         if(!id){
12624             id = setInterval(call, d);
12625         }
12626     };
12627
12628     /**
12629      * Cancel the last queued timeout
12630      */
12631     this.cancel = function(){
12632         if(id){
12633             clearInterval(id);
12634             id = null;
12635         }
12636     };
12637 };/*
12638  * Based on:
12639  * Ext JS Library 1.1.1
12640  * Copyright(c) 2006-2007, Ext JS, LLC.
12641  *
12642  * Originally Released Under LGPL - original licence link has changed is not relivant.
12643  *
12644  * Fork - LGPL
12645  * <script type="text/javascript">
12646  */
12647  
12648  
12649 Roo.util.TaskRunner = function(interval){
12650     interval = interval || 10;
12651     var tasks = [], removeQueue = [];
12652     var id = 0;
12653     var running = false;
12654
12655     var stopThread = function(){
12656         running = false;
12657         clearInterval(id);
12658         id = 0;
12659     };
12660
12661     var startThread = function(){
12662         if(!running){
12663             running = true;
12664             id = setInterval(runTasks, interval);
12665         }
12666     };
12667
12668     var removeTask = function(task){
12669         removeQueue.push(task);
12670         if(task.onStop){
12671             task.onStop();
12672         }
12673     };
12674
12675     var runTasks = function(){
12676         if(removeQueue.length > 0){
12677             for(var i = 0, len = removeQueue.length; i < len; i++){
12678                 tasks.remove(removeQueue[i]);
12679             }
12680             removeQueue = [];
12681             if(tasks.length < 1){
12682                 stopThread();
12683                 return;
12684             }
12685         }
12686         var now = new Date().getTime();
12687         for(var i = 0, len = tasks.length; i < len; ++i){
12688             var t = tasks[i];
12689             var itime = now - t.taskRunTime;
12690             if(t.interval <= itime){
12691                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12692                 t.taskRunTime = now;
12693                 if(rt === false || t.taskRunCount === t.repeat){
12694                     removeTask(t);
12695                     return;
12696                 }
12697             }
12698             if(t.duration && t.duration <= (now - t.taskStartTime)){
12699                 removeTask(t);
12700             }
12701         }
12702     };
12703
12704     /**
12705      * Queues a new task.
12706      * @param {Object} task
12707      */
12708     this.start = function(task){
12709         tasks.push(task);
12710         task.taskStartTime = new Date().getTime();
12711         task.taskRunTime = 0;
12712         task.taskRunCount = 0;
12713         startThread();
12714         return task;
12715     };
12716
12717     this.stop = function(task){
12718         removeTask(task);
12719         return task;
12720     };
12721
12722     this.stopAll = function(){
12723         stopThread();
12724         for(var i = 0, len = tasks.length; i < len; i++){
12725             if(tasks[i].onStop){
12726                 tasks[i].onStop();
12727             }
12728         }
12729         tasks = [];
12730         removeQueue = [];
12731     };
12732 };
12733
12734 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12735  * Based on:
12736  * Ext JS Library 1.1.1
12737  * Copyright(c) 2006-2007, Ext JS, LLC.
12738  *
12739  * Originally Released Under LGPL - original licence link has changed is not relivant.
12740  *
12741  * Fork - LGPL
12742  * <script type="text/javascript">
12743  */
12744
12745  
12746 /**
12747  * @class Roo.util.MixedCollection
12748  * @extends Roo.util.Observable
12749  * A Collection class that maintains both numeric indexes and keys and exposes events.
12750  * @constructor
12751  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12752  * collection (defaults to false)
12753  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12754  * and return the key value for that item.  This is used when available to look up the key on items that
12755  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12756  * equivalent to providing an implementation for the {@link #getKey} method.
12757  */
12758 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12759     this.items = [];
12760     this.map = {};
12761     this.keys = [];
12762     this.length = 0;
12763     this.addEvents({
12764         /**
12765          * @event clear
12766          * Fires when the collection is cleared.
12767          */
12768         "clear" : true,
12769         /**
12770          * @event add
12771          * Fires when an item is added to the collection.
12772          * @param {Number} index The index at which the item was added.
12773          * @param {Object} o The item added.
12774          * @param {String} key The key associated with the added item.
12775          */
12776         "add" : true,
12777         /**
12778          * @event replace
12779          * Fires when an item is replaced in the collection.
12780          * @param {String} key he key associated with the new added.
12781          * @param {Object} old The item being replaced.
12782          * @param {Object} new The new item.
12783          */
12784         "replace" : true,
12785         /**
12786          * @event remove
12787          * Fires when an item is removed from the collection.
12788          * @param {Object} o The item being removed.
12789          * @param {String} key (optional) The key associated with the removed item.
12790          */
12791         "remove" : true,
12792         "sort" : true
12793     });
12794     this.allowFunctions = allowFunctions === true;
12795     if(keyFn){
12796         this.getKey = keyFn;
12797     }
12798     Roo.util.MixedCollection.superclass.constructor.call(this);
12799 };
12800
12801 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12802     allowFunctions : false,
12803     
12804 /**
12805  * Adds an item to the collection.
12806  * @param {String} key The key to associate with the item
12807  * @param {Object} o The item to add.
12808  * @return {Object} The item added.
12809  */
12810     add : function(key, o){
12811         if(arguments.length == 1){
12812             o = arguments[0];
12813             key = this.getKey(o);
12814         }
12815         if(typeof key == "undefined" || key === null){
12816             this.length++;
12817             this.items.push(o);
12818             this.keys.push(null);
12819         }else{
12820             var old = this.map[key];
12821             if(old){
12822                 return this.replace(key, o);
12823             }
12824             this.length++;
12825             this.items.push(o);
12826             this.map[key] = o;
12827             this.keys.push(key);
12828         }
12829         this.fireEvent("add", this.length-1, o, key);
12830         return o;
12831     },
12832        
12833 /**
12834   * MixedCollection has a generic way to fetch keys if you implement getKey.
12835 <pre><code>
12836 // normal way
12837 var mc = new Roo.util.MixedCollection();
12838 mc.add(someEl.dom.id, someEl);
12839 mc.add(otherEl.dom.id, otherEl);
12840 //and so on
12841
12842 // using getKey
12843 var mc = new Roo.util.MixedCollection();
12844 mc.getKey = function(el){
12845    return el.dom.id;
12846 };
12847 mc.add(someEl);
12848 mc.add(otherEl);
12849
12850 // or via the constructor
12851 var mc = new Roo.util.MixedCollection(false, function(el){
12852    return el.dom.id;
12853 });
12854 mc.add(someEl);
12855 mc.add(otherEl);
12856 </code></pre>
12857  * @param o {Object} The item for which to find the key.
12858  * @return {Object} The key for the passed item.
12859  */
12860     getKey : function(o){
12861          return o.id; 
12862     },
12863    
12864 /**
12865  * Replaces an item in the collection.
12866  * @param {String} key The key associated with the item to replace, or the item to replace.
12867  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12868  * @return {Object}  The new item.
12869  */
12870     replace : function(key, o){
12871         if(arguments.length == 1){
12872             o = arguments[0];
12873             key = this.getKey(o);
12874         }
12875         var old = this.item(key);
12876         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12877              return this.add(key, o);
12878         }
12879         var index = this.indexOfKey(key);
12880         this.items[index] = o;
12881         this.map[key] = o;
12882         this.fireEvent("replace", key, old, o);
12883         return o;
12884     },
12885    
12886 /**
12887  * Adds all elements of an Array or an Object to the collection.
12888  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12889  * an Array of values, each of which are added to the collection.
12890  */
12891     addAll : function(objs){
12892         if(arguments.length > 1 || objs instanceof Array){
12893             var args = arguments.length > 1 ? arguments : objs;
12894             for(var i = 0, len = args.length; i < len; i++){
12895                 this.add(args[i]);
12896             }
12897         }else{
12898             for(var key in objs){
12899                 if(this.allowFunctions || typeof objs[key] != "function"){
12900                     this.add(key, objs[key]);
12901                 }
12902             }
12903         }
12904     },
12905    
12906 /**
12907  * Executes the specified function once for every item in the collection, passing each
12908  * item as the first and only parameter. returning false from the function will stop the iteration.
12909  * @param {Function} fn The function to execute for each item.
12910  * @param {Object} scope (optional) The scope in which to execute the function.
12911  */
12912     each : function(fn, scope){
12913         var items = [].concat(this.items); // each safe for removal
12914         for(var i = 0, len = items.length; i < len; i++){
12915             if(fn.call(scope || items[i], items[i], i, len) === false){
12916                 break;
12917             }
12918         }
12919     },
12920    
12921 /**
12922  * Executes the specified function once for every key in the collection, passing each
12923  * key, and its associated item as the first two parameters.
12924  * @param {Function} fn The function to execute for each item.
12925  * @param {Object} scope (optional) The scope in which to execute the function.
12926  */
12927     eachKey : function(fn, scope){
12928         for(var i = 0, len = this.keys.length; i < len; i++){
12929             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12930         }
12931     },
12932    
12933 /**
12934  * Returns the first item in the collection which elicits a true return value from the
12935  * passed selection function.
12936  * @param {Function} fn The selection function to execute for each item.
12937  * @param {Object} scope (optional) The scope in which to execute the function.
12938  * @return {Object} The first item in the collection which returned true from the selection function.
12939  */
12940     find : function(fn, scope){
12941         for(var i = 0, len = this.items.length; i < len; i++){
12942             if(fn.call(scope || window, this.items[i], this.keys[i])){
12943                 return this.items[i];
12944             }
12945         }
12946         return null;
12947     },
12948    
12949 /**
12950  * Inserts an item at the specified index in the collection.
12951  * @param {Number} index The index to insert the item at.
12952  * @param {String} key The key to associate with the new item, or the item itself.
12953  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12954  * @return {Object} The item inserted.
12955  */
12956     insert : function(index, key, o){
12957         if(arguments.length == 2){
12958             o = arguments[1];
12959             key = this.getKey(o);
12960         }
12961         if(index >= this.length){
12962             return this.add(key, o);
12963         }
12964         this.length++;
12965         this.items.splice(index, 0, o);
12966         if(typeof key != "undefined" && key != null){
12967             this.map[key] = o;
12968         }
12969         this.keys.splice(index, 0, key);
12970         this.fireEvent("add", index, o, key);
12971         return o;
12972     },
12973    
12974 /**
12975  * Removed an item from the collection.
12976  * @param {Object} o The item to remove.
12977  * @return {Object} The item removed.
12978  */
12979     remove : function(o){
12980         return this.removeAt(this.indexOf(o));
12981     },
12982    
12983 /**
12984  * Remove an item from a specified index in the collection.
12985  * @param {Number} index The index within the collection of the item to remove.
12986  */
12987     removeAt : function(index){
12988         if(index < this.length && index >= 0){
12989             this.length--;
12990             var o = this.items[index];
12991             this.items.splice(index, 1);
12992             var key = this.keys[index];
12993             if(typeof key != "undefined"){
12994                 delete this.map[key];
12995             }
12996             this.keys.splice(index, 1);
12997             this.fireEvent("remove", o, key);
12998         }
12999     },
13000    
13001 /**
13002  * Removed an item associated with the passed key fom the collection.
13003  * @param {String} key The key of the item to remove.
13004  */
13005     removeKey : function(key){
13006         return this.removeAt(this.indexOfKey(key));
13007     },
13008    
13009 /**
13010  * Returns the number of items in the collection.
13011  * @return {Number} the number of items in the collection.
13012  */
13013     getCount : function(){
13014         return this.length; 
13015     },
13016    
13017 /**
13018  * Returns index within the collection of the passed Object.
13019  * @param {Object} o The item to find the index of.
13020  * @return {Number} index of the item.
13021  */
13022     indexOf : function(o){
13023         if(!this.items.indexOf){
13024             for(var i = 0, len = this.items.length; i < len; i++){
13025                 if(this.items[i] == o) return i;
13026             }
13027             return -1;
13028         }else{
13029             return this.items.indexOf(o);
13030         }
13031     },
13032    
13033 /**
13034  * Returns index within the collection of the passed key.
13035  * @param {String} key The key to find the index of.
13036  * @return {Number} index of the key.
13037  */
13038     indexOfKey : function(key){
13039         if(!this.keys.indexOf){
13040             for(var i = 0, len = this.keys.length; i < len; i++){
13041                 if(this.keys[i] == key) return i;
13042             }
13043             return -1;
13044         }else{
13045             return this.keys.indexOf(key);
13046         }
13047     },
13048    
13049 /**
13050  * Returns the item associated with the passed key OR index. Key has priority over index.
13051  * @param {String/Number} key The key or index of the item.
13052  * @return {Object} The item associated with the passed key.
13053  */
13054     item : function(key){
13055         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13056         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13057     },
13058     
13059 /**
13060  * Returns the item at the specified index.
13061  * @param {Number} index The index of the item.
13062  * @return {Object}
13063  */
13064     itemAt : function(index){
13065         return this.items[index];
13066     },
13067     
13068 /**
13069  * Returns the item associated with the passed key.
13070  * @param {String/Number} key The key of the item.
13071  * @return {Object} The item associated with the passed key.
13072  */
13073     key : function(key){
13074         return this.map[key];
13075     },
13076    
13077 /**
13078  * Returns true if the collection contains the passed Object as an item.
13079  * @param {Object} o  The Object to look for in the collection.
13080  * @return {Boolean} True if the collection contains the Object as an item.
13081  */
13082     contains : function(o){
13083         return this.indexOf(o) != -1;
13084     },
13085    
13086 /**
13087  * Returns true if the collection contains the passed Object as a key.
13088  * @param {String} key The key to look for in the collection.
13089  * @return {Boolean} True if the collection contains the Object as a key.
13090  */
13091     containsKey : function(key){
13092         return typeof this.map[key] != "undefined";
13093     },
13094    
13095 /**
13096  * Removes all items from the collection.
13097  */
13098     clear : function(){
13099         this.length = 0;
13100         this.items = [];
13101         this.keys = [];
13102         this.map = {};
13103         this.fireEvent("clear");
13104     },
13105    
13106 /**
13107  * Returns the first item in the collection.
13108  * @return {Object} the first item in the collection..
13109  */
13110     first : function(){
13111         return this.items[0]; 
13112     },
13113    
13114 /**
13115  * Returns the last item in the collection.
13116  * @return {Object} the last item in the collection..
13117  */
13118     last : function(){
13119         return this.items[this.length-1];   
13120     },
13121     
13122     _sort : function(property, dir, fn){
13123         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13124         fn = fn || function(a, b){
13125             return a-b;
13126         };
13127         var c = [], k = this.keys, items = this.items;
13128         for(var i = 0, len = items.length; i < len; i++){
13129             c[c.length] = {key: k[i], value: items[i], index: i};
13130         }
13131         c.sort(function(a, b){
13132             var v = fn(a[property], b[property]) * dsc;
13133             if(v == 0){
13134                 v = (a.index < b.index ? -1 : 1);
13135             }
13136             return v;
13137         });
13138         for(var i = 0, len = c.length; i < len; i++){
13139             items[i] = c[i].value;
13140             k[i] = c[i].key;
13141         }
13142         this.fireEvent("sort", this);
13143     },
13144     
13145     /**
13146      * Sorts this collection with the passed comparison function
13147      * @param {String} direction (optional) "ASC" or "DESC"
13148      * @param {Function} fn (optional) comparison function
13149      */
13150     sort : function(dir, fn){
13151         this._sort("value", dir, fn);
13152     },
13153     
13154     /**
13155      * Sorts this collection by keys
13156      * @param {String} direction (optional) "ASC" or "DESC"
13157      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13158      */
13159     keySort : function(dir, fn){
13160         this._sort("key", dir, fn || function(a, b){
13161             return String(a).toUpperCase()-String(b).toUpperCase();
13162         });
13163     },
13164     
13165     /**
13166      * Returns a range of items in this collection
13167      * @param {Number} startIndex (optional) defaults to 0
13168      * @param {Number} endIndex (optional) default to the last item
13169      * @return {Array} An array of items
13170      */
13171     getRange : function(start, end){
13172         var items = this.items;
13173         if(items.length < 1){
13174             return [];
13175         }
13176         start = start || 0;
13177         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13178         var r = [];
13179         if(start <= end){
13180             for(var i = start; i <= end; i++) {
13181                     r[r.length] = items[i];
13182             }
13183         }else{
13184             for(var i = start; i >= end; i--) {
13185                     r[r.length] = items[i];
13186             }
13187         }
13188         return r;
13189     },
13190         
13191     /**
13192      * Filter the <i>objects</i> in this collection by a specific property. 
13193      * Returns a new collection that has been filtered.
13194      * @param {String} property A property on your objects
13195      * @param {String/RegExp} value Either string that the property values 
13196      * should start with or a RegExp to test against the property
13197      * @return {MixedCollection} The new filtered collection
13198      */
13199     filter : function(property, value){
13200         if(!value.exec){ // not a regex
13201             value = String(value);
13202             if(value.length == 0){
13203                 return this.clone();
13204             }
13205             value = new RegExp("^" + Roo.escapeRe(value), "i");
13206         }
13207         return this.filterBy(function(o){
13208             return o && value.test(o[property]);
13209         });
13210         },
13211     
13212     /**
13213      * Filter by a function. * Returns a new collection that has been filtered.
13214      * The passed function will be called with each 
13215      * object in the collection. If the function returns true, the value is included 
13216      * otherwise it is filtered.
13217      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13218      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13219      * @return {MixedCollection} The new filtered collection
13220      */
13221     filterBy : function(fn, scope){
13222         var r = new Roo.util.MixedCollection();
13223         r.getKey = this.getKey;
13224         var k = this.keys, it = this.items;
13225         for(var i = 0, len = it.length; i < len; i++){
13226             if(fn.call(scope||this, it[i], k[i])){
13227                                 r.add(k[i], it[i]);
13228                         }
13229         }
13230         return r;
13231     },
13232     
13233     /**
13234      * Creates a duplicate of this collection
13235      * @return {MixedCollection}
13236      */
13237     clone : function(){
13238         var r = new Roo.util.MixedCollection();
13239         var k = this.keys, it = this.items;
13240         for(var i = 0, len = it.length; i < len; i++){
13241             r.add(k[i], it[i]);
13242         }
13243         r.getKey = this.getKey;
13244         return r;
13245     }
13246 });
13247 /**
13248  * Returns the item associated with the passed key or index.
13249  * @method
13250  * @param {String/Number} key The key or index of the item.
13251  * @return {Object} The item associated with the passed key.
13252  */
13253 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13254  * Based on:
13255  * Ext JS Library 1.1.1
13256  * Copyright(c) 2006-2007, Ext JS, LLC.
13257  *
13258  * Originally Released Under LGPL - original licence link has changed is not relivant.
13259  *
13260  * Fork - LGPL
13261  * <script type="text/javascript">
13262  */
13263 /**
13264  * @class Roo.util.JSON
13265  * Modified version of Douglas Crockford"s json.js that doesn"t
13266  * mess with the Object prototype 
13267  * http://www.json.org/js.html
13268  * @singleton
13269  */
13270 Roo.util.JSON = new (function(){
13271     var useHasOwn = {}.hasOwnProperty ? true : false;
13272     
13273     // crashes Safari in some instances
13274     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13275     
13276     var pad = function(n) {
13277         return n < 10 ? "0" + n : n;
13278     };
13279     
13280     var m = {
13281         "\b": '\\b',
13282         "\t": '\\t',
13283         "\n": '\\n',
13284         "\f": '\\f',
13285         "\r": '\\r',
13286         '"' : '\\"',
13287         "\\": '\\\\'
13288     };
13289
13290     var encodeString = function(s){
13291         if (/["\\\x00-\x1f]/.test(s)) {
13292             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13293                 var c = m[b];
13294                 if(c){
13295                     return c;
13296                 }
13297                 c = b.charCodeAt();
13298                 return "\\u00" +
13299                     Math.floor(c / 16).toString(16) +
13300                     (c % 16).toString(16);
13301             }) + '"';
13302         }
13303         return '"' + s + '"';
13304     };
13305     
13306     var encodeArray = function(o){
13307         var a = ["["], b, i, l = o.length, v;
13308             for (i = 0; i < l; i += 1) {
13309                 v = o[i];
13310                 switch (typeof v) {
13311                     case "undefined":
13312                     case "function":
13313                     case "unknown":
13314                         break;
13315                     default:
13316                         if (b) {
13317                             a.push(',');
13318                         }
13319                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13320                         b = true;
13321                 }
13322             }
13323             a.push("]");
13324             return a.join("");
13325     };
13326     
13327     var encodeDate = function(o){
13328         return '"' + o.getFullYear() + "-" +
13329                 pad(o.getMonth() + 1) + "-" +
13330                 pad(o.getDate()) + "T" +
13331                 pad(o.getHours()) + ":" +
13332                 pad(o.getMinutes()) + ":" +
13333                 pad(o.getSeconds()) + '"';
13334     };
13335     
13336     /**
13337      * Encodes an Object, Array or other value
13338      * @param {Mixed} o The variable to encode
13339      * @return {String} The JSON string
13340      */
13341     this.encode = function(o)
13342     {
13343         // should this be extended to fully wrap stringify..
13344         
13345         if(typeof o == "undefined" || o === null){
13346             return "null";
13347         }else if(o instanceof Array){
13348             return encodeArray(o);
13349         }else if(o instanceof Date){
13350             return encodeDate(o);
13351         }else if(typeof o == "string"){
13352             return encodeString(o);
13353         }else if(typeof o == "number"){
13354             return isFinite(o) ? String(o) : "null";
13355         }else if(typeof o == "boolean"){
13356             return String(o);
13357         }else {
13358             var a = ["{"], b, i, v;
13359             for (i in o) {
13360                 if(!useHasOwn || o.hasOwnProperty(i)) {
13361                     v = o[i];
13362                     switch (typeof v) {
13363                     case "undefined":
13364                     case "function":
13365                     case "unknown":
13366                         break;
13367                     default:
13368                         if(b){
13369                             a.push(',');
13370                         }
13371                         a.push(this.encode(i), ":",
13372                                 v === null ? "null" : this.encode(v));
13373                         b = true;
13374                     }
13375                 }
13376             }
13377             a.push("}");
13378             return a.join("");
13379         }
13380     };
13381     
13382     /**
13383      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13384      * @param {String} json The JSON string
13385      * @return {Object} The resulting object
13386      */
13387     this.decode = function(json){
13388         
13389         return  /** eval:var:json */ eval("(" + json + ')');
13390     };
13391 })();
13392 /** 
13393  * Shorthand for {@link Roo.util.JSON#encode}
13394  * @member Roo encode 
13395  * @method */
13396 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13397 /** 
13398  * Shorthand for {@link Roo.util.JSON#decode}
13399  * @member Roo decode 
13400  * @method */
13401 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13402 /*
13403  * Based on:
13404  * Ext JS Library 1.1.1
13405  * Copyright(c) 2006-2007, Ext JS, LLC.
13406  *
13407  * Originally Released Under LGPL - original licence link has changed is not relivant.
13408  *
13409  * Fork - LGPL
13410  * <script type="text/javascript">
13411  */
13412  
13413 /**
13414  * @class Roo.util.Format
13415  * Reusable data formatting functions
13416  * @singleton
13417  */
13418 Roo.util.Format = function(){
13419     var trimRe = /^\s+|\s+$/g;
13420     return {
13421         /**
13422          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13423          * @param {String} value The string to truncate
13424          * @param {Number} length The maximum length to allow before truncating
13425          * @return {String} The converted text
13426          */
13427         ellipsis : function(value, len){
13428             if(value && value.length > len){
13429                 return value.substr(0, len-3)+"...";
13430             }
13431             return value;
13432         },
13433
13434         /**
13435          * Checks a reference and converts it to empty string if it is undefined
13436          * @param {Mixed} value Reference to check
13437          * @return {Mixed} Empty string if converted, otherwise the original value
13438          */
13439         undef : function(value){
13440             return typeof value != "undefined" ? value : "";
13441         },
13442
13443         /**
13444          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13445          * @param {String} value The string to encode
13446          * @return {String} The encoded text
13447          */
13448         htmlEncode : function(value){
13449             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13450         },
13451
13452         /**
13453          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13454          * @param {String} value The string to decode
13455          * @return {String} The decoded text
13456          */
13457         htmlDecode : function(value){
13458             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13459         },
13460
13461         /**
13462          * Trims any whitespace from either side of a string
13463          * @param {String} value The text to trim
13464          * @return {String} The trimmed text
13465          */
13466         trim : function(value){
13467             return String(value).replace(trimRe, "");
13468         },
13469
13470         /**
13471          * Returns a substring from within an original string
13472          * @param {String} value The original text
13473          * @param {Number} start The start index of the substring
13474          * @param {Number} length The length of the substring
13475          * @return {String} The substring
13476          */
13477         substr : function(value, start, length){
13478             return String(value).substr(start, length);
13479         },
13480
13481         /**
13482          * Converts a string to all lower case letters
13483          * @param {String} value The text to convert
13484          * @return {String} The converted text
13485          */
13486         lowercase : function(value){
13487             return String(value).toLowerCase();
13488         },
13489
13490         /**
13491          * Converts a string to all upper case letters
13492          * @param {String} value The text to convert
13493          * @return {String} The converted text
13494          */
13495         uppercase : function(value){
13496             return String(value).toUpperCase();
13497         },
13498
13499         /**
13500          * Converts the first character only of a string to upper case
13501          * @param {String} value The text to convert
13502          * @return {String} The converted text
13503          */
13504         capitalize : function(value){
13505             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13506         },
13507
13508         // private
13509         call : function(value, fn){
13510             if(arguments.length > 2){
13511                 var args = Array.prototype.slice.call(arguments, 2);
13512                 args.unshift(value);
13513                  
13514                 return /** eval:var:value */  eval(fn).apply(window, args);
13515             }else{
13516                 /** eval:var:value */
13517                 return /** eval:var:value */ eval(fn).call(window, value);
13518             }
13519         },
13520
13521        
13522         /**
13523          * safer version of Math.toFixed..??/
13524          * @param {Number/String} value The numeric value to format
13525          * @param {Number/String} value Decimal places 
13526          * @return {String} The formatted currency string
13527          */
13528         toFixed : function(v, n)
13529         {
13530             // why not use to fixed - precision is buggered???
13531             if (!n) {
13532                 return Math.round(v-0);
13533             }
13534             var fact = Math.pow(10,n+1);
13535             v = (Math.round((v-0)*fact))/fact;
13536             var z = (''+fact).substring(2);
13537             if (v == Math.floor(v)) {
13538                 return Math.floor(v) + '.' + z;
13539             }
13540             
13541             // now just padd decimals..
13542             var ps = String(v).split('.');
13543             var fd = (ps[1] + z);
13544             var r = fd.substring(0,n); 
13545             var rm = fd.substring(n); 
13546             if (rm < 5) {
13547                 return ps[0] + '.' + r;
13548             }
13549             r*=1; // turn it into a number;
13550             r++;
13551             if (String(r).length != n) {
13552                 ps[0]*=1;
13553                 ps[0]++;
13554                 r = String(r).substring(1); // chop the end off.
13555             }
13556             
13557             return ps[0] + '.' + r;
13558              
13559         },
13560         
13561         /**
13562          * Format a number as US currency
13563          * @param {Number/String} value The numeric value to format
13564          * @return {String} The formatted currency string
13565          */
13566         usMoney : function(v){
13567             return '$' + Roo.util.Format.number(v);
13568         },
13569         
13570         /**
13571          * Format a number
13572          * eventually this should probably emulate php's number_format
13573          * @param {Number/String} value The numeric value to format
13574          * @param {Number} decimals number of decimal places
13575          * @return {String} The formatted currency string
13576          */
13577         number : function(v,decimals)
13578         {
13579             // multiply and round.
13580             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13581             var mul = Math.pow(10, decimals);
13582             var zero = String(mul).substring(1);
13583             v = (Math.round((v-0)*mul))/mul;
13584             
13585             // if it's '0' number.. then
13586             
13587             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13588             v = String(v);
13589             var ps = v.split('.');
13590             var whole = ps[0];
13591             
13592             
13593             var r = /(\d+)(\d{3})/;
13594             // add comma's
13595             while (r.test(whole)) {
13596                 whole = whole.replace(r, '$1' + ',' + '$2');
13597             }
13598             
13599             
13600             var sub = ps[1] ?
13601                     // has decimals..
13602                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13603                     // does not have decimals
13604                     (decimals ? ('.' + zero) : '');
13605             
13606             
13607             return whole + sub ;
13608         },
13609         
13610         /**
13611          * Parse a value into a formatted date using the specified format pattern.
13612          * @param {Mixed} value The value to format
13613          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13614          * @return {String} The formatted date string
13615          */
13616         date : function(v, format){
13617             if(!v){
13618                 return "";
13619             }
13620             if(!(v instanceof Date)){
13621                 v = new Date(Date.parse(v));
13622             }
13623             return v.dateFormat(format || Roo.util.Format.defaults.date);
13624         },
13625
13626         /**
13627          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13628          * @param {String} format Any valid date format string
13629          * @return {Function} The date formatting function
13630          */
13631         dateRenderer : function(format){
13632             return function(v){
13633                 return Roo.util.Format.date(v, format);  
13634             };
13635         },
13636
13637         // private
13638         stripTagsRE : /<\/?[^>]+>/gi,
13639         
13640         /**
13641          * Strips all HTML tags
13642          * @param {Mixed} value The text from which to strip tags
13643          * @return {String} The stripped text
13644          */
13645         stripTags : function(v){
13646             return !v ? v : String(v).replace(this.stripTagsRE, "");
13647         }
13648     };
13649 }();
13650 Roo.util.Format.defaults = {
13651     date : 'd/M/Y'
13652 };/*
13653  * Based on:
13654  * Ext JS Library 1.1.1
13655  * Copyright(c) 2006-2007, Ext JS, LLC.
13656  *
13657  * Originally Released Under LGPL - original licence link has changed is not relivant.
13658  *
13659  * Fork - LGPL
13660  * <script type="text/javascript">
13661  */
13662
13663
13664  
13665
13666 /**
13667  * @class Roo.MasterTemplate
13668  * @extends Roo.Template
13669  * Provides a template that can have child templates. The syntax is:
13670 <pre><code>
13671 var t = new Roo.MasterTemplate(
13672         '&lt;select name="{name}"&gt;',
13673                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13674         '&lt;/select&gt;'
13675 );
13676 t.add('options', {value: 'foo', text: 'bar'});
13677 // or you can add multiple child elements in one shot
13678 t.addAll('options', [
13679     {value: 'foo', text: 'bar'},
13680     {value: 'foo2', text: 'bar2'},
13681     {value: 'foo3', text: 'bar3'}
13682 ]);
13683 // then append, applying the master template values
13684 t.append('my-form', {name: 'my-select'});
13685 </code></pre>
13686 * A name attribute for the child template is not required if you have only one child
13687 * template or you want to refer to them by index.
13688  */
13689 Roo.MasterTemplate = function(){
13690     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13691     this.originalHtml = this.html;
13692     var st = {};
13693     var m, re = this.subTemplateRe;
13694     re.lastIndex = 0;
13695     var subIndex = 0;
13696     while(m = re.exec(this.html)){
13697         var name = m[1], content = m[2];
13698         st[subIndex] = {
13699             name: name,
13700             index: subIndex,
13701             buffer: [],
13702             tpl : new Roo.Template(content)
13703         };
13704         if(name){
13705             st[name] = st[subIndex];
13706         }
13707         st[subIndex].tpl.compile();
13708         st[subIndex].tpl.call = this.call.createDelegate(this);
13709         subIndex++;
13710     }
13711     this.subCount = subIndex;
13712     this.subs = st;
13713 };
13714 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13715     /**
13716     * The regular expression used to match sub templates
13717     * @type RegExp
13718     * @property
13719     */
13720     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13721
13722     /**
13723      * Applies the passed values to a child template.
13724      * @param {String/Number} name (optional) The name or index of the child template
13725      * @param {Array/Object} values The values to be applied to the template
13726      * @return {MasterTemplate} this
13727      */
13728      add : function(name, values){
13729         if(arguments.length == 1){
13730             values = arguments[0];
13731             name = 0;
13732         }
13733         var s = this.subs[name];
13734         s.buffer[s.buffer.length] = s.tpl.apply(values);
13735         return this;
13736     },
13737
13738     /**
13739      * Applies all the passed values to a child template.
13740      * @param {String/Number} name (optional) The name or index of the child template
13741      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13742      * @param {Boolean} reset (optional) True to reset the template first
13743      * @return {MasterTemplate} this
13744      */
13745     fill : function(name, values, reset){
13746         var a = arguments;
13747         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13748             values = a[0];
13749             name = 0;
13750             reset = a[1];
13751         }
13752         if(reset){
13753             this.reset();
13754         }
13755         for(var i = 0, len = values.length; i < len; i++){
13756             this.add(name, values[i]);
13757         }
13758         return this;
13759     },
13760
13761     /**
13762      * Resets the template for reuse
13763      * @return {MasterTemplate} this
13764      */
13765      reset : function(){
13766         var s = this.subs;
13767         for(var i = 0; i < this.subCount; i++){
13768             s[i].buffer = [];
13769         }
13770         return this;
13771     },
13772
13773     applyTemplate : function(values){
13774         var s = this.subs;
13775         var replaceIndex = -1;
13776         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13777             return s[++replaceIndex].buffer.join("");
13778         });
13779         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13780     },
13781
13782     apply : function(){
13783         return this.applyTemplate.apply(this, arguments);
13784     },
13785
13786     compile : function(){return this;}
13787 });
13788
13789 /**
13790  * Alias for fill().
13791  * @method
13792  */
13793 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13794  /**
13795  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13796  * var tpl = Roo.MasterTemplate.from('element-id');
13797  * @param {String/HTMLElement} el
13798  * @param {Object} config
13799  * @static
13800  */
13801 Roo.MasterTemplate.from = function(el, config){
13802     el = Roo.getDom(el);
13803     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13804 };/*
13805  * Based on:
13806  * Ext JS Library 1.1.1
13807  * Copyright(c) 2006-2007, Ext JS, LLC.
13808  *
13809  * Originally Released Under LGPL - original licence link has changed is not relivant.
13810  *
13811  * Fork - LGPL
13812  * <script type="text/javascript">
13813  */
13814
13815  
13816 /**
13817  * @class Roo.util.CSS
13818  * Utility class for manipulating CSS rules
13819  * @singleton
13820  */
13821 Roo.util.CSS = function(){
13822         var rules = null;
13823         var doc = document;
13824
13825     var camelRe = /(-[a-z])/gi;
13826     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13827
13828    return {
13829    /**
13830     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13831     * tag and appended to the HEAD of the document.
13832     * @param {String|Object} cssText The text containing the css rules
13833     * @param {String} id An id to add to the stylesheet for later removal
13834     * @return {StyleSheet}
13835     */
13836     createStyleSheet : function(cssText, id){
13837         var ss;
13838         var head = doc.getElementsByTagName("head")[0];
13839         var nrules = doc.createElement("style");
13840         nrules.setAttribute("type", "text/css");
13841         if(id){
13842             nrules.setAttribute("id", id);
13843         }
13844         if (typeof(cssText) != 'string') {
13845             // support object maps..
13846             // not sure if this a good idea.. 
13847             // perhaps it should be merged with the general css handling
13848             // and handle js style props.
13849             var cssTextNew = [];
13850             for(var n in cssText) {
13851                 var citems = [];
13852                 for(var k in cssText[n]) {
13853                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13854                 }
13855                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13856                 
13857             }
13858             cssText = cssTextNew.join("\n");
13859             
13860         }
13861        
13862        
13863        if(Roo.isIE){
13864            head.appendChild(nrules);
13865            ss = nrules.styleSheet;
13866            ss.cssText = cssText;
13867        }else{
13868            try{
13869                 nrules.appendChild(doc.createTextNode(cssText));
13870            }catch(e){
13871                nrules.cssText = cssText; 
13872            }
13873            head.appendChild(nrules);
13874            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13875        }
13876        this.cacheStyleSheet(ss);
13877        return ss;
13878    },
13879
13880    /**
13881     * Removes a style or link tag by id
13882     * @param {String} id The id of the tag
13883     */
13884    removeStyleSheet : function(id){
13885        var existing = doc.getElementById(id);
13886        if(existing){
13887            existing.parentNode.removeChild(existing);
13888        }
13889    },
13890
13891    /**
13892     * Dynamically swaps an existing stylesheet reference for a new one
13893     * @param {String} id The id of an existing link tag to remove
13894     * @param {String} url The href of the new stylesheet to include
13895     */
13896    swapStyleSheet : function(id, url){
13897        this.removeStyleSheet(id);
13898        var ss = doc.createElement("link");
13899        ss.setAttribute("rel", "stylesheet");
13900        ss.setAttribute("type", "text/css");
13901        ss.setAttribute("id", id);
13902        ss.setAttribute("href", url);
13903        doc.getElementsByTagName("head")[0].appendChild(ss);
13904    },
13905    
13906    /**
13907     * Refresh the rule cache if you have dynamically added stylesheets
13908     * @return {Object} An object (hash) of rules indexed by selector
13909     */
13910    refreshCache : function(){
13911        return this.getRules(true);
13912    },
13913
13914    // private
13915    cacheStyleSheet : function(stylesheet){
13916        if(!rules){
13917            rules = {};
13918        }
13919        try{// try catch for cross domain access issue
13920            var ssRules = stylesheet.cssRules || stylesheet.rules;
13921            for(var j = ssRules.length-1; j >= 0; --j){
13922                rules[ssRules[j].selectorText] = ssRules[j];
13923            }
13924        }catch(e){}
13925    },
13926    
13927    /**
13928     * Gets all css rules for the document
13929     * @param {Boolean} refreshCache true to refresh the internal cache
13930     * @return {Object} An object (hash) of rules indexed by selector
13931     */
13932    getRules : function(refreshCache){
13933                 if(rules == null || refreshCache){
13934                         rules = {};
13935                         var ds = doc.styleSheets;
13936                         for(var i =0, len = ds.length; i < len; i++){
13937                             try{
13938                         this.cacheStyleSheet(ds[i]);
13939                     }catch(e){} 
13940                 }
13941                 }
13942                 return rules;
13943         },
13944         
13945         /**
13946     * Gets an an individual CSS rule by selector(s)
13947     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13948     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13949     * @return {CSSRule} The CSS rule or null if one is not found
13950     */
13951    getRule : function(selector, refreshCache){
13952                 var rs = this.getRules(refreshCache);
13953                 if(!(selector instanceof Array)){
13954                     return rs[selector];
13955                 }
13956                 for(var i = 0; i < selector.length; i++){
13957                         if(rs[selector[i]]){
13958                                 return rs[selector[i]];
13959                         }
13960                 }
13961                 return null;
13962         },
13963         
13964         
13965         /**
13966     * Updates a rule property
13967     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13968     * @param {String} property The css property
13969     * @param {String} value The new value for the property
13970     * @return {Boolean} true If a rule was found and updated
13971     */
13972    updateRule : function(selector, property, value){
13973                 if(!(selector instanceof Array)){
13974                         var rule = this.getRule(selector);
13975                         if(rule){
13976                                 rule.style[property.replace(camelRe, camelFn)] = value;
13977                                 return true;
13978                         }
13979                 }else{
13980                         for(var i = 0; i < selector.length; i++){
13981                                 if(this.updateRule(selector[i], property, value)){
13982                                         return true;
13983                                 }
13984                         }
13985                 }
13986                 return false;
13987         }
13988    };   
13989 }();/*
13990  * Based on:
13991  * Ext JS Library 1.1.1
13992  * Copyright(c) 2006-2007, Ext JS, LLC.
13993  *
13994  * Originally Released Under LGPL - original licence link has changed is not relivant.
13995  *
13996  * Fork - LGPL
13997  * <script type="text/javascript">
13998  */
13999
14000  
14001
14002 /**
14003  * @class Roo.util.ClickRepeater
14004  * @extends Roo.util.Observable
14005  * 
14006  * A wrapper class which can be applied to any element. Fires a "click" event while the
14007  * mouse is pressed. The interval between firings may be specified in the config but
14008  * defaults to 10 milliseconds.
14009  * 
14010  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14011  * 
14012  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14013  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14014  * Similar to an autorepeat key delay.
14015  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14016  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14017  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14018  *           "interval" and "delay" are ignored. "immediate" is honored.
14019  * @cfg {Boolean} preventDefault True to prevent the default click event
14020  * @cfg {Boolean} stopDefault True to stop the default click event
14021  * 
14022  * @history
14023  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14024  *     2007-02-02 jvs Renamed to ClickRepeater
14025  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14026  *
14027  *  @constructor
14028  * @param {String/HTMLElement/Element} el The element to listen on
14029  * @param {Object} config
14030  **/
14031 Roo.util.ClickRepeater = function(el, config)
14032 {
14033     this.el = Roo.get(el);
14034     this.el.unselectable();
14035
14036     Roo.apply(this, config);
14037
14038     this.addEvents({
14039     /**
14040      * @event mousedown
14041      * Fires when the mouse button is depressed.
14042      * @param {Roo.util.ClickRepeater} this
14043      */
14044         "mousedown" : true,
14045     /**
14046      * @event click
14047      * Fires on a specified interval during the time the element is pressed.
14048      * @param {Roo.util.ClickRepeater} this
14049      */
14050         "click" : true,
14051     /**
14052      * @event mouseup
14053      * Fires when the mouse key is released.
14054      * @param {Roo.util.ClickRepeater} this
14055      */
14056         "mouseup" : true
14057     });
14058
14059     this.el.on("mousedown", this.handleMouseDown, this);
14060     if(this.preventDefault || this.stopDefault){
14061         this.el.on("click", function(e){
14062             if(this.preventDefault){
14063                 e.preventDefault();
14064             }
14065             if(this.stopDefault){
14066                 e.stopEvent();
14067             }
14068         }, this);
14069     }
14070
14071     // allow inline handler
14072     if(this.handler){
14073         this.on("click", this.handler,  this.scope || this);
14074     }
14075
14076     Roo.util.ClickRepeater.superclass.constructor.call(this);
14077 };
14078
14079 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14080     interval : 20,
14081     delay: 250,
14082     preventDefault : true,
14083     stopDefault : false,
14084     timer : 0,
14085
14086     // private
14087     handleMouseDown : function(){
14088         clearTimeout(this.timer);
14089         this.el.blur();
14090         if(this.pressClass){
14091             this.el.addClass(this.pressClass);
14092         }
14093         this.mousedownTime = new Date();
14094
14095         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14096         this.el.on("mouseout", this.handleMouseOut, this);
14097
14098         this.fireEvent("mousedown", this);
14099         this.fireEvent("click", this);
14100         
14101         this.timer = this.click.defer(this.delay || this.interval, this);
14102     },
14103
14104     // private
14105     click : function(){
14106         this.fireEvent("click", this);
14107         this.timer = this.click.defer(this.getInterval(), this);
14108     },
14109
14110     // private
14111     getInterval: function(){
14112         if(!this.accelerate){
14113             return this.interval;
14114         }
14115         var pressTime = this.mousedownTime.getElapsed();
14116         if(pressTime < 500){
14117             return 400;
14118         }else if(pressTime < 1700){
14119             return 320;
14120         }else if(pressTime < 2600){
14121             return 250;
14122         }else if(pressTime < 3500){
14123             return 180;
14124         }else if(pressTime < 4400){
14125             return 140;
14126         }else if(pressTime < 5300){
14127             return 80;
14128         }else if(pressTime < 6200){
14129             return 50;
14130         }else{
14131             return 10;
14132         }
14133     },
14134
14135     // private
14136     handleMouseOut : function(){
14137         clearTimeout(this.timer);
14138         if(this.pressClass){
14139             this.el.removeClass(this.pressClass);
14140         }
14141         this.el.on("mouseover", this.handleMouseReturn, this);
14142     },
14143
14144     // private
14145     handleMouseReturn : function(){
14146         this.el.un("mouseover", this.handleMouseReturn);
14147         if(this.pressClass){
14148             this.el.addClass(this.pressClass);
14149         }
14150         this.click();
14151     },
14152
14153     // private
14154     handleMouseUp : function(){
14155         clearTimeout(this.timer);
14156         this.el.un("mouseover", this.handleMouseReturn);
14157         this.el.un("mouseout", this.handleMouseOut);
14158         Roo.get(document).un("mouseup", this.handleMouseUp);
14159         this.el.removeClass(this.pressClass);
14160         this.fireEvent("mouseup", this);
14161     }
14162 });/*
14163  * Based on:
14164  * Ext JS Library 1.1.1
14165  * Copyright(c) 2006-2007, Ext JS, LLC.
14166  *
14167  * Originally Released Under LGPL - original licence link has changed is not relivant.
14168  *
14169  * Fork - LGPL
14170  * <script type="text/javascript">
14171  */
14172
14173  
14174 /**
14175  * @class Roo.KeyNav
14176  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14177  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14178  * way to implement custom navigation schemes for any UI component.</p>
14179  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14180  * pageUp, pageDown, del, home, end.  Usage:</p>
14181  <pre><code>
14182 var nav = new Roo.KeyNav("my-element", {
14183     "left" : function(e){
14184         this.moveLeft(e.ctrlKey);
14185     },
14186     "right" : function(e){
14187         this.moveRight(e.ctrlKey);
14188     },
14189     "enter" : function(e){
14190         this.save();
14191     },
14192     scope : this
14193 });
14194 </code></pre>
14195  * @constructor
14196  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14197  * @param {Object} config The config
14198  */
14199 Roo.KeyNav = function(el, config){
14200     this.el = Roo.get(el);
14201     Roo.apply(this, config);
14202     if(!this.disabled){
14203         this.disabled = true;
14204         this.enable();
14205     }
14206 };
14207
14208 Roo.KeyNav.prototype = {
14209     /**
14210      * @cfg {Boolean} disabled
14211      * True to disable this KeyNav instance (defaults to false)
14212      */
14213     disabled : false,
14214     /**
14215      * @cfg {String} defaultEventAction
14216      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14217      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14218      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14219      */
14220     defaultEventAction: "stopEvent",
14221     /**
14222      * @cfg {Boolean} forceKeyDown
14223      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14224      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14225      * handle keydown instead of keypress.
14226      */
14227     forceKeyDown : false,
14228
14229     // private
14230     prepareEvent : function(e){
14231         var k = e.getKey();
14232         var h = this.keyToHandler[k];
14233         //if(h && this[h]){
14234         //    e.stopPropagation();
14235         //}
14236         if(Roo.isSafari && h && k >= 37 && k <= 40){
14237             e.stopEvent();
14238         }
14239     },
14240
14241     // private
14242     relay : function(e){
14243         var k = e.getKey();
14244         var h = this.keyToHandler[k];
14245         if(h && this[h]){
14246             if(this.doRelay(e, this[h], h) !== true){
14247                 e[this.defaultEventAction]();
14248             }
14249         }
14250     },
14251
14252     // private
14253     doRelay : function(e, h, hname){
14254         return h.call(this.scope || this, e);
14255     },
14256
14257     // possible handlers
14258     enter : false,
14259     left : false,
14260     right : false,
14261     up : false,
14262     down : false,
14263     tab : false,
14264     esc : false,
14265     pageUp : false,
14266     pageDown : false,
14267     del : false,
14268     home : false,
14269     end : false,
14270
14271     // quick lookup hash
14272     keyToHandler : {
14273         37 : "left",
14274         39 : "right",
14275         38 : "up",
14276         40 : "down",
14277         33 : "pageUp",
14278         34 : "pageDown",
14279         46 : "del",
14280         36 : "home",
14281         35 : "end",
14282         13 : "enter",
14283         27 : "esc",
14284         9  : "tab"
14285     },
14286
14287         /**
14288          * Enable this KeyNav
14289          */
14290         enable: function(){
14291                 if(this.disabled){
14292             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14293             // the EventObject will normalize Safari automatically
14294             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14295                 this.el.on("keydown", this.relay,  this);
14296             }else{
14297                 this.el.on("keydown", this.prepareEvent,  this);
14298                 this.el.on("keypress", this.relay,  this);
14299             }
14300                     this.disabled = false;
14301                 }
14302         },
14303
14304         /**
14305          * Disable this KeyNav
14306          */
14307         disable: function(){
14308                 if(!this.disabled){
14309                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14310                 this.el.un("keydown", this.relay);
14311             }else{
14312                 this.el.un("keydown", this.prepareEvent);
14313                 this.el.un("keypress", this.relay);
14314             }
14315                     this.disabled = true;
14316                 }
14317         }
14318 };/*
14319  * Based on:
14320  * Ext JS Library 1.1.1
14321  * Copyright(c) 2006-2007, Ext JS, LLC.
14322  *
14323  * Originally Released Under LGPL - original licence link has changed is not relivant.
14324  *
14325  * Fork - LGPL
14326  * <script type="text/javascript">
14327  */
14328
14329  
14330 /**
14331  * @class Roo.KeyMap
14332  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14333  * The constructor accepts the same config object as defined by {@link #addBinding}.
14334  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14335  * combination it will call the function with this signature (if the match is a multi-key
14336  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14337  * A KeyMap can also handle a string representation of keys.<br />
14338  * Usage:
14339  <pre><code>
14340 // map one key by key code
14341 var map = new Roo.KeyMap("my-element", {
14342     key: 13, // or Roo.EventObject.ENTER
14343     fn: myHandler,
14344     scope: myObject
14345 });
14346
14347 // map multiple keys to one action by string
14348 var map = new Roo.KeyMap("my-element", {
14349     key: "a\r\n\t",
14350     fn: myHandler,
14351     scope: myObject
14352 });
14353
14354 // map multiple keys to multiple actions by strings and array of codes
14355 var map = new Roo.KeyMap("my-element", [
14356     {
14357         key: [10,13],
14358         fn: function(){ alert("Return was pressed"); }
14359     }, {
14360         key: "abc",
14361         fn: function(){ alert('a, b or c was pressed'); }
14362     }, {
14363         key: "\t",
14364         ctrl:true,
14365         shift:true,
14366         fn: function(){ alert('Control + shift + tab was pressed.'); }
14367     }
14368 ]);
14369 </code></pre>
14370  * <b>Note: A KeyMap starts enabled</b>
14371  * @constructor
14372  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14373  * @param {Object} config The config (see {@link #addBinding})
14374  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14375  */
14376 Roo.KeyMap = function(el, config, eventName){
14377     this.el  = Roo.get(el);
14378     this.eventName = eventName || "keydown";
14379     this.bindings = [];
14380     if(config){
14381         this.addBinding(config);
14382     }
14383     this.enable();
14384 };
14385
14386 Roo.KeyMap.prototype = {
14387     /**
14388      * True to stop the event from bubbling and prevent the default browser action if the
14389      * key was handled by the KeyMap (defaults to false)
14390      * @type Boolean
14391      */
14392     stopEvent : false,
14393
14394     /**
14395      * Add a new binding to this KeyMap. The following config object properties are supported:
14396      * <pre>
14397 Property    Type             Description
14398 ----------  ---------------  ----------------------------------------------------------------------
14399 key         String/Array     A single keycode or an array of keycodes to handle
14400 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14401 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14402 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14403 fn          Function         The function to call when KeyMap finds the expected key combination
14404 scope       Object           The scope of the callback function
14405 </pre>
14406      *
14407      * Usage:
14408      * <pre><code>
14409 // Create a KeyMap
14410 var map = new Roo.KeyMap(document, {
14411     key: Roo.EventObject.ENTER,
14412     fn: handleKey,
14413     scope: this
14414 });
14415
14416 //Add a new binding to the existing KeyMap later
14417 map.addBinding({
14418     key: 'abc',
14419     shift: true,
14420     fn: handleKey,
14421     scope: this
14422 });
14423 </code></pre>
14424      * @param {Object/Array} config A single KeyMap config or an array of configs
14425      */
14426         addBinding : function(config){
14427         if(config instanceof Array){
14428             for(var i = 0, len = config.length; i < len; i++){
14429                 this.addBinding(config[i]);
14430             }
14431             return;
14432         }
14433         var keyCode = config.key,
14434             shift = config.shift, 
14435             ctrl = config.ctrl, 
14436             alt = config.alt,
14437             fn = config.fn,
14438             scope = config.scope;
14439         if(typeof keyCode == "string"){
14440             var ks = [];
14441             var keyString = keyCode.toUpperCase();
14442             for(var j = 0, len = keyString.length; j < len; j++){
14443                 ks.push(keyString.charCodeAt(j));
14444             }
14445             keyCode = ks;
14446         }
14447         var keyArray = keyCode instanceof Array;
14448         var handler = function(e){
14449             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14450                 var k = e.getKey();
14451                 if(keyArray){
14452                     for(var i = 0, len = keyCode.length; i < len; i++){
14453                         if(keyCode[i] == k){
14454                           if(this.stopEvent){
14455                               e.stopEvent();
14456                           }
14457                           fn.call(scope || window, k, e);
14458                           return;
14459                         }
14460                     }
14461                 }else{
14462                     if(k == keyCode){
14463                         if(this.stopEvent){
14464                            e.stopEvent();
14465                         }
14466                         fn.call(scope || window, k, e);
14467                     }
14468                 }
14469             }
14470         };
14471         this.bindings.push(handler);  
14472         },
14473
14474     /**
14475      * Shorthand for adding a single key listener
14476      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14477      * following options:
14478      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14479      * @param {Function} fn The function to call
14480      * @param {Object} scope (optional) The scope of the function
14481      */
14482     on : function(key, fn, scope){
14483         var keyCode, shift, ctrl, alt;
14484         if(typeof key == "object" && !(key instanceof Array)){
14485             keyCode = key.key;
14486             shift = key.shift;
14487             ctrl = key.ctrl;
14488             alt = key.alt;
14489         }else{
14490             keyCode = key;
14491         }
14492         this.addBinding({
14493             key: keyCode,
14494             shift: shift,
14495             ctrl: ctrl,
14496             alt: alt,
14497             fn: fn,
14498             scope: scope
14499         })
14500     },
14501
14502     // private
14503     handleKeyDown : function(e){
14504             if(this.enabled){ //just in case
14505             var b = this.bindings;
14506             for(var i = 0, len = b.length; i < len; i++){
14507                 b[i].call(this, e);
14508             }
14509             }
14510         },
14511         
14512         /**
14513          * Returns true if this KeyMap is enabled
14514          * @return {Boolean} 
14515          */
14516         isEnabled : function(){
14517             return this.enabled;  
14518         },
14519         
14520         /**
14521          * Enables this KeyMap
14522          */
14523         enable: function(){
14524                 if(!this.enabled){
14525                     this.el.on(this.eventName, this.handleKeyDown, this);
14526                     this.enabled = true;
14527                 }
14528         },
14529
14530         /**
14531          * Disable this KeyMap
14532          */
14533         disable: function(){
14534                 if(this.enabled){
14535                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14536                     this.enabled = false;
14537                 }
14538         }
14539 };/*
14540  * Based on:
14541  * Ext JS Library 1.1.1
14542  * Copyright(c) 2006-2007, Ext JS, LLC.
14543  *
14544  * Originally Released Under LGPL - original licence link has changed is not relivant.
14545  *
14546  * Fork - LGPL
14547  * <script type="text/javascript">
14548  */
14549
14550  
14551 /**
14552  * @class Roo.util.TextMetrics
14553  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14554  * wide, in pixels, a given block of text will be.
14555  * @singleton
14556  */
14557 Roo.util.TextMetrics = function(){
14558     var shared;
14559     return {
14560         /**
14561          * Measures the size of the specified text
14562          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14563          * that can affect the size of the rendered text
14564          * @param {String} text The text to measure
14565          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14566          * in order to accurately measure the text height
14567          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14568          */
14569         measure : function(el, text, fixedWidth){
14570             if(!shared){
14571                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14572             }
14573             shared.bind(el);
14574             shared.setFixedWidth(fixedWidth || 'auto');
14575             return shared.getSize(text);
14576         },
14577
14578         /**
14579          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14580          * the overhead of multiple calls to initialize the style properties on each measurement.
14581          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14582          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14583          * in order to accurately measure the text height
14584          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14585          */
14586         createInstance : function(el, fixedWidth){
14587             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14588         }
14589     };
14590 }();
14591
14592  
14593
14594 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14595     var ml = new Roo.Element(document.createElement('div'));
14596     document.body.appendChild(ml.dom);
14597     ml.position('absolute');
14598     ml.setLeftTop(-1000, -1000);
14599     ml.hide();
14600
14601     if(fixedWidth){
14602         ml.setWidth(fixedWidth);
14603     }
14604      
14605     var instance = {
14606         /**
14607          * Returns the size of the specified text based on the internal element's style and width properties
14608          * @memberOf Roo.util.TextMetrics.Instance#
14609          * @param {String} text The text to measure
14610          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14611          */
14612         getSize : function(text){
14613             ml.update(text);
14614             var s = ml.getSize();
14615             ml.update('');
14616             return s;
14617         },
14618
14619         /**
14620          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14621          * that can affect the size of the rendered text
14622          * @memberOf Roo.util.TextMetrics.Instance#
14623          * @param {String/HTMLElement} el The element, dom node or id
14624          */
14625         bind : function(el){
14626             ml.setStyle(
14627                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14628             );
14629         },
14630
14631         /**
14632          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14633          * to set a fixed width in order to accurately measure the text height.
14634          * @memberOf Roo.util.TextMetrics.Instance#
14635          * @param {Number} width The width to set on the element
14636          */
14637         setFixedWidth : function(width){
14638             ml.setWidth(width);
14639         },
14640
14641         /**
14642          * Returns the measured width of the specified text
14643          * @memberOf Roo.util.TextMetrics.Instance#
14644          * @param {String} text The text to measure
14645          * @return {Number} width The width in pixels
14646          */
14647         getWidth : function(text){
14648             ml.dom.style.width = 'auto';
14649             return this.getSize(text).width;
14650         },
14651
14652         /**
14653          * Returns the measured height of the specified text.  For multiline text, be sure to call
14654          * {@link #setFixedWidth} if necessary.
14655          * @memberOf Roo.util.TextMetrics.Instance#
14656          * @param {String} text The text to measure
14657          * @return {Number} height The height in pixels
14658          */
14659         getHeight : function(text){
14660             return this.getSize(text).height;
14661         }
14662     };
14663
14664     instance.bind(bindTo);
14665
14666     return instance;
14667 };
14668
14669 // backwards compat
14670 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14671  * Based on:
14672  * Ext JS Library 1.1.1
14673  * Copyright(c) 2006-2007, Ext JS, LLC.
14674  *
14675  * Originally Released Under LGPL - original licence link has changed is not relivant.
14676  *
14677  * Fork - LGPL
14678  * <script type="text/javascript">
14679  */
14680
14681 /**
14682  * @class Roo.state.Provider
14683  * Abstract base class for state provider implementations. This class provides methods
14684  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14685  * Provider interface.
14686  */
14687 Roo.state.Provider = function(){
14688     /**
14689      * @event statechange
14690      * Fires when a state change occurs.
14691      * @param {Provider} this This state provider
14692      * @param {String} key The state key which was changed
14693      * @param {String} value The encoded value for the state
14694      */
14695     this.addEvents({
14696         "statechange": true
14697     });
14698     this.state = {};
14699     Roo.state.Provider.superclass.constructor.call(this);
14700 };
14701 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14702     /**
14703      * Returns the current value for a key
14704      * @param {String} name The key name
14705      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14706      * @return {Mixed} The state data
14707      */
14708     get : function(name, defaultValue){
14709         return typeof this.state[name] == "undefined" ?
14710             defaultValue : this.state[name];
14711     },
14712     
14713     /**
14714      * Clears a value from the state
14715      * @param {String} name The key name
14716      */
14717     clear : function(name){
14718         delete this.state[name];
14719         this.fireEvent("statechange", this, name, null);
14720     },
14721     
14722     /**
14723      * Sets the value for a key
14724      * @param {String} name The key name
14725      * @param {Mixed} value The value to set
14726      */
14727     set : function(name, value){
14728         this.state[name] = value;
14729         this.fireEvent("statechange", this, name, value);
14730     },
14731     
14732     /**
14733      * Decodes a string previously encoded with {@link #encodeValue}.
14734      * @param {String} value The value to decode
14735      * @return {Mixed} The decoded value
14736      */
14737     decodeValue : function(cookie){
14738         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14739         var matches = re.exec(unescape(cookie));
14740         if(!matches || !matches[1]) return; // non state cookie
14741         var type = matches[1];
14742         var v = matches[2];
14743         switch(type){
14744             case "n":
14745                 return parseFloat(v);
14746             case "d":
14747                 return new Date(Date.parse(v));
14748             case "b":
14749                 return (v == "1");
14750             case "a":
14751                 var all = [];
14752                 var values = v.split("^");
14753                 for(var i = 0, len = values.length; i < len; i++){
14754                     all.push(this.decodeValue(values[i]));
14755                 }
14756                 return all;
14757            case "o":
14758                 var all = {};
14759                 var values = v.split("^");
14760                 for(var i = 0, len = values.length; i < len; i++){
14761                     var kv = values[i].split("=");
14762                     all[kv[0]] = this.decodeValue(kv[1]);
14763                 }
14764                 return all;
14765            default:
14766                 return v;
14767         }
14768     },
14769     
14770     /**
14771      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14772      * @param {Mixed} value The value to encode
14773      * @return {String} The encoded value
14774      */
14775     encodeValue : function(v){
14776         var enc;
14777         if(typeof v == "number"){
14778             enc = "n:" + v;
14779         }else if(typeof v == "boolean"){
14780             enc = "b:" + (v ? "1" : "0");
14781         }else if(v instanceof Date){
14782             enc = "d:" + v.toGMTString();
14783         }else if(v instanceof Array){
14784             var flat = "";
14785             for(var i = 0, len = v.length; i < len; i++){
14786                 flat += this.encodeValue(v[i]);
14787                 if(i != len-1) flat += "^";
14788             }
14789             enc = "a:" + flat;
14790         }else if(typeof v == "object"){
14791             var flat = "";
14792             for(var key in v){
14793                 if(typeof v[key] != "function"){
14794                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14795                 }
14796             }
14797             enc = "o:" + flat.substring(0, flat.length-1);
14798         }else{
14799             enc = "s:" + v;
14800         }
14801         return escape(enc);        
14802     }
14803 });
14804
14805 /*
14806  * Based on:
14807  * Ext JS Library 1.1.1
14808  * Copyright(c) 2006-2007, Ext JS, LLC.
14809  *
14810  * Originally Released Under LGPL - original licence link has changed is not relivant.
14811  *
14812  * Fork - LGPL
14813  * <script type="text/javascript">
14814  */
14815 /**
14816  * @class Roo.state.Manager
14817  * This is the global state manager. By default all components that are "state aware" check this class
14818  * for state information if you don't pass them a custom state provider. In order for this class
14819  * to be useful, it must be initialized with a provider when your application initializes.
14820  <pre><code>
14821 // in your initialization function
14822 init : function(){
14823    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14824    ...
14825    // supposed you have a {@link Roo.BorderLayout}
14826    var layout = new Roo.BorderLayout(...);
14827    layout.restoreState();
14828    // or a {Roo.BasicDialog}
14829    var dialog = new Roo.BasicDialog(...);
14830    dialog.restoreState();
14831  </code></pre>
14832  * @singleton
14833  */
14834 Roo.state.Manager = function(){
14835     var provider = new Roo.state.Provider();
14836     
14837     return {
14838         /**
14839          * Configures the default state provider for your application
14840          * @param {Provider} stateProvider The state provider to set
14841          */
14842         setProvider : function(stateProvider){
14843             provider = stateProvider;
14844         },
14845         
14846         /**
14847          * Returns the current value for a key
14848          * @param {String} name The key name
14849          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14850          * @return {Mixed} The state data
14851          */
14852         get : function(key, defaultValue){
14853             return provider.get(key, defaultValue);
14854         },
14855         
14856         /**
14857          * Sets the value for a key
14858          * @param {String} name The key name
14859          * @param {Mixed} value The state data
14860          */
14861          set : function(key, value){
14862             provider.set(key, value);
14863         },
14864         
14865         /**
14866          * Clears a value from the state
14867          * @param {String} name The key name
14868          */
14869         clear : function(key){
14870             provider.clear(key);
14871         },
14872         
14873         /**
14874          * Gets the currently configured state provider
14875          * @return {Provider} The state provider
14876          */
14877         getProvider : function(){
14878             return provider;
14879         }
14880     };
14881 }();
14882 /*
14883  * Based on:
14884  * Ext JS Library 1.1.1
14885  * Copyright(c) 2006-2007, Ext JS, LLC.
14886  *
14887  * Originally Released Under LGPL - original licence link has changed is not relivant.
14888  *
14889  * Fork - LGPL
14890  * <script type="text/javascript">
14891  */
14892 /**
14893  * @class Roo.state.CookieProvider
14894  * @extends Roo.state.Provider
14895  * The default Provider implementation which saves state via cookies.
14896  * <br />Usage:
14897  <pre><code>
14898    var cp = new Roo.state.CookieProvider({
14899        path: "/cgi-bin/",
14900        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14901        domain: "roojs.com"
14902    })
14903    Roo.state.Manager.setProvider(cp);
14904  </code></pre>
14905  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14906  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14907  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14908  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14909  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14910  * domain the page is running on including the 'www' like 'www.roojs.com')
14911  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14912  * @constructor
14913  * Create a new CookieProvider
14914  * @param {Object} config The configuration object
14915  */
14916 Roo.state.CookieProvider = function(config){
14917     Roo.state.CookieProvider.superclass.constructor.call(this);
14918     this.path = "/";
14919     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14920     this.domain = null;
14921     this.secure = false;
14922     Roo.apply(this, config);
14923     this.state = this.readCookies();
14924 };
14925
14926 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14927     // private
14928     set : function(name, value){
14929         if(typeof value == "undefined" || value === null){
14930             this.clear(name);
14931             return;
14932         }
14933         this.setCookie(name, value);
14934         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14935     },
14936
14937     // private
14938     clear : function(name){
14939         this.clearCookie(name);
14940         Roo.state.CookieProvider.superclass.clear.call(this, name);
14941     },
14942
14943     // private
14944     readCookies : function(){
14945         var cookies = {};
14946         var c = document.cookie + ";";
14947         var re = /\s?(.*?)=(.*?);/g;
14948         var matches;
14949         while((matches = re.exec(c)) != null){
14950             var name = matches[1];
14951             var value = matches[2];
14952             if(name && name.substring(0,3) == "ys-"){
14953                 cookies[name.substr(3)] = this.decodeValue(value);
14954             }
14955         }
14956         return cookies;
14957     },
14958
14959     // private
14960     setCookie : function(name, value){
14961         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14962            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14963            ((this.path == null) ? "" : ("; path=" + this.path)) +
14964            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14965            ((this.secure == true) ? "; secure" : "");
14966     },
14967
14968     // private
14969     clearCookie : function(name){
14970         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14971            ((this.path == null) ? "" : ("; path=" + this.path)) +
14972            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14973            ((this.secure == true) ? "; secure" : "");
14974     }
14975 });/*
14976  * Based on:
14977  * Ext JS Library 1.1.1
14978  * Copyright(c) 2006-2007, Ext JS, LLC.
14979  *
14980  * Originally Released Under LGPL - original licence link has changed is not relivant.
14981  *
14982  * Fork - LGPL
14983  * <script type="text/javascript">
14984  */
14985  
14986
14987 /**
14988  * @class Roo.ComponentMgr
14989  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14990  * @singleton
14991  */
14992 Roo.ComponentMgr = function(){
14993     var all = new Roo.util.MixedCollection();
14994
14995     return {
14996         /**
14997          * Registers a component.
14998          * @param {Roo.Component} c The component
14999          */
15000         register : function(c){
15001             all.add(c);
15002         },
15003
15004         /**
15005          * Unregisters a component.
15006          * @param {Roo.Component} c The component
15007          */
15008         unregister : function(c){
15009             all.remove(c);
15010         },
15011
15012         /**
15013          * Returns a component by id
15014          * @param {String} id The component id
15015          */
15016         get : function(id){
15017             return all.get(id);
15018         },
15019
15020         /**
15021          * Registers a function that will be called when a specified component is added to ComponentMgr
15022          * @param {String} id The component id
15023          * @param {Funtction} fn The callback function
15024          * @param {Object} scope The scope of the callback
15025          */
15026         onAvailable : function(id, fn, scope){
15027             all.on("add", function(index, o){
15028                 if(o.id == id){
15029                     fn.call(scope || o, o);
15030                     all.un("add", fn, scope);
15031                 }
15032             });
15033         }
15034     };
15035 }();/*
15036  * Based on:
15037  * Ext JS Library 1.1.1
15038  * Copyright(c) 2006-2007, Ext JS, LLC.
15039  *
15040  * Originally Released Under LGPL - original licence link has changed is not relivant.
15041  *
15042  * Fork - LGPL
15043  * <script type="text/javascript">
15044  */
15045  
15046 /**
15047  * @class Roo.Component
15048  * @extends Roo.util.Observable
15049  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15050  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15051  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15052  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15053  * All visual components (widgets) that require rendering into a layout should subclass Component.
15054  * @constructor
15055  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15056  * 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
15057  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15058  */
15059 Roo.Component = function(config){
15060     config = config || {};
15061     if(config.tagName || config.dom || typeof config == "string"){ // element object
15062         config = {el: config, id: config.id || config};
15063     }
15064     this.initialConfig = config;
15065
15066     Roo.apply(this, config);
15067     this.addEvents({
15068         /**
15069          * @event disable
15070          * Fires after the component is disabled.
15071              * @param {Roo.Component} this
15072              */
15073         disable : true,
15074         /**
15075          * @event enable
15076          * Fires after the component is enabled.
15077              * @param {Roo.Component} this
15078              */
15079         enable : true,
15080         /**
15081          * @event beforeshow
15082          * Fires before the component is shown.  Return false to stop the show.
15083              * @param {Roo.Component} this
15084              */
15085         beforeshow : true,
15086         /**
15087          * @event show
15088          * Fires after the component is shown.
15089              * @param {Roo.Component} this
15090              */
15091         show : true,
15092         /**
15093          * @event beforehide
15094          * Fires before the component is hidden. Return false to stop the hide.
15095              * @param {Roo.Component} this
15096              */
15097         beforehide : true,
15098         /**
15099          * @event hide
15100          * Fires after the component is hidden.
15101              * @param {Roo.Component} this
15102              */
15103         hide : true,
15104         /**
15105          * @event beforerender
15106          * Fires before the component is rendered. Return false to stop the render.
15107              * @param {Roo.Component} this
15108              */
15109         beforerender : true,
15110         /**
15111          * @event render
15112          * Fires after the component is rendered.
15113              * @param {Roo.Component} this
15114              */
15115         render : true,
15116         /**
15117          * @event beforedestroy
15118          * Fires before the component is destroyed. Return false to stop the destroy.
15119              * @param {Roo.Component} this
15120              */
15121         beforedestroy : true,
15122         /**
15123          * @event destroy
15124          * Fires after the component is destroyed.
15125              * @param {Roo.Component} this
15126              */
15127         destroy : true
15128     });
15129     if(!this.id){
15130         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15131     }
15132     Roo.ComponentMgr.register(this);
15133     Roo.Component.superclass.constructor.call(this);
15134     this.initComponent();
15135     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15136         this.render(this.renderTo);
15137         delete this.renderTo;
15138     }
15139 };
15140
15141 /** @private */
15142 Roo.Component.AUTO_ID = 1000;
15143
15144 Roo.extend(Roo.Component, Roo.util.Observable, {
15145     /**
15146      * @scope Roo.Component.prototype
15147      * @type {Boolean}
15148      * true if this component is hidden. Read-only.
15149      */
15150     hidden : false,
15151     /**
15152      * @type {Boolean}
15153      * true if this component is disabled. Read-only.
15154      */
15155     disabled : false,
15156     /**
15157      * @type {Boolean}
15158      * true if this component has been rendered. Read-only.
15159      */
15160     rendered : false,
15161     
15162     /** @cfg {String} disableClass
15163      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15164      */
15165     disabledClass : "x-item-disabled",
15166         /** @cfg {Boolean} allowDomMove
15167          * Whether the component can move the Dom node when rendering (defaults to true).
15168          */
15169     allowDomMove : true,
15170     /** @cfg {String} hideMode
15171      * How this component should hidden. Supported values are
15172      * "visibility" (css visibility), "offsets" (negative offset position) and
15173      * "display" (css display) - defaults to "display".
15174      */
15175     hideMode: 'display',
15176
15177     /** @private */
15178     ctype : "Roo.Component",
15179
15180     /**
15181      * @cfg {String} actionMode 
15182      * which property holds the element that used for  hide() / show() / disable() / enable()
15183      * default is 'el' 
15184      */
15185     actionMode : "el",
15186
15187     /** @private */
15188     getActionEl : function(){
15189         return this[this.actionMode];
15190     },
15191
15192     initComponent : Roo.emptyFn,
15193     /**
15194      * If this is a lazy rendering component, render it to its container element.
15195      * @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.
15196      */
15197     render : function(container, position){
15198         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15199             if(!container && this.el){
15200                 this.el = Roo.get(this.el);
15201                 container = this.el.dom.parentNode;
15202                 this.allowDomMove = false;
15203             }
15204             this.container = Roo.get(container);
15205             this.rendered = true;
15206             if(position !== undefined){
15207                 if(typeof position == 'number'){
15208                     position = this.container.dom.childNodes[position];
15209                 }else{
15210                     position = Roo.getDom(position);
15211                 }
15212             }
15213             this.onRender(this.container, position || null);
15214             if(this.cls){
15215                 this.el.addClass(this.cls);
15216                 delete this.cls;
15217             }
15218             if(this.style){
15219                 this.el.applyStyles(this.style);
15220                 delete this.style;
15221             }
15222             this.fireEvent("render", this);
15223             this.afterRender(this.container);
15224             if(this.hidden){
15225                 this.hide();
15226             }
15227             if(this.disabled){
15228                 this.disable();
15229             }
15230         }
15231         return this;
15232     },
15233
15234     /** @private */
15235     // default function is not really useful
15236     onRender : function(ct, position){
15237         if(this.el){
15238             this.el = Roo.get(this.el);
15239             if(this.allowDomMove !== false){
15240                 ct.dom.insertBefore(this.el.dom, position);
15241             }
15242         }
15243     },
15244
15245     /** @private */
15246     getAutoCreate : function(){
15247         var cfg = typeof this.autoCreate == "object" ?
15248                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15249         if(this.id && !cfg.id){
15250             cfg.id = this.id;
15251         }
15252         return cfg;
15253     },
15254
15255     /** @private */
15256     afterRender : Roo.emptyFn,
15257
15258     /**
15259      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15260      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15261      */
15262     destroy : function(){
15263         if(this.fireEvent("beforedestroy", this) !== false){
15264             this.purgeListeners();
15265             this.beforeDestroy();
15266             if(this.rendered){
15267                 this.el.removeAllListeners();
15268                 this.el.remove();
15269                 if(this.actionMode == "container"){
15270                     this.container.remove();
15271                 }
15272             }
15273             this.onDestroy();
15274             Roo.ComponentMgr.unregister(this);
15275             this.fireEvent("destroy", this);
15276         }
15277     },
15278
15279         /** @private */
15280     beforeDestroy : function(){
15281
15282     },
15283
15284         /** @private */
15285         onDestroy : function(){
15286
15287     },
15288
15289     /**
15290      * Returns the underlying {@link Roo.Element}.
15291      * @return {Roo.Element} The element
15292      */
15293     getEl : function(){
15294         return this.el;
15295     },
15296
15297     /**
15298      * Returns the id of this component.
15299      * @return {String}
15300      */
15301     getId : function(){
15302         return this.id;
15303     },
15304
15305     /**
15306      * Try to focus this component.
15307      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15308      * @return {Roo.Component} this
15309      */
15310     focus : function(selectText){
15311         if(this.rendered){
15312             this.el.focus();
15313             if(selectText === true){
15314                 this.el.dom.select();
15315             }
15316         }
15317         return this;
15318     },
15319
15320     /** @private */
15321     blur : function(){
15322         if(this.rendered){
15323             this.el.blur();
15324         }
15325         return this;
15326     },
15327
15328     /**
15329      * Disable this component.
15330      * @return {Roo.Component} this
15331      */
15332     disable : function(){
15333         if(this.rendered){
15334             this.onDisable();
15335         }
15336         this.disabled = true;
15337         this.fireEvent("disable", this);
15338         return this;
15339     },
15340
15341         // private
15342     onDisable : function(){
15343         this.getActionEl().addClass(this.disabledClass);
15344         this.el.dom.disabled = true;
15345     },
15346
15347     /**
15348      * Enable this component.
15349      * @return {Roo.Component} this
15350      */
15351     enable : function(){
15352         if(this.rendered){
15353             this.onEnable();
15354         }
15355         this.disabled = false;
15356         this.fireEvent("enable", this);
15357         return this;
15358     },
15359
15360         // private
15361     onEnable : function(){
15362         this.getActionEl().removeClass(this.disabledClass);
15363         this.el.dom.disabled = false;
15364     },
15365
15366     /**
15367      * Convenience function for setting disabled/enabled by boolean.
15368      * @param {Boolean} disabled
15369      */
15370     setDisabled : function(disabled){
15371         this[disabled ? "disable" : "enable"]();
15372     },
15373
15374     /**
15375      * Show this component.
15376      * @return {Roo.Component} this
15377      */
15378     show: function(){
15379         if(this.fireEvent("beforeshow", this) !== false){
15380             this.hidden = false;
15381             if(this.rendered){
15382                 this.onShow();
15383             }
15384             this.fireEvent("show", this);
15385         }
15386         return this;
15387     },
15388
15389     // private
15390     onShow : function(){
15391         var ae = this.getActionEl();
15392         if(this.hideMode == 'visibility'){
15393             ae.dom.style.visibility = "visible";
15394         }else if(this.hideMode == 'offsets'){
15395             ae.removeClass('x-hidden');
15396         }else{
15397             ae.dom.style.display = "";
15398         }
15399     },
15400
15401     /**
15402      * Hide this component.
15403      * @return {Roo.Component} this
15404      */
15405     hide: function(){
15406         if(this.fireEvent("beforehide", this) !== false){
15407             this.hidden = true;
15408             if(this.rendered){
15409                 this.onHide();
15410             }
15411             this.fireEvent("hide", this);
15412         }
15413         return this;
15414     },
15415
15416     // private
15417     onHide : function(){
15418         var ae = this.getActionEl();
15419         if(this.hideMode == 'visibility'){
15420             ae.dom.style.visibility = "hidden";
15421         }else if(this.hideMode == 'offsets'){
15422             ae.addClass('x-hidden');
15423         }else{
15424             ae.dom.style.display = "none";
15425         }
15426     },
15427
15428     /**
15429      * Convenience function to hide or show this component by boolean.
15430      * @param {Boolean} visible True to show, false to hide
15431      * @return {Roo.Component} this
15432      */
15433     setVisible: function(visible){
15434         if(visible) {
15435             this.show();
15436         }else{
15437             this.hide();
15438         }
15439         return this;
15440     },
15441
15442     /**
15443      * Returns true if this component is visible.
15444      */
15445     isVisible : function(){
15446         return this.getActionEl().isVisible();
15447     },
15448
15449     cloneConfig : function(overrides){
15450         overrides = overrides || {};
15451         var id = overrides.id || Roo.id();
15452         var cfg = Roo.applyIf(overrides, this.initialConfig);
15453         cfg.id = id; // prevent dup id
15454         return new this.constructor(cfg);
15455     }
15456 });/*
15457  * Based on:
15458  * Ext JS Library 1.1.1
15459  * Copyright(c) 2006-2007, Ext JS, LLC.
15460  *
15461  * Originally Released Under LGPL - original licence link has changed is not relivant.
15462  *
15463  * Fork - LGPL
15464  * <script type="text/javascript">
15465  */
15466
15467 /**
15468  * @class Roo.BoxComponent
15469  * @extends Roo.Component
15470  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15471  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15472  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15473  * layout containers.
15474  * @constructor
15475  * @param {Roo.Element/String/Object} config The configuration options.
15476  */
15477 Roo.BoxComponent = function(config){
15478     Roo.Component.call(this, config);
15479     this.addEvents({
15480         /**
15481          * @event resize
15482          * Fires after the component is resized.
15483              * @param {Roo.Component} this
15484              * @param {Number} adjWidth The box-adjusted width that was set
15485              * @param {Number} adjHeight The box-adjusted height that was set
15486              * @param {Number} rawWidth The width that was originally specified
15487              * @param {Number} rawHeight The height that was originally specified
15488              */
15489         resize : true,
15490         /**
15491          * @event move
15492          * Fires after the component is moved.
15493              * @param {Roo.Component} this
15494              * @param {Number} x The new x position
15495              * @param {Number} y The new y position
15496              */
15497         move : true
15498     });
15499 };
15500
15501 Roo.extend(Roo.BoxComponent, Roo.Component, {
15502     // private, set in afterRender to signify that the component has been rendered
15503     boxReady : false,
15504     // private, used to defer height settings to subclasses
15505     deferHeight: false,
15506     /** @cfg {Number} width
15507      * width (optional) size of component
15508      */
15509      /** @cfg {Number} height
15510      * height (optional) size of component
15511      */
15512      
15513     /**
15514      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15515      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15516      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15517      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15518      * @return {Roo.BoxComponent} this
15519      */
15520     setSize : function(w, h){
15521         // support for standard size objects
15522         if(typeof w == 'object'){
15523             h = w.height;
15524             w = w.width;
15525         }
15526         // not rendered
15527         if(!this.boxReady){
15528             this.width = w;
15529             this.height = h;
15530             return this;
15531         }
15532
15533         // prevent recalcs when not needed
15534         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15535             return this;
15536         }
15537         this.lastSize = {width: w, height: h};
15538
15539         var adj = this.adjustSize(w, h);
15540         var aw = adj.width, ah = adj.height;
15541         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15542             var rz = this.getResizeEl();
15543             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15544                 rz.setSize(aw, ah);
15545             }else if(!this.deferHeight && ah !== undefined){
15546                 rz.setHeight(ah);
15547             }else if(aw !== undefined){
15548                 rz.setWidth(aw);
15549             }
15550             this.onResize(aw, ah, w, h);
15551             this.fireEvent('resize', this, aw, ah, w, h);
15552         }
15553         return this;
15554     },
15555
15556     /**
15557      * Gets the current size of the component's underlying element.
15558      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15559      */
15560     getSize : function(){
15561         return this.el.getSize();
15562     },
15563
15564     /**
15565      * Gets the current XY position 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      * @return {Array} The XY position of the element (e.g., [100, 200])
15568      */
15569     getPosition : function(local){
15570         if(local === true){
15571             return [this.el.getLeft(true), this.el.getTop(true)];
15572         }
15573         return this.xy || this.el.getXY();
15574     },
15575
15576     /**
15577      * Gets the current box measurements of the component's underlying element.
15578      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15579      * @returns {Object} box An object in the format {x, y, width, height}
15580      */
15581     getBox : function(local){
15582         var s = this.el.getSize();
15583         if(local){
15584             s.x = this.el.getLeft(true);
15585             s.y = this.el.getTop(true);
15586         }else{
15587             var xy = this.xy || this.el.getXY();
15588             s.x = xy[0];
15589             s.y = xy[1];
15590         }
15591         return s;
15592     },
15593
15594     /**
15595      * Sets the current box measurements of the component's underlying element.
15596      * @param {Object} box An object in the format {x, y, width, height}
15597      * @returns {Roo.BoxComponent} this
15598      */
15599     updateBox : function(box){
15600         this.setSize(box.width, box.height);
15601         this.setPagePosition(box.x, box.y);
15602         return this;
15603     },
15604
15605     // protected
15606     getResizeEl : function(){
15607         return this.resizeEl || this.el;
15608     },
15609
15610     // protected
15611     getPositionEl : function(){
15612         return this.positionEl || this.el;
15613     },
15614
15615     /**
15616      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15617      * This method fires the move event.
15618      * @param {Number} left The new left
15619      * @param {Number} top The new top
15620      * @returns {Roo.BoxComponent} this
15621      */
15622     setPosition : function(x, y){
15623         this.x = x;
15624         this.y = y;
15625         if(!this.boxReady){
15626             return this;
15627         }
15628         var adj = this.adjustPosition(x, y);
15629         var ax = adj.x, ay = adj.y;
15630
15631         var el = this.getPositionEl();
15632         if(ax !== undefined || ay !== undefined){
15633             if(ax !== undefined && ay !== undefined){
15634                 el.setLeftTop(ax, ay);
15635             }else if(ax !== undefined){
15636                 el.setLeft(ax);
15637             }else if(ay !== undefined){
15638                 el.setTop(ay);
15639             }
15640             this.onPosition(ax, ay);
15641             this.fireEvent('move', this, ax, ay);
15642         }
15643         return this;
15644     },
15645
15646     /**
15647      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15648      * This method fires the move event.
15649      * @param {Number} x The new x position
15650      * @param {Number} y The new y position
15651      * @returns {Roo.BoxComponent} this
15652      */
15653     setPagePosition : function(x, y){
15654         this.pageX = x;
15655         this.pageY = y;
15656         if(!this.boxReady){
15657             return;
15658         }
15659         if(x === undefined || y === undefined){ // cannot translate undefined points
15660             return;
15661         }
15662         var p = this.el.translatePoints(x, y);
15663         this.setPosition(p.left, p.top);
15664         return this;
15665     },
15666
15667     // private
15668     onRender : function(ct, position){
15669         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15670         if(this.resizeEl){
15671             this.resizeEl = Roo.get(this.resizeEl);
15672         }
15673         if(this.positionEl){
15674             this.positionEl = Roo.get(this.positionEl);
15675         }
15676     },
15677
15678     // private
15679     afterRender : function(){
15680         Roo.BoxComponent.superclass.afterRender.call(this);
15681         this.boxReady = true;
15682         this.setSize(this.width, this.height);
15683         if(this.x || this.y){
15684             this.setPosition(this.x, this.y);
15685         }
15686         if(this.pageX || this.pageY){
15687             this.setPagePosition(this.pageX, this.pageY);
15688         }
15689     },
15690
15691     /**
15692      * Force the component's size to recalculate based on the underlying element's current height and width.
15693      * @returns {Roo.BoxComponent} this
15694      */
15695     syncSize : function(){
15696         delete this.lastSize;
15697         this.setSize(this.el.getWidth(), this.el.getHeight());
15698         return this;
15699     },
15700
15701     /**
15702      * Called after the component is resized, this method is empty by default but can be implemented by any
15703      * subclass that needs to perform custom logic after a resize occurs.
15704      * @param {Number} adjWidth The box-adjusted width that was set
15705      * @param {Number} adjHeight The box-adjusted height that was set
15706      * @param {Number} rawWidth The width that was originally specified
15707      * @param {Number} rawHeight The height that was originally specified
15708      */
15709     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15710
15711     },
15712
15713     /**
15714      * Called after the component is moved, this method is empty by default but can be implemented by any
15715      * subclass that needs to perform custom logic after a move occurs.
15716      * @param {Number} x The new x position
15717      * @param {Number} y The new y position
15718      */
15719     onPosition : function(x, y){
15720
15721     },
15722
15723     // private
15724     adjustSize : function(w, h){
15725         if(this.autoWidth){
15726             w = 'auto';
15727         }
15728         if(this.autoHeight){
15729             h = 'auto';
15730         }
15731         return {width : w, height: h};
15732     },
15733
15734     // private
15735     adjustPosition : function(x, y){
15736         return {x : x, y: y};
15737     }
15738 });/*
15739  * Original code for Roojs - LGPL
15740  * <script type="text/javascript">
15741  */
15742  
15743 /**
15744  * @class Roo.XComponent
15745  * A delayed Element creator...
15746  * Or a way to group chunks of interface together.
15747  * 
15748  * Mypart.xyx = new Roo.XComponent({
15749
15750     parent : 'Mypart.xyz', // empty == document.element.!!
15751     order : '001',
15752     name : 'xxxx'
15753     region : 'xxxx'
15754     disabled : function() {} 
15755      
15756     tree : function() { // return an tree of xtype declared components
15757         var MODULE = this;
15758         return 
15759         {
15760             xtype : 'NestedLayoutPanel',
15761             // technicall
15762         }
15763      ]
15764  *})
15765  *
15766  *
15767  * It can be used to build a big heiracy, with parent etc.
15768  * or you can just use this to render a single compoent to a dom element
15769  * MYPART.render(Roo.Element | String(id) | dom_element )
15770  * 
15771  * @extends Roo.util.Observable
15772  * @constructor
15773  * @param cfg {Object} configuration of component
15774  * 
15775  */
15776 Roo.XComponent = function(cfg) {
15777     Roo.apply(this, cfg);
15778     this.addEvents({ 
15779         /**
15780              * @event built
15781              * Fires when this the componnt is built
15782              * @param {Roo.XComponent} c the component
15783              */
15784         'built' : true
15785         
15786     });
15787     this.region = this.region || 'center'; // default..
15788     Roo.XComponent.register(this);
15789     this.modules = false;
15790     this.el = false; // where the layout goes..
15791     
15792     
15793 }
15794 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15795     /**
15796      * @property el
15797      * The created element (with Roo.factory())
15798      * @type {Roo.Layout}
15799      */
15800     el  : false,
15801     
15802     /**
15803      * @property el
15804      * for BC  - use el in new code
15805      * @type {Roo.Layout}
15806      */
15807     panel : false,
15808     
15809     /**
15810      * @property layout
15811      * for BC  - use el in new code
15812      * @type {Roo.Layout}
15813      */
15814     layout : false,
15815     
15816      /**
15817      * @cfg {Function|boolean} disabled
15818      * If this module is disabled by some rule, return true from the funtion
15819      */
15820     disabled : false,
15821     
15822     /**
15823      * @cfg {String} parent 
15824      * Name of parent element which it get xtype added to..
15825      */
15826     parent: false,
15827     
15828     /**
15829      * @cfg {String} order
15830      * Used to set the order in which elements are created (usefull for multiple tabs)
15831      */
15832     
15833     order : false,
15834     /**
15835      * @cfg {String} name
15836      * String to display while loading.
15837      */
15838     name : false,
15839     /**
15840      * @cfg {String} region
15841      * Region to render component to (defaults to center)
15842      */
15843     region : 'center',
15844     
15845     /**
15846      * @cfg {Array} items
15847      * A single item array - the first element is the root of the tree..
15848      * It's done this way to stay compatible with the Xtype system...
15849      */
15850     items : false,
15851     
15852     /**
15853      * @property _tree
15854      * The method that retuns the tree of parts that make up this compoennt 
15855      * @type {function}
15856      */
15857     _tree  : false,
15858     
15859      /**
15860      * render
15861      * render element to dom or tree
15862      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15863      */
15864     
15865     render : function(el)
15866     {
15867         
15868         el = el || false;
15869         var hp = this.parent ? 1 : 0;
15870         
15871         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15872             // if parent is a '#.....' string, then let's use that..
15873             var ename = this.parent.substr(1)
15874             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15875             el = Roo.get(ename);
15876             if (!el && !this.parent) {
15877                 Roo.log("Warning - element can not be found :#" + ename );
15878                 return;
15879             }
15880         }
15881         var tree = this._tree ? this._tree() : this.tree();
15882
15883         
15884         if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15885             //el = Roo.get(document.body);
15886             this.parent = { el : true };
15887         }
15888             
15889             
15890         
15891         if (!this.parent) {
15892             
15893             Roo.log("no parent - creating one");
15894             
15895             el = el ? Roo.get(el) : false;      
15896             
15897             // it's a top level one..
15898             this.parent =  {
15899                 el : new Roo.BorderLayout(el || document.body, {
15900                 
15901                      center: {
15902                          titlebar: false,
15903                          autoScroll:false,
15904                          closeOnTab: true,
15905                          tabPosition: 'top',
15906                           //resizeTabs: true,
15907                          alwaysShowTabs: el && hp? false :  true,
15908                          hideTabs: el || !hp ? true :  false,
15909                          minTabWidth: 140
15910                      }
15911                  })
15912             }
15913         }
15914         
15915                 if (!this.parent.el) {
15916                         // probably an old style ctor, which has been disabled.
15917                         return;
15918                         
15919                 }
15920                 // The 'tree' method is  '_tree now' 
15921             
15922         tree.region = tree.region || this.region;
15923         
15924         if (this.parent.el === true) {
15925             // bootstrap... - body..
15926             this.parent.el = Roo.factory(tree);
15927         }
15928         
15929         this.el = this.parent.el.addxtype(tree);
15930         this.fireEvent('built', this);
15931         
15932         this.panel = this.el;
15933         this.layout = this.panel.layout;
15934                 this.parentLayout = this.parent.layout  || false;  
15935          
15936     }
15937     
15938 });
15939
15940 Roo.apply(Roo.XComponent, {
15941     /**
15942      * @property  hideProgress
15943      * true to disable the building progress bar.. usefull on single page renders.
15944      * @type Boolean
15945      */
15946     hideProgress : false,
15947     /**
15948      * @property  buildCompleted
15949      * True when the builder has completed building the interface.
15950      * @type Boolean
15951      */
15952     buildCompleted : false,
15953      
15954     /**
15955      * @property  topModule
15956      * the upper most module - uses document.element as it's constructor.
15957      * @type Object
15958      */
15959      
15960     topModule  : false,
15961       
15962     /**
15963      * @property  modules
15964      * array of modules to be created by registration system.
15965      * @type {Array} of Roo.XComponent
15966      */
15967     
15968     modules : [],
15969     /**
15970      * @property  elmodules
15971      * array of modules to be created by which use #ID 
15972      * @type {Array} of Roo.XComponent
15973      */
15974      
15975     elmodules : [],
15976
15977      /**
15978      * @property  build_from_html
15979      * Build elements from html - used by bootstrap HTML stuff 
15980      *    - this is cleared after build is completed
15981      * @type {boolean} true  (default false)
15982      */
15983      
15984     build_from_html : false,
15985
15986     /**
15987      * Register components to be built later.
15988      *
15989      * This solves the following issues
15990      * - Building is not done on page load, but after an authentication process has occured.
15991      * - Interface elements are registered on page load
15992      * - Parent Interface elements may not be loaded before child, so this handles that..
15993      * 
15994      *
15995      * example:
15996      * 
15997      * MyApp.register({
15998           order : '000001',
15999           module : 'Pman.Tab.projectMgr',
16000           region : 'center',
16001           parent : 'Pman.layout',
16002           disabled : false,  // or use a function..
16003         })
16004      
16005      * * @param {Object} details about module
16006      */
16007     register : function(obj) {
16008                 
16009         Roo.XComponent.event.fireEvent('register', obj);
16010         switch(typeof(obj.disabled) ) {
16011                 
16012             case 'undefined':
16013                 break;
16014             
16015             case 'function':
16016                 if ( obj.disabled() ) {
16017                         return;
16018                 }
16019                 break;
16020             
16021             default:
16022                 if (obj.disabled) {
16023                         return;
16024                 }
16025                 break;
16026         }
16027                 
16028         this.modules.push(obj);
16029          
16030     },
16031     /**
16032      * convert a string to an object..
16033      * eg. 'AAA.BBB' -> finds AAA.BBB
16034
16035      */
16036     
16037     toObject : function(str)
16038     {
16039         if (!str || typeof(str) == 'object') {
16040             return str;
16041         }
16042         if (str.substring(0,1) == '#') {
16043             return str;
16044         }
16045
16046         var ar = str.split('.');
16047         var rt, o;
16048         rt = ar.shift();
16049             /** eval:var:o */
16050         try {
16051             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16052         } catch (e) {
16053             throw "Module not found : " + str;
16054         }
16055         
16056         if (o === false) {
16057             throw "Module not found : " + str;
16058         }
16059         Roo.each(ar, function(e) {
16060             if (typeof(o[e]) == 'undefined') {
16061                 throw "Module not found : " + str;
16062             }
16063             o = o[e];
16064         });
16065         
16066         return o;
16067         
16068     },
16069     
16070     
16071     /**
16072      * move modules into their correct place in the tree..
16073      * 
16074      */
16075     preBuild : function ()
16076     {
16077         var _t = this;
16078         Roo.each(this.modules , function (obj)
16079         {
16080             Roo.XComponent.event.fireEvent('beforebuild', obj);
16081             
16082             var opar = obj.parent;
16083             try { 
16084                 obj.parent = this.toObject(opar);
16085             } catch(e) {
16086                 Roo.log("parent:toObject failed: " + e.toString());
16087                 return;
16088             }
16089             
16090             if (!obj.parent) {
16091                 Roo.debug && Roo.log("GOT top level module");
16092                 Roo.debug && Roo.log(obj);
16093                 obj.modules = new Roo.util.MixedCollection(false, 
16094                     function(o) { return o.order + '' }
16095                 );
16096                 this.topModule = obj;
16097                 return;
16098             }
16099                         // parent is a string (usually a dom element name..)
16100             if (typeof(obj.parent) == 'string') {
16101                 this.elmodules.push(obj);
16102                 return;
16103             }
16104             if (obj.parent.constructor != Roo.XComponent) {
16105                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16106             }
16107             if (!obj.parent.modules) {
16108                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16109                     function(o) { return o.order + '' }
16110                 );
16111             }
16112             if (obj.parent.disabled) {
16113                 obj.disabled = true;
16114             }
16115             obj.parent.modules.add(obj);
16116         }, this);
16117     },
16118     
16119      /**
16120      * make a list of modules to build.
16121      * @return {Array} list of modules. 
16122      */ 
16123     
16124     buildOrder : function()
16125     {
16126         var _this = this;
16127         var cmp = function(a,b) {   
16128             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16129         };
16130         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16131             throw "No top level modules to build";
16132         }
16133         
16134         // make a flat list in order of modules to build.
16135         var mods = this.topModule ? [ this.topModule ] : [];
16136                 
16137         
16138         // elmodules (is a list of DOM based modules )
16139         Roo.each(this.elmodules, function(e) {
16140             mods.push(e);
16141             if (!this.topModule &&
16142                 typeof(e.parent) == 'string' &&
16143                 e.parent.substring(0,1) == '#' &&
16144                 Roo.get(e.parent.substr(1))
16145                ) {
16146                 
16147                 _this.topModule = e;
16148             }
16149             
16150         });
16151
16152         
16153         // add modules to their parents..
16154         var addMod = function(m) {
16155             Roo.debug && Roo.log("build Order: add: " + m.name);
16156                 
16157             mods.push(m);
16158             if (m.modules && !m.disabled) {
16159                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16160                 m.modules.keySort('ASC',  cmp );
16161                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16162     
16163                 m.modules.each(addMod);
16164             } else {
16165                 Roo.debug && Roo.log("build Order: no child modules");
16166             }
16167             // not sure if this is used any more..
16168             if (m.finalize) {
16169                 m.finalize.name = m.name + " (clean up) ";
16170                 mods.push(m.finalize);
16171             }
16172             
16173         }
16174         if (this.topModule && this.topModule.modules) { 
16175             this.topModule.modules.keySort('ASC',  cmp );
16176             this.topModule.modules.each(addMod);
16177         } 
16178         return mods;
16179     },
16180     
16181      /**
16182      * Build the registered modules.
16183      * @param {Object} parent element.
16184      * @param {Function} optional method to call after module has been added.
16185      * 
16186      */ 
16187    
16188     build : function(opts) 
16189     {
16190         
16191         if (typeof(opts) != 'undefined') {
16192             Roo.apply(this,opts);
16193         }
16194         
16195         this.preBuild();
16196         var mods = this.buildOrder();
16197       
16198         //this.allmods = mods;
16199         //Roo.debug && Roo.log(mods);
16200         //return;
16201         if (!mods.length) { // should not happen
16202             throw "NO modules!!!";
16203         }
16204         
16205         
16206         var msg = "Building Interface...";
16207         // flash it up as modal - so we store the mask!?
16208         if (!this.hideProgress && Roo.MessageBox) {
16209             Roo.MessageBox.show({ title: 'loading' });
16210             Roo.MessageBox.show({
16211                title: "Please wait...",
16212                msg: msg,
16213                width:450,
16214                progress:true,
16215                closable:false,
16216                modal: false
16217               
16218             });
16219         }
16220         var total = mods.length;
16221         
16222         var _this = this;
16223         var progressRun = function() {
16224             if (!mods.length) {
16225                 Roo.debug && Roo.log('hide?');
16226                 if (!this.hideProgress && Roo.MessageBox) {
16227                     Roo.MessageBox.hide();
16228                 }
16229                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16230                 
16231                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16232                 
16233                 // THE END...
16234                 return false;   
16235             }
16236             
16237             var m = mods.shift();
16238             
16239             
16240             Roo.debug && Roo.log(m);
16241             // not sure if this is supported any more.. - modules that are are just function
16242             if (typeof(m) == 'function') { 
16243                 m.call(this);
16244                 return progressRun.defer(10, _this);
16245             } 
16246             
16247             
16248             msg = "Building Interface " + (total  - mods.length) + 
16249                     " of " + total + 
16250                     (m.name ? (' - ' + m.name) : '');
16251                         Roo.debug && Roo.log(msg);
16252             if (!this.hideProgress &&  Roo.MessageBox) { 
16253                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16254             }
16255             
16256          
16257             // is the module disabled?
16258             var disabled = (typeof(m.disabled) == 'function') ?
16259                 m.disabled.call(m.module.disabled) : m.disabled;    
16260             
16261             
16262             if (disabled) {
16263                 return progressRun(); // we do not update the display!
16264             }
16265             
16266             // now build 
16267             
16268                         
16269                         
16270             m.render();
16271             // it's 10 on top level, and 1 on others??? why...
16272             return progressRun.defer(10, _this);
16273              
16274         }
16275         progressRun.defer(1, _this);
16276      
16277         
16278         
16279     },
16280         
16281         
16282         /**
16283          * Event Object.
16284          *
16285          *
16286          */
16287         event: false, 
16288     /**
16289          * wrapper for event.on - aliased later..  
16290          * Typically use to register a event handler for register:
16291          *
16292          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16293          *
16294          */
16295     on : false
16296    
16297     
16298     
16299 });
16300
16301 Roo.XComponent.event = new Roo.util.Observable({
16302                 events : { 
16303                         /**
16304                          * @event register
16305                          * Fires when an Component is registered,
16306                          * set the disable property on the Component to stop registration.
16307                          * @param {Roo.XComponent} c the component being registerd.
16308                          * 
16309                          */
16310                         'register' : true,
16311             /**
16312                          * @event beforebuild
16313                          * Fires before each Component is built
16314                          * can be used to apply permissions.
16315                          * @param {Roo.XComponent} c the component being registerd.
16316                          * 
16317                          */
16318                         'beforebuild' : true,
16319                         /**
16320                          * @event buildcomplete
16321                          * Fires on the top level element when all elements have been built
16322                          * @param {Roo.XComponent} the top level component.
16323                          */
16324                         'buildcomplete' : true
16325                         
16326                 }
16327 });
16328
16329 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16330